Skip to content

Self-hosting

Observability

Metrics, logs, and tracing emitted by the Golden Reports stack, and how to wire them into your monitoring infrastructure.

Every service in Golden Reports emits structured logs, Prometheus metrics, and OpenTelemetry traces. This page is the catalog: what's emitted, where it's emitted from, and how to wire it into the rest of your monitoring stack.


What's emitted

SurfaceFormatFrom
Application logsStructured JSON to stdoutapi, query-engine, data-provider, manager
MetricsPrometheus exposition (/metrics)api, query-engine, data-provider
TracesOpenTelemetry OTLPapi, query-engine, data-provider
Audit logPersisted records in the platform DBapi

The platform follows the modern Kubernetes-native convention: logs go to stdout, metrics are scraped over HTTP, traces are pushed over OTLP. There's no proprietary collector to deploy.


Logs

All services log structured JSON. The key fields you'll see across every service:

  • timestamp - ISO 8601.
  • level - Debug, Information, Warning, Error, Critical.
  • message - human-readable.
  • traceId and spanId - OpenTelemetry trace context.
  • tenantId - when the request has tenant context.
  • correlationId / plan_id - for query-engine operations.
  • service.name - the service emitting the log (api, query-engine, etc.).

Logs are emitted at Information level by default. Increase to Debug per-service through the Logging:LogLevel:* environment variables exposed in each component's env block.

Collecting logs

Any Kubernetes log collector that reads stdout works:

  • Fluent Bit - DaemonSet that tails container logs and ships to your sink.
  • Vector - same shape.
  • Loki + Promtail - for Grafana-native logging.
  • CloudWatch / Stackdriver / Datadog - managed equivalents.

A useful filter: service.name="api" AND level >= "Warning" is a good starting point for a "what's not right" stream.


Metrics

Each service exposes Prometheus metrics on /metrics on its container port. The chart's Service already exposes the port; you only need to point your Prometheus instance at it.

Suggested scrape config

- job_name: golden-reports
  kubernetes_sd_configs:
    - role: pod
  relabel_configs:
    - source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name]
      regex: golden-reports
      action: keep
    - source_labels: [__meta_kubernetes_pod_container_port_name]
      regex: http
      action: keep

Or, if you run the Prometheus Operator, add a ServiceMonitor selecting the chart's Services by label.

Key metrics by service

Platform API

  • http_server_request_duration_seconds_bucket - request latency histogram, labelled by route and status.
  • Runtime counters (GC, thread pool, exceptions) - useful for capacity tuning.
  • Handler-level timing - internal-handler duration histogram, useful when narrowing down a slow request.

Query Engine

  • engine_executions_total - counter, labelled by execution status.
  • engine_execution_duration_seconds - histogram covering fetch and in-engine processing phases.
  • engine_rows_returned_total - counter.
  • engine_active_executions - current gauge.
  • engine_errors_total - counter, labelled by error category.

Data Provider

  • connector_invocations_total - counter for connector operations.
  • connector_invocation_duration_seconds - histogram.
  • connector_load_errors_total - counter.

Dashboards worth building

A minimum useful dashboard set:

  • API latency - request duration p50/p95/p99 by route.
  • Engine throughput - executions per second, error rate, p95 latency.
  • Active reports - engine_active_executions gauge.
  • Error breakdown - engine_errors_total and failed connector_invocations_total stacked by category.

Tracing

OpenTelemetry tracing is enabled by default. To send spans to a collector, set:

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production

on each Deployment via the chart's env blocks.

What's instrumented

  • HTTP server (Platform API): every inbound request.
  • HTTP client (Platform API): every outbound call.
  • Inter-service calls (API → engine, engine → data-provider): every call.
  • Platform-database queries (parameter values redacted).
  • Internal handler timing: every command/query handler.
  • Custom spans: report rendering, plan building, query execution phases.

The plan_id correlation

The query engine emits a plan_id (UUID) on every execution. This propagates as the correlation ID from the API into the engine and onwards:

GraphQL request (API)
└── span: ExecuteReport
    ├── span: BuildPlan
    └── span: QueryEngine.Execute    plan_id=<uuid>
        └── span: Connector.Fetch    plan_id=<uuid>

Searching your trace store for a plan_id returns the full execution path across services. The API also includes the plan_id in the export response, so you can search backwards from a customer-reported "this report failed" all the way to the connector's outbound call.


Audit log

A separate concern from operational telemetry. Every privileged action - workspace member change, data-access policy edit, share grant, plugin install, billing change - writes an audit record to the platform database.

The Manager exposes a queryable view at Manager → Audit with filters by:

  • Actor (user).
  • Action category (membership changes, policy edits, share grants, plugin installs, billing changes).
  • Target (record affected).
  • Time range.

The audit log is append-only at the platform level - it cannot be deleted or modified through the API. For compliance regimes that require external archival, export the audit log periodically through the API and ship it to your SIEM.


A starter alert set:

AlertCondition
API error raterate(http_server_requests_total{status=~"5.."}[5m]) > 1%
API latencyhistogram_quantile(0.95, http_server_request_duration_seconds) > 1s
Engine error raterate(engine_errors_total[5m]) / rate(engine_executions_total[5m]) > 5%
Engine queue saturationactive executions approaching the configured concurrency cap
Connector load failuresincrease(connector_load_errors_total[10m]) > 0
Platform DB connection failuresrate of database open failures > 0
Pod restartsrate(kube_pod_container_status_restarts_total{namespace="golden-reports"}[15m]) > 0.1
Migration job failurekube_job_status_failed{job_name=~".*migration.*"} > 0

Tune the thresholds to your own traffic and SLOs.


Health endpoints

In addition to /metrics, each backend component exposes:

EndpointReturns
/health/live200 if the process is alive. Used by Kubernetes liveness probe.
/health/ready200 if the process can handle traffic (database reachable, dependencies up). Used by readiness probe.

The Manager doesn't have dedicated health endpoints - readiness defaults to a 200 on /.


What's not (yet) provided

  • Built-in dashboards. The platform doesn't ship Grafana dashboards. Build your own from the metrics above; we may publish reference dashboards in a future release.
  • Built-in alerting. No bundled Alertmanager rules. The alert list above is a starting point.
  • Per-tenant metric labels. Most metrics are intentionally low-cardinality. Trace context is where tenant-specific detail lives.

Next

Previous
Helm chart reference