Observability
Monitoring Berserk itself — the per-pod Prometheus metrics endpoint and exporting Berserk's own telemetry over OTLP
Berserk has two monitoring surfaces. Enable either or both:
| Surface | Model | What it carries |
|---|---|---|
Prometheus /metrics | Pull: your Prometheus scrapes each pod | A curated set of operator metrics, per pod |
| OTLP export | Push: services send to an OTLP endpoint | All of Berserk's own logs, metrics and traces |
The Prometheus endpoint feeds an existing monitoring stack. OTLP export carries everything, and can send Berserk's telemetry back into Berserk.
Prometheus metrics endpoint
Every Berserk pod serves GET /metrics in Prometheus text format on an internal HTTP port. A Prometheus, or any compatible scraper, in your cluster can collect it; it needs no Prometheus Operator, no CRDs and no Berserk configuration.
| Service | Port | Where it lives |
|---|---|---|
| gateway | 9502 | Dedicated internal listener; the public edge port (9500) never serves /metrics |
| meta | 9560 | HTTP side of the main service port |
| query | 9511 | Dedicated internal listener, separate from the query API port (9510) |
| ingest | 9550 | Internal health port |
| janitor | 9502 | Internal health port |
| nursery | 9530 | Main service port |
| ui | 9571 | Dedicated internal listener |
| permissions | 9580 | Main service port |
The endpoint is unauthenticated and reachable only inside the cluster: every service is ClusterIP, and the ports that can be public (the gateway edge and ingest's API ports) do not serve /metrics.
gateway.metricsPort sets the gateway's listener port; "" turns the listener off. After changing it, update the prometheus.io/port annotation in gateway.podAnnotations to match.
What the endpoint exposes
/metrics carries the operator tier, a small set of metrics for dashboards and alerts:
- Request and error rates, ingest throughput, bytes in and out
- Queue depths, merge backlog, in-flight query gauges
- Cache occupancy and hit rates
- S3 request, failure and bandwidth counters
- Latency histograms (query execution, S3, upstream calls)
- Process and container basics: CPU, working-set memory, file-descriptor usage, uptime
Values are pod totals. On the multi-process pods (query, nursery), the short-lived per-query worker processes record into shared memory owned by the pod's main process, so their values are included. Each pod exposes only its own role's metrics.
The full metric set, with the per-query and per-segment detail the operator tier leaves out, goes over OTLP export; Service Metrics lists it. Every operator-tier metric also reaches OTLP under its dotted name, so the bzrk_s3_* metrics behind the UI's Monitoring → Storage page are queryable as bzrk.s3.*. Metrics on only one surface have different names and labels: bzrk.segment_cache.s3_fetch_* and s3.request.* are OTLP-only and do not replace them in queries.
The UI's Monitoring pages read the operator tier through an in-product collector, which scrapes every pod and keeps a short window in memory, lost on restart. For longer history, scrape /metrics with a Prometheus.
Names on the scrape surface:
- Every metric is prefixed
bzrk_, and dots in the OpenTelemetry name become underscores:bzrk.query.errors→bzrk_query_errors. - Most counters have no
_totalsuffix (bzrk_query_errors,bzrk_nursery_bytes_ingested); a few do (bzrk_ingest_invalid_otlp_total,bzrk_*_cpu_seconds_total). Use the names the endpoint reports. - Histograms are classic explicit-bucket:
_bucket{le=...},_sum,_count. Usehistogram_quantile()over the_bucketrate for percentiles.
Scrape configuration
The chart sets the conventional scrape annotations on every pod, in each service's podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/path: /metrics
prometheus.io/port: "<port from the table above>"Cluster-wide annotation-based pod discovery picks Berserk pods up as they are. Otherwise, use a kubernetes_sd_configs pod-discovery job:
scrape_configs:
- job_name: berserk
kubernetes_sd_configs:
- role: pod
namespaces:
names: [<berserk-namespace>]
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels:
[__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- source_labels: [__meta_kubernetes_pod_label_app]
action: replace
target_label: serviceThe last rule adds a service label (gateway, meta, query, …) to every sample, for alerts and dashboards to aggregate on.
Metrics ports under network policies
With network policies on, the metrics ports are open by default only to the peers the chart ships: the UI's in-product collector, and the bundled Prometheus when prometheus.enabled (global.networkPolicy.scrape.from). The chart does not know your monitoring namespace, so allow it:
global:
networkPolicy:
enabled: true
additionalIngress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- port: 9502 # gateway, janitor
protocol: TCP
- port: 9511 # query
protocol: TCP
- port: 9530 # nursery
protocol: TCP
- port: 9550 # ingest
protocol: TCP
- port: 9560 # meta
protocol: TCP
- port: 9571 # ui
protocol: TCP
- port: 9580 # permissions
protocol: TCPFor a narrower rule, use each service's networkPolicy.additionalIngress with only that service's port: Custom Rules.
Exporting Berserk's own telemetry
Berserk services emit their own logs, metrics and traces over OpenTelemetry, and can export them to any OTLP endpoint. Export is off by default:
global:
observability:
otlpEnabled: true
otlpEndpoint: "your-collector:4317"With export on, every Berserk service, the UI included, sends to the endpoint over OTLP gRPC. The stream carries the full metric set (the operator tier plus per-query and per-segment detail), traces and logs. Service Metrics lists every metric with its OpenTelemetry name.
The default endpoint, ingest:4317, is the installation's own ingest
service: Berserk stores its own telemetry, and you query it like any other
data. To keep monitoring through an outage of the cluster, point
otlpEndpoint at a separate collector or a second Berserk installation.
With network policies on, egress to the default ingest:4317 is allowed; an external collector needs an otlpEgress rule: OTLP Telemetry.