Lesson 3 · Fundamentals & metrics
How this repo scrapes
From a pod annotation to a time series — and where your service's numbers actually come from.
Your win: trace how Prometheus discovers and scrapes this repo's services
(the prometheus.io/scrape annotation), and know what metrics your Go services
expose — the RED metrics and the custom business ones your team already emits.
Service discovery by annotation
How does Prometheus find ~25 services across autoscaling pods? Not a hard-coded list — it
discovers pods from the Kubernetes API and filters by an annotation. A pod
that carries prometheus.io/scrape: "true" (plus port/path)
gets scraped; others are ignored.
kubernetes-pods scrape job
platforms/monitoring/prometheus/values.yaml:424-467 defines the
job. Via relabeling it: keeps only pods with
prometheus_io_scrape=true (:430), maps
prometheus_io_scheme→__scheme__,
prometheus_io_path→__metrics_path__, and
__address__ + prometheus_io_port→__address__
(:436-448), then attaches namespace/pod labels. Those
annotations come from the Helm library's
_workload_metadata.tpl (Course 3) — the same file that set the
Istio sidecar tuning. So every service opts into scraping just by having those annotations,
no per-service Prometheus config.
What your Go services expose
/metrics on :8888
Every bootstrapped service serves /metrics on port 8888
(internal/golibs/bootstrap/monitor.go:75-79). The registry is an
OTel Prometheus exporter that bridges OpenCensus stats
(interceptors/telemetry.go:274-321) — so the metric names
are OpenCensus-style (grpc_io_server_*), a detail worth being precise about.
grpc_io_server_completed_rpcs— a counter by method + status → Rate and Errors.grpc_io_server_server_latency_bucket— a histogram (buckets 5…10000ms) → Duration.
backend-services alert rules fire on (Lesson 4).
WithPrometheusCollectors hook (in each cmd/server/<svc>/gserver.go),
using the internal/golibs/metrics helper. Your team's:
- notification:
manabie_notification_error_pushed_counter,notificationmgmt_request_send_email_status_counter(internal/notification/infra/metrics/notification_metrics.go:43,50). - spike:
manabie_email_event_counter. - conversationmgmt:
agora_chat_concurrent_connections_counter.
Prometheus — Configuration (scrape & relabeling)
Kubernetes SD, the scrape config, and relabel_configs (keep/drop/replace).
→ prometheus.io — Configuration
→ istio.io — Envoy stats (the mesh side)
Check yourself (from memory)
Q1. Prometheus decides which pods to scrape by…
kubernetes-pods job keeps pods with
prometheus_io_scrape=true via relabeling. (No Operator/ServiceMonitor here.)
Q2. The RED metrics on this repo's services come from…
grpc_io_server_completed_rpcs +
latency histogram) give Rate/Errors/Duration for every RPC.
Q3. "Relabeling" in a scrape config is used to…
kubernetes-pods job
(prometheus/values.yaml:424-467) uses RELABELING to keep pods with
prometheus_io_scrape=true, map scheme/path/port→__address__, attach
pod/namespace labels — annotations from _workload_metadata.tpl (C3). No Operator/
ServiceMonitor. SERVICES expose /metrics on :8888
(bootstrap/monitor.go:75), via an OTel-Prometheus exporter BRIDGING OpenCensus
(names grpc_io_server_*). RED for free via gRPC interceptor VIEWS
(telemetry.go:34-52): grpc_io_server_completed_rpcs (Rate/Errors) +
grpc_io_server_server_latency_bucket (Duration). CUSTOM business metrics via
WithPrometheusCollectors (repo: notification/spike/conversationmgmt counters), each
with a matching alert./metrics output, or how a custom collector is
registered in gserver.go? Ask me.
1. Prometheus — Configuration; in-repo platforms/monitoring/prometheus/values.yaml:424-467, internal/golibs/bootstrap/monitor.go:75.