feat(go): add gated OTLP metrics, reconcile events, and log bridge (#2148) - #2675
Open
MartinForReal wants to merge 2 commits into
Open
feat(go): add gated OTLP metrics, reconcile events, and log bridge (#2148)#2675MartinForReal wants to merge 2 commits into
MartinForReal wants to merge 2 commits into
Conversation
Implements the Go observability gaps in kagent-dev#2148 as three independent, default-OFF additions so the Go runtime/controller match the OpenTelemetry capabilities of the Python runtime: 1. go/adk — GenAI token usage metrics. Configure a MeterProvider with a periodic OTLP metric exporter and emit gen_ai.client.token.usage (Int64 histogram, unit {token}) with the same attribute set the Python runtime records (gen_ai.token.type input/output, gen_ai.request.model, gen_ai.response.model, gen_ai.provider.name, gen_ai.agent.name). The A2A executor records one input + one output observation per LLM call (prompt tokens; output = candidate + reasoning tokens), skipping streamed Partial events. Gated behind OTEL_METRICS_ENABLED. 2. go/core — Kubernetes Events on reconcile. The RemoteMCPServer and MCPServer (MCPServerTool) discovery reconcilers emit Normal ToolsDiscovered and Warning ValidationFailed / Warning ReconcileFailed via an optional EventRecorder. Emission is skipped when no recorder is wired (the default), so behavior is byte-identical to today. 3. go/core — controller log -> OTLP bridge. InitLoggerProvider builds an OTLP LoggerProvider via autoexport (same resource as traces) and ControllerZapOpts tees the controller zap logger with an otelzap bridge core while preserving stdout. Gated behind OTEL_LOGGING_ENABLED; when unset both functions are no-ops. Promotes the OTLP metric and log SDK dependencies to direct requires (same versions already in the graph) and adds the otelzap bridge dependency. Refs: kagent-dev#2148 Signed-off-by: MartinForReal <fanshangxiang@gmail.com>
Signed-off-by: MartinForReal <fanshangxiang@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the Go-side observability gaps from #2148 as three independent, default-OFF additions so the Go runtime/controller expose the same OpenTelemetry signals as the Python runtime.
1. Go ADK — GenAI token-usage metrics (
go/adk)Configures a MeterProvider with a periodic OTLP metric exporter and emits
gen_ai.client.token.usage(Int64 histogram, unit{token}) per LLM call.gen_ai.token.type(input/output),gen_ai.request.model,gen_ai.response.model,gen_ai.provider.name,gen_ai.agent.name.Partialevents so chunked streams are not double-counted.config_usage.ModelName); response model falls back to the request model.OTEL_METRICS_ENABLED(default OFF) and the standardOTEL_EXPORTER_OTLP_*endpoint/protocol resolution shared with traces.adk/pkg/telemetry/metrics_test.go(recording via ManualReader, provider-name mapping) andadk/pkg/a2a/executor_metrics_test.go(token accounting + partial/nil guard).2. Kubernetes Events on reconcile (
go/core)The discovery reconcilers surface lifecycle events via an optional
EventRecorder, mirroring the agentharness-substrate-controller pattern:internal/controller/remotemcpserver):Normal ToolsDiscovered,Warning ValidationFailed,Warning ReconcileFailed.internal/controller/mcpserver):Normal ToolsDiscovered,Warning ValidationFailed,Warning ReconcileFailed.Note on Agent/ModelConfig: in current
mainthose objects reconcile through the KRT-based status collections ingo/core/v2/controller, not classic controller-runtimeReconcileinstallers, so they have no EventRecorder path to attach events to. The events gap is therefore implemented on the two remaining classic discovery controllers — the direct successors of the MCPServerTool/RemoteMCPServer roles named in the issue. Emission is a no-op when no recorder is wired (the default).3. Controller log → OTLP bridge (
go/core)telemetry.InitLoggerProviderbuilds an OTLP LoggerProvider viaautoexport(same resource attributes as traces) and sets it global.telemetry.ControllerZapOptsadditively tees the controller zap logger with anotelzapbridge core, preserving stdout.cmd/controller-v2/main.gobefore the controller logger is built.OTEL_LOGGING_ENABLED(already plumbed via the Helm chartotel.logging.enabled); when unset both functions are no-ops and logs are byte-identical.Validation
go build ./...,go veton all changed packages,gofmt/goimports clean.go testpasses foradk/pkg/a2a,adk/pkg/telemetry,adk/pkg/config,core/internal/telemetry, andcore/internal/controller/{mcpserver,remotemcpserver}(incl. the new event tests).pkg/sessionhas two pre-existing Windows-only TempDir-cleanup failures (SQLite handle held open during cleanup); unrelated to this change.Dependencies
Promotes
otlplog,otlpmetric(grpc/http),otel/log,otel/metric,otel/sdk/metricto direct requires at the same versions already in the graph, and addsgo.opentelemetry.io/contrib/bridges/otelzap v0.19.0. No version bumps.Refs: #2148