Skip to content

objectstack serve registers no ObservabilityServicePlugin, so observability:metrics is unregistered — every consumer but the dispatcher resolves to nothing #9832

Description

@huangyiirene

Found while implementing the transport-owned http_requests_total seam for #9650 (PR #9746). Filed unassigned; not graded by the filing seat.

The claim, measured on 8957c72227 (branch head, origin/main merged at 9ff11921a2)

OBSERVABILITY_METRICS_SERVICE ('observability:metrics') has exactly one registrar in the whole repo — ObservabilityServicePlugin.init(), packages/runtime/src/observability/observability-service-plugin.ts:85.

A repo-wide sweep finds no host that registers it:

grep -rn "ObservabilityServicePlugin" --include=*.ts packages/ apps/ examples/

returns only the plugin's own definition, its own test, and three JSDoc mentions pointing readers at it. packages/cli/src/commands/serve.ts never names it.

What serve.ts does instead (:2564): builds one registry from env and threads it into a single consumer.

constobservability=awaitbuildServeObservability();awaitkernel.use(createDispatcherPlugin({ ...,observability, ... }));

The transport is constructed 800 lines earlier and gets nothing (serve.ts:1758):

constserverPlugin=newHonoServerPlugin({ port });

Consequences, all measured or read on the current ref

Why this is not a one-line change, i.e. why it is filed rather than folded in

buildServeObservability() is called once, deep in the dispatcher block. Calling it a second time at the transport's construction site would build a second exporter — for OS_OBS_EXPORTER=otlp that means two OtlpHttpMetricsRegistry instances with two independent flush timers. So the repair is a choice, not a rewrite:

  1. hoist/memoize buildServeObservability() and pass the same block to new HonoServerPlugin({ port, observability }) — narrow, leaves cache/storage still dark;
  2. register ObservabilityServicePlugin with that block before every consumer and let the documented chain do the rest — one registration, lights up transport, cache and storage together, and matches what the plugin's own JSDoc tells hosts to do ("Register this plugin before any plugin that wants to consume the services").

Option 2 looks right and is the reason this is a card rather than a rider: it changes plugin ordering in serve.ts and turns three currently-silent metric families on at once, which deserves a deliberate decision rather than a side effect of an unrelated PR.

Scope note

packages/cli/src/commands/serve.ts was read only — no edit was made from #9650's dispatch, whose file surface did not include it.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions