การตรวจสอบแบบเรียลไทม์ของ Watermill โดยใช้ Prometheus
การเก็บค่าการวัด
Watermill สามารถตรวจสอบได้โดยใช้ตัวบอก (decorators) สำหรับผู้เผยแพร่/ผู้บริโภค และ middleware สำหรับตัวจัดการ (handlers) โดยเรามีการประยุกต์ใช้งานที่ค่าเริ่มต้น โดยใช้ Prometheus client for Go อย่างเป็นทางการ
แพคเกจ components/metrics
ส่งออก PrometheusMetricsBuilder
ซึ่งมีฟังก์ชันที่สะดวกสบายสำหรับการห่อผู้เผยแพร่, ผู้บริโภค, และตัวจัดการเพื่ออัพเดทรีจิสทรีของ Prometheus ที่เกี่ยวข้อง:
รหัสภายใน: github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// PrometheusMetricsBuilder มีเมธอดสำหรับการตกแต่งผู้เผยแพร่, ผู้บริโภค, และตัวจัดการ
type PrometheusMetricsBuilder struct {
// PrometheusRegistry สามารถเติมในรีจิสทรี Prometheus ที่มีอยู่หรือเป็นค่าว่างเพื่อใช้รีจิสทรีเริ่มต้น
PrometheusRegistry prometheus.Registerer
Namespace string
Subsystem string
}
// เพิ่มเมตริกของ PrometheusRouterMetrics เป็นฟังก์ชันที่สะดวกสบายสำหรับเพิ่ม middleware เมตริกไปยังตัวจัดการทุกตัวในเส้นทางของข้อความ ทั้งนี้ยังตกแต่งผู้เผยแพร่และผู้บริโภคของตัวจัดการด้วย
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
// ...
การห่อผู้เผยแพร่, ผู้บริโภค, และตัวจัดการ
หากคุณใช้ตัวจัดการของ Watermill (ซึ่งเราขอแนะนำให้ใช้ในกรณีส่วนมาก) คุณสามารถใช้ฟังก์ชันที่สะดวกสบาย AddPrometheusRouterMetrics
เพื่อให้แน่ใจว่าทุกตัวจัดการที่เพิ่มเข้าไปในตัวจัดการนี้ได้รับการห่อเพื่ออัพเดทรีจิสทรีของ Prometheus, อีกทั้งยังรวมถึงผู้เผยแพร่และผู้บริโภคของพวกเขา:
รหัสภายใน: github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// AddPrometheusRouterMetrics เป็นฟังก์ชันที่สะดวกสบายสำหรับเพิ่ม middleware เมตริกไปยังตัวจัดการทุกตัวในเส้นทางของข้อความ ทั้งนี้ยังตกแต่งผู้เผยแพร่และผู้บริโภคของตัวจัดการด้วย
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
r.AddPublisherDecorators(b.DecoratePublisher)
r.AddSubscriberDecorators(b.DecorateSubscriber)
r.AddMiddleware(b.NewRouterMiddleware().Middleware)
}
// ...
ตัวอย่างการใช้ AddPrometheusRouterMetrics
:
รหัสภายใน: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
// เราปล่อยให้ namespace และ subsytem ว่างเปล่า
metricsBuilder := metrics.NewPrometheusMetricsBuilder(prometheusRegistry, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
ในตัวอย่างของรหัสด้านบน, เราปล่อยให้พารามิเตอร์ namespace
และ subsystem
ว่างเปล่า. ไลบรารีไคลเอ็นต์ของ Prometheus ใช้พารามิเตอร์เหล่านี้ เพื่อใส่คำนำหน้าในชื่อข้อความเมตริก คุณอาจต้องการใช้ namespace หรือ subsytem แต่โปรดทราบว่านี้จะส่งผลต่อชื่อเมตริก ดังนั้นคุณจำเป็นต้องปรับแต่งแดชบอร์ด Grafana ตามนั้น
ผู้เผยแพร่และผู้บริโภคที่อิสระสามารถถูกตกแต่งโดยใช้เมธอดที่จัดสรรของ PrometheusMetricsBuilder
:
รหัสภายใน: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
subWithMetrics, err := metricsBuilder.DecorateSubscriber(pubSub)
if err != nil {
panic(err)
}
pubWithMetrics, err := metricsBuilder.DecoratePublisher(pub)
if err != nil {
panic(err)
}
// ...
การเปิดเผย / การปล่อย /metrics Endpoint
ตามการทำงานของ Prometheus บริการจำเป็นต้องเปิดเผยจุดปลายทาง HTTP สำหรับการดึงข้อมูล ตามปกตินี้คือจุดปลายทางที่ใช้วิธี GET และเส้นทางปกติคือ /metrics
เพื่อให้มีจุดปลายทางนี้สามารถให้บริการได้มีฟังก์ชันสะดวก 2 ฟังก์ชันที่ใช้เพิกถอนทะเบียน Prometheus ที่สร้างไว้ก่อนหน้านี้และอีกฟังก์ชันหนึ่งสร้างทะเบียนใหม่พร้อมกัน:
โค้ดที่เต็มรูปแบบ: github.com/ThreeDotsLabs/watermill/components/metrics/http.go
// ...
// สร้างทะเบียนและให้บริการเปิดเผย HTTP ที่ที่อยู่ที่กำหนด เพื่อเปิดเผยจุดปลายทาง /metrics ให้กับ Prometheus
// มันคืนทะเบียน Prometheus ใหม่ (สำหรับการลงทะเบียนเมตริก) และฟังก์ชันการยกเลิกเพื่อปิดบริการ
func CreateRegistryAndServeHTTP(addr string) (registry *prometheus.Registry, cancel func()) {
registry = prometheus.NewRegistry()
return registry, ServeHTTP(addr, registry)
}
// ServeHTTP สร้างเซิร์ฟเวอร์ HTTP ที่ที่อยู่ที่กำหนดเพื่อเปิดเผยจุดปลายทาง /metrics ให้กับ Prometheus
// มันยอมรับทะเบียน Prometheus ที่มีอยู่และคืนฟังก์ชันการยกเลิกเพื่อปิดบริการ
func ServeHTTP(addr string, registry *prometheus.Registry) (cancel func()) {
// ...
ตัวอย่างการใช้งาน:
โค้ดที่เต็มรูปแบบ: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
prometheusRegistry, closeMetricsServer := metrics.CreateRegistryAndServeHTTP(*metricsAddr)
defer closeMetricsServer()
// เราปล่อยชื่อเป้าหมายและเซบเซตเครื่องมือเปล่า
metricsBuilder := metrics.NewPrometheusMetricsBuilder(prometheusRegistry, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
ตัวอย่างแอปพลิเคชัน
เพื่อเข้าใจว่าแดชบอร์ดทำงานอย่างไรในแง่ปฏิบัติ คุณสามารถอ้างอิงไปยัง ตัวอย่าง metrics
ทำตามคำแนะนำใน README ของตัวอย่างเพื่อรันและเพิ่มต้นทางข้อมูลของ Prometheus เข้าไปใน Grafana
แดชบอร์ด Grafana
เราได้เตรียมไว้แล้ว แดชบอร์ด Grafana เพื่อใช้งานร่วมกับการปฏิบัติที่กล่าวถึง มันจะให้ข้อมูลพื้นฐานเกี่ยวกับผลผลิต, อัตราการล้มเหลว และระยะเวลาในการเผยแพร่/ประมวลผล
หากคุณต้องการมุ่งเห็นแดชบอร์ดนี้ในท้องถิ่น คุณสามารถใช้แอปพลิเคชันตัวอย่างได้
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการส่งออกข้อมูลเมตริกไปยัง Prometheus ดูที่ Exported metrics
การนำเข้าแดชบอร์ด
เพื่อนำเข้าแดชบอร์ด Grafana, เลือก แดชบอร์ด/จัดการ จากเมนูด้านซ้าย จากนั้นคลิก + นำเข้า
ป้อน URL ของแดชบอร์ด https://grafana.com/dashboards/9777 (หรือเพียงแค่ ID, 9777), จากนั้นคลิก โหลด
จากนั้นเลือกต้นทางข้อมูล Prometheus ที่ใช้สแกนจุดปลายทาง /metrics
คลิก นำเข้า
และเสร็จสิ้น!
การส่ง Metrics
ต่อไปนี้คือรายการของ metrics ที่ลงทะเบียนในทะเบียน Prometheus โดย PrometheusMetricsBuilder
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับประเภทของ metrics ของ Prometheus โปรดอ่านที่ เอกสารของ Prometheus.
วัตถุ | Metric | คำอธิบาย | ป้าย/ค่า |
---|---|---|---|
Subscriber | subscriber_messages_received_total |
ตัวนับของ Prometheus นับจำนวนข้อความที่ได้รับจาก Subscriber | acked เป็น "acked" หรือ "nacked" |
หาก Subscriber ทำงานภายใน handler ให้ตั้ง handler_name ; หากไม่ใช่ ให้ใช้ " |
|||
subscriber_name ระบุ Subscriber ถ้ามันได้ implement interface fmt.Stringer นั้นคือผลลัพธ์จาก String() ; ไม่ใช่ คือ package.structName |
เรื่องเพิ่มเติม แต่ละ metric มี node
label ที่ Prometheus จัดหา โดยมีค่าที่สอดคล้องกับตัวอย่างของตัวอย่าง source และ job
ที่ระบุเป็นชื่องานใน ไฟล์การกำหนดค่าของ Prometheus.
หมายเหตุ: อ้างอิงจากที่กล่าวด้านบน การใช้ namespace
หรือ subsystem
ที่ไม่ว่างเปล่าจะทำให้เกิด prefix ของชื่อ metric คุณอาจจำเป็นต้องทำการปรับปรุงที่สอดคล้องเช่นการกำหนดค่าพาเนลในแดชบอร์ดของ Grafana
การปรับแต่ง
หากคุณคิดว่ามี metrics บางประการที่ของการตีคลุมคุณสามารถขยายบทบาทนี้ได้อย่างง่ายดาย วิธีที่ดีที่สุดคือการใช้การลงทะเบียน Prometheus ที่ใช้กับวิธี ServeHTTP
และลงทะเบียน metrics ตามเอกสารของ client ที่นี่.
วิธีย่อที่สุดในการปรับปรุง metrics เหล่านี้คือโดยใช้ decorators โค้ดเต็มอื่น ๆ สามารถค้นหาได้ที่ github.com/ThreeDotsLabs/watermill/message/decorator.go.
// ...
// MessageTransformSubscriberDecorator สร้าง subscriber decorator ที่เรียกฟังก์ชัน transform บนทุกข้อความที่ถ่ายทออกผ่าน subscriber
func MessageTransformSubscriberDecorator(transform func(*Message)) SubscriberDecorator {
if transform == nil {
panic("transform function is nil")
}
return func(sub Subscriber) (Subscriber, error) {
return &messageTransformSubscriberDecorator{
sub: sub,
transform: transform,
}, nil
}
}
// MessageTransformPublisherDecorator สร้าง publisher decorator ที่เรียกฟังก์ชัน transform บนทุกข้อความที่ถ่ายทออกผ่าน publisher
func MessageTransformPublisherDecorator(transform func(*Message)) PublisherDecorator {
if transform == nil {
panic("transform function is nil")
}
return func(pub Publisher) (Publisher, error) {
return &messageTransformPublisherDecorator{
Publisher: pub,
transform: transform,
}, nil
}
}
type messageTransformSubscriberDecorator struct {
// ...
และ/หรือ middleware ใน routers
วิธีที่ง่ายที่สุดคือการปรับปรุง metrics ที่จำเป็นเท่านั้นในฟังก์ชันของ handler