Scanner observability

Verified against commit 942a18727c (2026-09-26). Re-verify with: grep -rhoE "Create(Counter|Histogram|UpDownCounter|ObservableGauge)<[a-z]+>\(\s*\"[^\"]+\"" src/Scanner src/__Libraries/StellaOps.Scanner.ProofSpine and grep -oE "\"scanner_worker_[a-z_]+\"" src/Scanner/StellaOps.Scanner.Worker/Diagnostics/ScannerWorkerMetrics.cs.

This page records the metric, log, and trace contracts that operators bind dashboards and alerts to. Renaming or removing a metric listed here requires a sprint task and a same-change update of the dashboards under operations/.

Metric inventory

MetricTypeSource
scanner_queue_enqueued_total, scanner_queue_deduplicated_total, scanner_queue_ack_total, scanner_queue_retry_total, scanner_queue_deadletter_totalcounterssrc/Scanner/__Libraries/StellaOps.Scanner.Queue/QueueMetrics.cs
scanner.layer_cache_hits_total, scanner.layer_cache_misses_total, scanner.layer_cache_evictions_total, scanner.layer_cache_bytescounters / histogramsrc/Scanner/__Libraries/StellaOps.Scanner.Cache/ScannerCacheMetrics.cs
scanner.file_cas_hits_total, scanner.file_cas_misses_total, scanner.file_cas_evictions_total, scanner.file_cas_bytescounters / histogramsame
scanner_worker_job_duration_ms, scanner_worker_stage_duration_ms, scanner_worker_queue_latency_mshistogramssrc/Scanner/StellaOps.Scanner.Worker/Diagnostics/ScannerWorkerMetrics.cs
scanner_worker_jobs_completed_total, scanner_worker_jobs_failed_totalcounterssame
scanner_worker_language_cache_{hits,misses}_total, scanner_worker_os_cache_{hits,misses}_totalcounterssame
scanner_worker_surface_manifests_{published,failed,skipped}_total, scanner_worker_surface_manifest_publish_duration_ms, scanner_worker_surface_payload_persisted_totalcounters / histogramsame
scanner_worker_registry_secret_requests_total, scanner_worker_registry_secret_ttl_secondscounter / histogramsame
scanner_worker_secrets_analysis_{completed,failed}_total, scanner_worker_secrets_analysis_duration_ms, scanner_worker_secrets_findings_detected_totalcounters / histogramsame
scanner_analyzer_golang_heuristic_total{indicator,version_hint}countersrc/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang.Go/Internal/GoAnalyzerMetrics.cs
entrytrace_resolutions_total{outcome}, entrytrace_unresolved_total{reason}counterssrc/Scanner/__Libraries/StellaOps.Scanner.EntryTrace/Diagnostics/EntryTraceMetrics.cs
scanner.runtime.policy.requests, scanner.runtime.policy.latency.mscounter / histogramsrc/Scanner/StellaOps.Scanner.WebService/Services/RuntimePolicyService.cs
scanner_proofspine_validation_failures_total, scanner_proofspine_validation_successes_totalcounterssrc/__Libraries/StellaOps.Scanner.ProofSpine/Diagnostics/ProofSpineValidationMetrics.cs (details below)

Scanner has no /metrics HTTP route (Q-25). The Worker exports metrics and traces through OpenTelemetry (src/Scanner/StellaOps.Scanner.Worker/Diagnostics/TelemetryExtensions.cs: OTLP when an endpoint is configured, console otherwise); the WebService telemetry switches live under scanner:telemetry.

ProofSpine validation metrics

scanner_proofspine_validation_failures_total

Counter. Incremented once per ProofSpine input rejected by StellaOps.Scanner.ProofSpine.Validation.ProofSegmentValidator (src/__Libraries/StellaOps.Scanner.ProofSpine/Validation/ProofSegmentValidator.cs).

Sprint reference: SPRINT_20260429_003_Scanner_proofspine_input_validation.md.

LabelCardinalityValues
reasonCodeBounded (≤16)One of the codes listed in proofspine.md.
tenantIdBounded by tenant populationTenant the request belongs to, or unknown.

Combined cardinality stays well below the 100-label threshold defined in .memory/standards/TESTING_PRACTICES.md (“Metrics contracts”).

scanner_proofspine_validation_successes_total

Counter. Paired success counter, used by dashboards to compute failure rate failures / (failures + successes). Single label tenantId.

Sample Grafana panel

Panel JSON (paste into a Grafana dashboard’s “Add panel -> Import JSON” dialog):

{
  "title": "ProofSpine validation failure rate",
  "type": "timeseries",
  "datasource": "Prometheus",
  "targets": [
    {
      "refId": "A",
      "expr": "sum by (reasonCode) (rate(scanner_proofspine_validation_failures_total[5m]))",
      "legendFormat": "{{reasonCode}}"
    }
  ],
  "fieldConfig": {
    "defaults": {
      "unit": "ops",
      "thresholds": {
        "mode": "absolute",
        "steps": [
          { "color": "green", "value": null },
          { "color": "yellow", "value": 0.1 },
          { "color": "red", "value": 1 }
        ]
      }
    }
  },
  "options": {
    "legend": { "displayMode": "table", "placement": "right" },
    "tooltip": { "mode": "multi" }
  }
}

A companion ratio panel (failures over total):

{
  "title": "ProofSpine validation failure ratio",
  "type": "stat",
  "datasource": "Prometheus",
  "targets": [
    {
      "refId": "A",
      "expr": "sum(rate(scanner_proofspine_validation_failures_total[5m])) / clamp_min(sum(rate(scanner_proofspine_validation_failures_total[5m]) + rate(scanner_proofspine_validation_successes_total[5m])), 1)"
    }
  ],
  "fieldConfig": {
    "defaults": { "unit": "percentunit" }
  }
}

Logs

The validator itself does not emit logs (it is a pure function). The endpoint records validation outcomes via the metrics counter. Operators correlate spikes in the failure counter with the request log for the matching tenantId and the X-Correlation-Id header.

Traces

ProofSpine endpoints inherit the standard Scanner WebService OTel span set: HTTP GET /api/v1/spines/{spineId} with attributes tenant.id, correlation.id, and (on failure) proofspine.validation.reasonCode. The validator does not start its own span; it adds the reason code as an attribute on the parent endpoint span when called.