Skip to content

Metrics

DagNats records metrics with the OpenTelemetry metrics API. Each process exports them to the TELEMETRY stream every 10 seconds, and optionally over OTLP.

Pipeline

observe.InitTelemetry (see Distributed Tracing) registers a global meter provider with two readers:

  • a NATS reader, which publishes each metric as JSON on telemetry.metrics.{service}.{name} every 10 seconds;
  • an OTLP/HTTP reader, added when OTEL_EXPORTER_OTLP_ENDPOINT is set.

The NATS exporter uses cumulative temporality: each point carries the running total since the process started, not the change in the last interval. Counters therefore only go up until the process restarts.

Create your own instruments with the standard API:

meter := otel.Meter("my-worker")
processed, _ := meter.Int64Counter("documents.processed")
latency, _ := meter.Float64Histogram("documents.latency_ms")

processed.Add(ctx, 1, metric.WithAttributes(attribute.String("task_type", "ocr")))
latency.Record(ctx, 123.4)

Instrument names are not prefixed, so pick names that will not collide with the ones below.

Metrics DagNats emits

MetricTypeComponentDescription
step.duration_msHistogramWorkerTime to execute a task handler
step.retriesCounterWorkerHandler errors that led to a retry
worker.tasks.activeUpDownCounterWorkerTasks currently being processed
worker.tasks.cancelled_skippedCounterWorkerTasks skipped because their run was already cancelled
worker.log_chunk.publish_failuresCounterWorkerLog chunks that failed to publish
workflow.runs.activeUpDownCounterEngineRuns currently running
workflow.runs.completedCounterEngineRuns that completed
workflow.runs.failedCounterEngineRuns that failed
workflow.runs.reconciledCounterEngineRuns the reconciler repaired
workflow.runs.scan_degradedCounterEngineBounded run scans that had to cap or skip keys; a signal to prune or tune retention
step.enqueue.countCounterEngineTasks published to TASK_QUEUES
step.failure.non_retriableCounterEngineNon-retriable step failures
step.failure.retry_afterCounterEngineStep failures with a requested retry delay
task.concurrency.acquiredCounterEngineTask concurrency slots taken
task.concurrency.rejectedCounterEngineTasks held back by a full concurrency limit
snapshot.save.duration_msHistogramEngineTime to save a run snapshot
dlq_entries_totalCounterEngineEntries written to the dead letter queue
dlq_depthUpDownCounterEngineCurrent dead letter queue depth
api.requestsCounterAPIControl-plane requests
api.errorsCounterAPIControl-plane requests that failed
api.request.duration_msHistogramAPIControl-plane request latency
bridge.requestsCounterBridgeHTTP bridge requests
bridge.request.duration_msHistogramBridgeHTTP bridge request latency
trigger_firings_totalCounterTriggerTrigger fires
trigger_last_fired_secondsGaugeTriggerUnix seconds of each cron trigger’s last successful fire in this process
trigger_next_fire_secondsGaugeTriggerUnix seconds of each enabled cron trigger’s next fire
console_audit_events_totalCounterConsoleConsole audit events written

The engine also emits repair and failure counters for its internal indexes and run finalization (names starting engine.run_active., engine.run_index., engine.finalize. and engine.run_event.), engine.concurrency.legacy_reset, engine.def_pin.missing_version, trigger.run_terminal.depth_refusals, bridge.log_chunk.publish_failures and workertoken.watch_failures. A non-zero value on any of those is worth a look.

Reading metrics

dagnats metrics show --name=step.duration_ms --since=5m --service=<service>

--name is required. --since defaults to 5 minutes, --service filters by the emitting process’s service name, and --json gives machine-readable output.

Prometheus

dagnats serve aggregates the metrics it sees on the stream and serves them in Prometheus text format at /metrics on the HTTP port. Counters get a _total suffix and dots become underscores, so workflow.runs.completed is workflow_runs_completed_total. By default only loopback callers may scrape it. Set METRICS_AUTH to change that:

METRICS_AUTHBehavior
loopback (default)Only 127.0.0.1 and ::1
basicHTTP Basic auth with METRICS_BASIC_USER and METRICS_BASIC_PASS
forwardTrust X-Forwarded-User from a reverse proxy
noneOpen to every caller; logs a warning at startup

An unknown value falls back to loopback.

dagnats observe status reports whether the telemetry pipeline is healthy.

Related