Skip to content

feat(otel): RED-minimal metrics + spec-path spans - #348

Merged
schickling-assistant merged 6 commits into
schickling/2026-08-25-otelfrom
schickling/2026-08-26-otel-metrics
Aug 26, 2026
Merged

feat(otel): RED-minimal metrics + spec-path spans#348
schickling-assistant merged 6 commits into
schickling/2026-08-25-otelfrom
schickling/2026-08-26-otel-metrics

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Stacked on #347 (PR1 — traces). Part 2 of the observability stack (VRS 06-observability).

What

RED-minimal metric set per interview decision Q5, plus the spec-up span coverage folded into this slice:

  • Meter provider in Telemetry::init alongside the tracer: same OTEL_EXPORTER_OTLP_ENDPOINT guard, same resource (st2-<unit>, version, host), OTLP/HTTP-JSON MetricExporter + PeriodicReader. Unset endpoint → no provider; the global meter is a silent no-op and every record call early-outs before touching an instrument (zero-overhead guarantee, R02). Telemetry::shutdown force-flushes points with spans so short-lived CLI runs deliver them.
  • Instruments (new src/metrics.rs), labels only from bounded enums — ids never become labels:
    Instrument Type Labels
    reconcile_passes_total counter result=pass|fail
    task_launches_total counter driver=codex|claude|opencode|pi|exec|other
    task_reaps_total counter driver (same enum)
    hook_invocations_total counter hook (registry name), event (bounded Claude set → other)
    message_deliveries_total counter result=pass|fail
    crash_loops_total counter
    reconcile_pass_duration_seconds histogram
    session_start_duration_seconds histogram
  • Spec-path spans: reconcile_pass_specs_with_sessions now emits the same st2.reconcile_pass root-span shape as the catalog loop pass and up_once.
  • Docs: spec.md metrics section + open-questions.md moved to landed reality.
  • CI proof: tests/otel_export.rs asserts reconcile_passes_total / reconcile_pass_duration_seconds rows land in otelite's metrics.ndjson, including the result=pass attribute.

Instrumentation stays strictly observational: counters/histograms only, no behavior change to reconcile/launch/reap logic (INVARIANTS).

Verification

  • nix develop -c cargo build green
  • nix develop -c cargo test --lib: 486 passed (incl. new metrics unit tests)
  • ST2_OTELITE_BIN=/tmp/st2-otel-interview/otelite/bin/otelite nix develop -c cargo test --test otel_export: 2 passed (spans + metrics captured end-to-end)
Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@929dc21

@schickling-assistant

Copy link
Copy Markdown
Contributor Author

@codex Please review — PR 2 of the otel stack (base: #347): RED-minimal metrics per design decision Q5.

Counters: reconcile_passes_total{result}, task_launches_total{driver}, task_reaps_total{driver}, hook_invocations_total{hook,event}, message_deliveries_total{result}, crash_loops_total.
Histograms: reconcile_pass_duration_seconds, session_start_duration_seconds.

Labels bounded to enums only; ids stay in span attributes per the central cardinality policy. Also instruments the spec-up path with st2.reconcile_pass. CI asserts metric rows in otelite metrics.ndjson.

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@929dc21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 766137accc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/run.rs Outdated
Comment thread src/claude_session.rs Outdated
Comment thread src/message.rs Outdated
@schickling-assistant
schickling-assistant force-pushed the schickling/2026-08-26-otel-metrics branch 5 times, most recently from fa2b896 to d784fba Compare August 26, 2026 16:53
Meter provider alongside the tracer in Telemetry::init (same endpoint
guard, resource, and OTLP/HTTP-JSON wire); shutdown flushes both.
Instruments per interview decision Q5, labels only from bounded enums:
reconcile_passes_total{result}, task_launches_total{driver},
task_reaps_total{driver}, hook_invocations_total{hook,event},
message_deliveries_total{result}, crash_loops_total,
reconcile_pass_duration_seconds, session_start_duration_seconds.
All record calls early-out unless a provider is installed.

The single-file spec path (reconcile_pass_specs_with_sessions) now emits
the same st2.reconcile_pass root span as the catalog paths. otelite e2e
asserts metric rows land in metrics.ndjson.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@929dc21
… metrics

- crash_loops_total: record once per park (inside the reported_flapping
  first-transition blocks) instead of every reconcile pass a task stays
  parked; execute no longer records per-pass.
- hook metrics: classify `st2 driver claude-observe` as telemetry unit
  "hook" in main.rs so hook_invocations_total exports under st2-hook per
  the documented process-unit contract (only claude observe records hook
  metrics today). Spec doc updated to match.
- message_deliveries_total: record result="fail" when the archived-path
  read_to_string fails instead of returning before any recording.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@929dc21
…vocations

Duration histograms recorded as_secs_f64() against the SDK's
millisecond-tuned default boundaries, collapsing sub-second reconcile
passes and session spawns into the lowest buckets. Register an explicit
view mapping both duration instruments onto 1ms..10s explicit buckets.

hook_invocations_total fired before agent-dir resolution, counting
invocations that never applied (undeclared agent). Record it after the
application target resolves.

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@929dc21
…uckets

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@929dc21
Replace the OTLP JSON substring match with parsed assertions on the
reconcile passes counter attribute and the duration histogram's
explicitBounds (12 seconds-scale boundaries, lowest 1ms).

agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@929dc21
agent-identity: unknown
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.0.3
agent-runtime: OMP 18.0.3
tooling-profile: dotfiles@e4789b0
@schickling-assistant
schickling-assistant force-pushed the schickling/2026-08-26-otel-metrics branch from d784fba to d314338 Compare August 26, 2026 19:17
@schickling-assistant
schickling-assistant merged commit af4881e into main Aug 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant