Skip to main content

Observability

Sukko ships with an optional bundled monitoring stack (Prometheus, Grafana, Loki), but every observability signal is designed to integrate with your existing infrastructure.

What Sukko Exposes​

SignalFormatEndpoint / Output
MetricsPrometheus/metrics on every service
LogsStructured JSONstdout (standard K8s log collection)
TracesOpenTelemetry (OTLP)Configurable exporter endpoint
DashboardsGrafana JSONBundled in Helm chart, exportable

Using the Bundled Stack​

Sukko's Helm chart includes a monitoring profile with Prometheus, Grafana, and Loki pre-configured. Enabled by default:

helm install sukko sukko-dev/sukko --set monitoring.enabled=true

For local development with Docker Compose, observability is opt-in via profile:

sukko init  # Select "yes" for observability when prompted
sukko up

Using Your Own Stack​

If you already run Prometheus, Grafana, Datadog, or another monitoring platform, disable the bundled stack and point Sukko at your infrastructure.

Step 1: Disable Bundled Monitoring​

helm install sukko sukko-dev/sukko --set monitoring.enabled=false

Step 2: Scrape Metrics​

Every Sukko service exposes Prometheus metrics at /metrics. Add them as scrape targets in your existing Prometheus:

# prometheus.yml
scrape_configs:
- job_name: sukko-gateway
static_configs:
- targets: ['sukko-gateway:3000']
- job_name: sukko-core
static_configs:
- targets: ['sukko-server:3005']
- job_name: sukko-provisioning
static_configs:
- targets: ['sukko-provisioning:8080']

Step 3: Collect Logs​

All services log structured JSON to stdout. Your existing log collector (Fluentd, Fluent Bit, Datadog Agent, Vector, etc.) picks them up automatically through standard Kubernetes log collection — no Loki dependency required.

Step 4: Import Dashboards​

Sukko's Grafana dashboards are JSON files bundled in the Helm chart. To use them in your own Grafana instance, export them from:

deployments/helm/sukko/charts/monitoring/dashboards/

Import the JSON files into your Grafana via the UI or API.

Step 5: Enable Tracing (Optional)​

Sukko supports OpenTelemetry tracing. Point it at any OTLP-compatible collector (Jaeger, Tempo, Datadog, Honeycomb, etc.):

helm install sukko sukko-dev/sukko \
--set monitoring.enabled=false \
--set env.OTEL_TRACING_ENABLED=true \
--set env.OTEL_EXPORTER_ENDPOINT=your-collector:4317

Step 5: Enable Profiling (Optional)​

Sukko supports continuous profiling via Pyroscope:

helm install sukko sukko-dev/sukko \
--set env.PYROSCOPE_ENABLED=true \
--set env.PYROSCOPE_ADDR=http://your-pyroscope:4040

Broadcast Delivery Signals​

The core server fans every ingested message out through the Valkey broadcast bus. If the bus is unreachable, the Kafka consumer deliberately stops advancing rather than committing past messages it could not deliver — delivery is at-least-once, so an outage costs latency and consumer lag, never silent message loss.

That trade-off is worth understanding before it happens: while the bus is down, the consumer blocks on the undelivered message and all tenants sharing that consumer wait behind it. Messages are not dropped; they are delayed until the bus returns, then delivered (possibly more than once — each carries a stable message id for de-duplication).

Three counters make the condition visible:

MetricMeaning
ws_broadcast_publish_failures_totalBroadcast publishes that failed — non-zero means the bus is unreachable or rejecting
ws_consumer_broadcast_retries_totalRetry attempts on held messages; climbing means the consumer is stalled on an undelivered message
ws_consumer_broadcast_blocked_seconds_totalCumulative time the consumer spent blocked — the direct measure of ingestion backpressure

Recommended alerts for your own stack:

# Bus unreachable — delivery is stalled, not losing data
- alert: SukkoBroadcastPublishFailing
expr: rate(ws_broadcast_publish_failures_total[5m]) > 0
for: 2m
labels: { severity: critical }

# Sustained ingestion backpressure
- alert: SukkoConsumerBlocked
expr: rate(ws_consumer_broadcast_blocked_seconds_total[5m]) > 0.1
for: 5m
labels: { severity: warning }

Pair these with Kafka consumer lag: rising lag with blocked-seconds climbing is a bus outage; rising lag without it is a throughput problem.

Subscription health​

The core server holds one Valkey subscription per tenant, and it reconciles what it should be subscribed to against what it has confirmed — so a lost subscription repairs itself rather than leaving a tenant silently undelivered.

MetricMeaning
ws_broadcast_subscriptions_desiredSubscriptions this pod should hold
ws_broadcast_subscriptions_establishedSubscriptions confirmed on its current connection

established below desired while publishes succeed is the signal to watch. It means messages are being published that this pod's subscribers cannot receive. It is normal for a fraction of a second after a tenant's first subscribe or last unsubscribe, and during bus reconnection; sustained divergence is not.

- alert: SukkoSubscriptionsNotConverged
expr: ws_broadcast_subscriptions_established < ws_broadcast_subscriptions_desired
for: 2m
labels: { severity: warning }

GET /health on the core server reports the same condition under checks.broadcast, with publish_healthy, subscriptions_converged, and the desired/established pair. Non-convergence is reported as degraded with HTTP 200 — deliberately, so it never fails the liveness probe. A pod whose subscription is still converging continues serving its existing connections, and restarting pods during a bus outage would turn a recoverable blip into a fleet-wide one.

Summary​

ScenarioHelm Config
Use bundled stackmonitoring.enabled=true (default)
Use your own stackmonitoring.enabled=false + scrape /metrics + collect stdout logs
Add tracingOTEL_TRACING_ENABLED=true + OTEL_EXPORTER_ENDPOINT=...
Add profilingPYROSCOPE_ENABLED=true + PYROSCOPE_ADDR=...

Tracing Details PRO​

Tracing is instrumented on cold paths only — operations that happen infrequently (connection setup, auth validation, Kafka rebalance). Hot paths (per-message delivery, broadcast fan-out) are not traced to protect latency; they're covered by Prometheus histograms instead.

Instrumented paths:

  • Gateway: WebSocket upgrade, auth validation, auth refresh, publish authorization
  • Core: Kafka consumer setup/rebalance, shard creation
  • Provisioning: API request handling, database queries, gRPC stream events

Exporters: OTLP/gRPC (default), OTLP/HTTP, stdout (development)

If the tracing backend is unreachable, spans are dropped silently — tracing never blocks the message pipeline.

Alerting PRO​

The bundled Helm chart includes PrometheusRule definitions with default alerts:

AlertConditionSeverity
Connection capacity > 80%5 min sustainedWarning
Connection capacity > 95%2 min sustainedCritical
Error rate > 1%5 min sustainedWarning
Pod restarts > 210 min windowWarning
Kafka consumer lag > 10005 min sustainedWarning
Memory > 80% of limit10 min sustainedWarning
License expiry within 7 days—Warning
Service down2 minCritical

AlertManager supports Slack, PagerDuty, OpsGenie, email, and generic webhooks. Configure via Helm values — no chart modification needed.

Operators can add custom alert rules via Helm values alongside the defaults.

Next Steps​