Implement metrics and traces surfaces (currently stubbed) #33

Closed
opened 2026-06-17 07:45:22 +00:00 by coilysiren · 2 comments
Owner

Originally filed by @coilysiren on 2026-04-24T12:38:05Z

Both the metrics and traces surfaces are currently stubbed no-ops. V1 exception/log capture works; the remaining roadmap items are the OTel metric emitter and the trace-span wrapper.

Metrics (`src/MetricsWorker.cs:34-38`)

Currently a 5-minute sleep loop with no emission. Wire OTel gauges/counters for:

  • `UserManager.OnlineUsers.Count` -> `eco.players.online` gauge
  • `WorldObjectManager` totals (by type) -> `eco.world_objects.count` gauge, tagged by object type
  • `Simulation.Time.WorldTime.Seconds` -> `eco.sim.world_time_seconds` counter
  • Stats plugin data (if accessible) -> `eco.stats.*`

GC/threadpool metrics come free via `OpenTelemetry.Instrumentation.Runtime`; confirm the package is registered.

Traces (`src/TraceSurface.cs:18-21`)

`ActivitySource` is created but nothing starts spans. Candidate integrations:

  • Wrap `PluginManager` init paths in spans (likely needs reflection or a public hook from EcoModKit; investigate).
  • Slow-handler detector: sample handler durations over a threshold (config-driven, e.g. 100ms) and emit as spans.
  • Kestrel request pipeline if the server exposes a hook point.

Verification

  • `dotnet build` succeeds.
  • Local Eco server run with an OTLP collector (e.g. otel-collector-contrib in Docker) shows the new metrics and spans flowing.
  • No regression in exception capture or log interception.

Out of scope

  • Publishing to mod.io (separate task).
  • `IConfigurablePlugin` admin-UI config editing (separate task).

Migrated from coilyco-flight-deck/eco-telemetry#4 during the eco repo consolidation (coilysiren/inbox#100). Reinstated per Kai - this item survives the cycle and belongs in eco-app.

_Originally filed by @coilysiren on 2026-04-24T12:38:05Z_ Both the metrics and traces surfaces are currently stubbed no-ops. V1 exception/log capture works; the remaining roadmap items are the OTel metric emitter and the trace-span wrapper. ## Metrics (\`src/MetricsWorker.cs:34-38\`) Currently a 5-minute sleep loop with no emission. Wire OTel gauges/counters for: - \`UserManager.OnlineUsers.Count\` -> \`eco.players.online\` gauge - \`WorldObjectManager\` totals (by type) -> \`eco.world_objects.count\` gauge, tagged by object type - \`Simulation.Time.WorldTime.Seconds\` -> \`eco.sim.world_time_seconds\` counter - Stats plugin data (if accessible) -> \`eco.stats.*\` GC/threadpool metrics come free via \`OpenTelemetry.Instrumentation.Runtime\`; confirm the package is registered. ## Traces (\`src/TraceSurface.cs:18-21\`) \`ActivitySource\` is created but nothing starts spans. Candidate integrations: - Wrap \`PluginManager\` init paths in spans (likely needs reflection or a public hook from EcoModKit; investigate). - Slow-handler detector: sample handler durations over a threshold (config-driven, e.g. 100ms) and emit as spans. - Kestrel request pipeline if the server exposes a hook point. ## Verification - \`dotnet build\` succeeds. - Local Eco server run with an OTLP collector (e.g. otel-collector-contrib in Docker) shows the new metrics and spans flowing. - No regression in exception capture or log interception. ## Out of scope - Publishing to mod.io (separate task). - \`IConfigurablePlugin\` admin-UI config editing (separate task). --- _Migrated from coilyco-flight-deck/eco-telemetry#4 during the eco repo consolidation (coilysiren/inbox#100). Reinstated per Kai - this item survives the cycle and belongs in eco-app._
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-eco-app-33 on host kais-macbook-pro-2.local is carrying this issue (reserved 2026-07-02T02:39:33Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-eco-app-33` on host `kais-macbook-pro-2.local` is carrying this issue (reserved 2026-07-02T02:39:33Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - metrics (world objects, world-time, GlobalStats) and an OTLP trace surface (init spans + config-driven slow-handler detector) now emit for real; merged to main and pushed.

Honestly this one was more pleasant than I expected. The scaffolding here was already good - the pipeline, config resolution, and exception/log capture gave me a clear pattern to copy, so the metrics were mostly "find the right Eco API and wire the observable instrument." The thing that fought back was verification: no dotnet in the container and no live Eco server, so I installed the SDK myself and wrote a MetadataLoadContext reflector to pin down the actual API shapes (WorldObjectManager.ForEach, WorldTime.Seconds, StatGameplaySettings.LatestGlobalStats) instead of guessing. That paid off - I'd have gotten the GlobalStats accessor wrong from memory.

For traces I made a judgment call: the issue's candidates (PluginManager-wide init spans, Kestrel hooks) all need live-server integration points I can't confirm from a build, so I built the real foundation instead - a TracerProvider on the ActivitySource plus a backdated, threshold-gated slow-handler primitive - wired it into our own plugin init, and documented the reflection/Kestrel call sites as follow-ups rather than shipping fragile guesses.

Confidence: high that it compiles and the OTel plumbing is correct - I proved the trace threshold gating and the multi-measurement metric export with standalone OTel harnesses against the real 1.12.0 packages. Medium on the live end-to-end, since I couldn't run an actual Eco server with a collector - the callbacks are all init-safe and try-guarded, but real-world thread-safety of iterating WorldObjectManager on the export thread is the one thing I'd want eyes on under load.

Rough edges / follow-ups worth filing: the diagnostic smoke-probe + Console.Error spam in StartMetrics is still there (that's issue #5, left alone); a live-server smoke test of the new metrics/spans against an OTLP collector; and the deferred PluginManager/Kestrel trace call sites if broader span coverage is wanted.

WARD-OUTCOME: done - metrics (world objects, world-time, GlobalStats) and an OTLP trace surface (init spans + config-driven slow-handler detector) now emit for real; merged to main and pushed. Honestly this one was more pleasant than I expected. The scaffolding here was already good - the pipeline, config resolution, and exception/log capture gave me a clear pattern to copy, so the metrics were mostly "find the right Eco API and wire the observable instrument." The thing that fought back was verification: no dotnet in the container and no live Eco server, so I installed the SDK myself and wrote a MetadataLoadContext reflector to pin down the actual API shapes (WorldObjectManager.ForEach, WorldTime.Seconds, StatGameplaySettings.LatestGlobalStats) instead of guessing. That paid off - I'd have gotten the GlobalStats accessor wrong from memory. For traces I made a judgment call: the issue's candidates (PluginManager-wide init spans, Kestrel hooks) all need live-server integration points I can't confirm from a build, so I built the real foundation instead - a TracerProvider on the ActivitySource plus a backdated, threshold-gated slow-handler primitive - wired it into our own plugin init, and documented the reflection/Kestrel call sites as follow-ups rather than shipping fragile guesses. Confidence: high that it compiles and the OTel plumbing is correct - I proved the trace threshold gating and the multi-measurement metric export with standalone OTel harnesses against the real 1.12.0 packages. Medium on the live end-to-end, since I couldn't run an actual Eco server with a collector - the callbacks are all init-safe and try-guarded, but real-world thread-safety of iterating WorldObjectManager on the export thread is the one thing I'd want eyes on under load. Rough edges / follow-ups worth filing: the diagnostic smoke-probe + Console.Error spam in StartMetrics is still there (that's issue #5, left alone); a live-server smoke test of the new metrics/spans against an OTLP collector; and the deferred PluginManager/Kestrel trace call sites if broader span coverage is wanted.
Sign in to join this conversation.
No description provided.