metrics.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package observability
  2. import (
  3. "github.com/prometheus/client_golang/prometheus"
  4. )
  5. // NewRegistry returns a fresh Prometheus registry. Each service gets
  6. // its own so the metric labels are scoped correctly.
  7. func NewRegistry(serviceName string) (*prometheus.Registry, *IngestdMetrics) {
  8. reg := prometheus.NewRegistry()
  9. reg.MustRegister(
  10. prometheus.NewGoCollector(),
  11. prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
  12. )
  13. return reg, NewIngestdMetrics(reg, serviceName)
  14. }
  15. // IngestdMetrics groups the counters/histograms declared in SPEC §22
  16. // for the ingest tier. Other tiers get their own metric groups.
  17. type IngestdMetrics struct {
  18. AlertsReceived *prometheus.CounterVec // result=accepted|invalid|rate_limited|payload_too_large|quarantined|circuit_open
  19. PayloadBytes prometheus.Histogram
  20. RateLimitHits *prometheus.CounterVec // scope=source|company
  21. Quarantines *prometheus.CounterVec
  22. CBState *prometheus.GaugeVec
  23. PublishLatency prometheus.Histogram
  24. }
  25. // NewIngestdMetrics registers and returns the ingestd metrics.
  26. func NewIngestdMetrics(reg prometheus.Registerer, serviceName string) *IngestdMetrics {
  27. m := &IngestdMetrics{
  28. AlertsReceived: prometheus.NewCounterVec(prometheus.CounterOpts{
  29. Namespace: "ba",
  30. Subsystem: "ingestd",
  31. Name: "alerts_received_total",
  32. Help: "Number of inbound alerts by result.",
  33. ConstLabels: prometheus.Labels{"service": serviceName},
  34. }, []string{"result"}),
  35. PayloadBytes: prometheus.NewHistogram(prometheus.HistogramOpts{
  36. Namespace: "ba",
  37. Subsystem: "ingestd",
  38. Name: "payload_bytes",
  39. Help: "Accepted alert payload size in bytes.",
  40. Buckets: prometheus.ExponentialBuckets(64, 4, 8), // 64..1MB
  41. ConstLabels: prometheus.Labels{"service": serviceName},
  42. }),
  43. RateLimitHits: prometheus.NewCounterVec(prometheus.CounterOpts{
  44. Namespace: "ba",
  45. Subsystem: "ingestd",
  46. Name: "rate_limited_total",
  47. Help: "Rate-limit rejections by scope.",
  48. ConstLabels: prometheus.Labels{"service": serviceName},
  49. }, []string{"scope"}),
  50. Quarantines: prometheus.NewCounterVec(prometheus.CounterOpts{
  51. Namespace: "ba",
  52. Subsystem: "ingestd",
  53. Name: "source_quarantined_total",
  54. Help: "Source quarantines triggered.",
  55. ConstLabels: prometheus.Labels{"service": serviceName},
  56. }, []string{"source_id", "company_id"}),
  57. CBState: prometheus.NewGaugeVec(prometheus.GaugeOpts{
  58. Namespace: "ba",
  59. Subsystem: "ingestd",
  60. Name: "circuit_breaker_state",
  61. Help: "0=closed, 1=half_open, 2=open.",
  62. ConstLabels: prometheus.Labels{"service": serviceName},
  63. }, []string{"component"}),
  64. PublishLatency: prometheus.NewHistogram(prometheus.HistogramOpts{
  65. Namespace: "ba",
  66. Subsystem: "ingestd",
  67. Name: "publish_latency_seconds",
  68. Help: "Time to publish an accepted alert to NATS.",
  69. Buckets: prometheus.DefBuckets,
  70. ConstLabels: prometheus.Labels{"service": serviceName},
  71. }),
  72. }
  73. reg.MustRegister(
  74. m.AlertsReceived,
  75. m.PayloadBytes,
  76. m.RateLimitHits,
  77. m.Quarantines,
  78. m.CBState,
  79. m.PublishLatency,
  80. )
  81. m.AlertsReceived.WithLabelValues("accepted")
  82. return m
  83. }