This example demonstrates production-grade observability with automatic metrics collection and distributed tracing using explicit provider configuration.
- ✅ How to configure observability using context-based providers
- ✅ How OpenTelemetry integrates with AgentMesh
- ✅ What metrics and traces are automatically collected
- ✅ How distributed tracing works across node execution
- ✅ How to access providers in node RunFuncs for custom instrumentation
cd examples/observability
go run main.go// For development/testing - zero overhead
logger := logging.NoopLogger{}
metricsProvider := metrics.Noop()
traceProvider := trace.Noop()
// Attach providers to context
ctx = logging.WithLogger(ctx, logger)
ctx = trace.WithProvider(ctx, traceProvider)
ctx = metrics.WithProvider(ctx, metricsProvider)
result, _ := graph.Last(compiled.Run(ctx, messages))import (
"log/slog"
"github.com/hupe1980/agentmesh/pkg/logging"
"github.com/hupe1980/agentmesh/pkg/metrics/opentelemetry"
"github.com/hupe1980/agentmesh/pkg/trace/opentelemetry"
)
// Configure observability providers
logger := logging.NewSlogAdapter(slog.New(slog.NewJSONHandler(os.Stdout, nil)))
traceProvider := opentelemetry.NewProvider(
opentelemetry.WithEndpoint("http://jaeger:4318"),
opentelemetry.WithServiceName("my-service"),
)
metricsProvider := opentelemetry.NewMetricsProvider(
opentelemetry.WithEndpoint("http://prometheus:9090"),
)
// Attach providers to context
ctx = logging.WithLogger(ctx, logger)
ctx = trace.WithProvider(ctx, traceProvider)
ctx = metrics.WithProvider(ctx, metricsProvider)
result, _ := graph.Last(compiled.Run(ctx, messages))When you configure observability providers, the framework automatically:
- Graph execution span: Covers entire Run() call
- Node execution spans: One span per node execution
- Checkpoint spans: For checkpoint save/restore operations
-
Node execution metrics:
agentgraph.node.executions- Counter for node executionsagentgraph.node.latency_ms- Histogram of node execution timeagentgraph.node.errors- Counter for node errors
-
Graph execution metrics:
agentgraph.graph.executions- Counter for graph executionsagentgraph.superstep.latency_ms- Histogram of superstep duration
All metrics include relevant labels like node.name, superstep, error.type.
All providers are automatically attached to context for node RunFuncs:
func(ctx context.Context, s state.Writer) (*graph.NodeResult, error) {
log := logging.FromContext(ctx)
tp := trace.FromContext(ctx)
mp := metrics.FromContext(ctx)
// Use them for custom instrumentation
log.Info("Processing", "node", "my_node")
tracer := tp.Tracer("my-service")
ctx, span := tracer.Start(ctx, "operation")
defer span.End(nil)
counter := mp.Counter("operations.count")
counter.Add(ctx, 1)
}- ✅ Automatic instrumentation - Zero code changes needed
- ✅ Explicit configuration - Clear intent, type-safe
- ✅ Production ready - OpenTelemetry compatible
- ✅ Zero overhead - Noop providers when not configured
- ✅ Custom instrumentation - Access providers in nodes
custom_observability- Custom provider usagestreaming- Real-time event streamingcheckpointing- State persistence with tracing