diff --git a/example/otel-collector/README.md b/example/otel-collector/README.md index f7013acb5cf3..dcb003bd679a 100644 --- a/example/otel-collector/README.md +++ b/example/otel-collector/README.md @@ -52,7 +52,7 @@ web-browser to view the generated traces. The Prometheus UI is available at [http://localhost:9090](http://localhost:9090). Navigate there in your favorite -web-browser to view the generated metrics. +web-browser to view the generated metrics, for instance, `testapp_run_total`. # Shutting down diff --git a/example/otel-collector/go.mod b/example/otel-collector/go.mod index 9b096a7f13c6..d644c8392c70 100644 --- a/example/otel-collector/go.mod +++ b/example/otel-collector/go.mod @@ -9,8 +9,10 @@ replace ( require ( go.opentelemetry.io/otel v1.26.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.26.0 go.opentelemetry.io/otel/sdk v1.26.0 + go.opentelemetry.io/otel/sdk/metric v1.26.0 go.opentelemetry.io/otel/trace v1.26.0 google.golang.org/grpc v1.63.2 ) diff --git a/example/otel-collector/go.sum b/example/otel-collector/go.sum index 660b6c348991..edb23ab4eaac 100644 --- a/example/otel-collector/go.sum +++ b/example/otel-collector/go.sum @@ -15,6 +15,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0 h1:+hm+I+KigBy3M24/h1p/NHkUx/evbLH0PNcjpMyCHc4= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.26.0/go.mod h1:NjC8142mLvvNT6biDpaMjyz78kyEHIwAJlSX0N9P5KI= +go.opentelemetry.io/otel/sdk/metric v1.26.0 h1:cWSks5tfriHPdWFnl+qpX3P681aAYqlZHcAyHw5aU9Y= +go.opentelemetry.io/otel/sdk/metric v1.26.0/go.mod h1:ClMFFknnThJCksebJwz7KIyEDHO+nTB6gK8obLy8RyE= go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= diff --git a/example/otel-collector/main.go b/example/otel-collector/main.go index fa81633dc747..00fa3c09b42f 100644 --- a/example/otel-collector/main.go +++ b/example/otel-collector/main.go @@ -9,6 +9,7 @@ package main import ( "context" "fmt" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "log" "os" "os/signal" @@ -20,28 +21,20 @@ import ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/propagation" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.24.0" "go.opentelemetry.io/otel/trace" ) -// Initializes an OTLP exporter, and configures the corresponding trace and -// metric providers. -func initProvider() (func(context.Context) error, error) { - ctx := context.Background() - - res, err := resource.New(ctx, - resource.WithAttributes( - // the service name used to display traces in backends - semconv.ServiceName("test-service"), - ), - ) - if err != nil { - return nil, fmt.Errorf("failed to create resource: %w", err) - } +var serviceName = semconv.ServiceNameKey.String("test-service") +// Initialize a gRPC connection to be used by both the tracer and meter +// providers. +func initConn() (*grpc.ClientConn, error) { // It connects the OpenTelemetry Collector through local gRPC connection. // You may replace `localhost:4317` with your endpoint. conn, err := grpc.NewClient("localhost:4317", @@ -52,6 +45,21 @@ func initProvider() (func(context.Context) error, error) { return nil, fmt.Errorf("failed to create gRPC connection to collector: %w", err) } + return conn, err +} + +// Initializes an OTLP exporter, and configures the corresponding trace provider. +func initTracerProvider(ctx context.Context, conn *grpc.ClientConn) (func(context.Context) error, error) { + res, err := resource.New(ctx, + resource.WithAttributes( + // The service name used to display traces in backends + serviceName, + ), + ) + if err != nil { + return nil, fmt.Errorf("failed to create resource: %w", err) + } + // Set up a trace exporter traceExporter, err := otlptracegrpc.New(context.Background(), otlptracegrpc.WithGRPCConn(conn)) if err != nil { @@ -68,30 +76,72 @@ func initProvider() (func(context.Context) error, error) { ) otel.SetTracerProvider(tracerProvider) - // set global propagator to tracecontext (the default is no-op). + // Set global propagator to tracecontext (the default is no-op). otel.SetTextMapPropagator(propagation.TraceContext{}) // Shutdown will flush any remaining spans and shut down the exporter. return tracerProvider.Shutdown, nil } +// Initializes an OTLP exporter, and configures the corresponding meter provider. +func initMeterProvider(ctx context.Context, conn *grpc.ClientConn) (func(context.Context) error, error) { + res, err := resource.New(ctx, + resource.WithAttributes( + // The service name used to display traces in backends + serviceName, + ), + ) + if err != nil { + return nil, fmt.Errorf("failed to create resource: %w", err) + } + + metricExporter, err := otlpmetricgrpc.New(ctx, otlpmetricgrpc.WithGRPCConn(conn)) + if err != nil { + return nil, fmt.Errorf("failed to create metrics exporter: %w", err) + } + + meterProvider := sdkmetric.NewMeterProvider( + sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExporter)), + sdkmetric.WithResource(res), + ) + otel.SetMeterProvider(meterProvider) + + return meterProvider.Shutdown, nil +} + func main() { log.Printf("Waiting for connection...") ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() - shutdown, err := initProvider() + conn, err := initConn() + if err != nil { + log.Fatal(err) + } + + shutdownTracerProvider, err := initTracerProvider(ctx, conn) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := shutdownTracerProvider(ctx); err != nil { + log.Fatalf("failed to shutdown TracerProvider: %s", err) + } + }() + + shutdownMeterProvider, err := initMeterProvider(ctx, conn) if err != nil { log.Fatal(err) } defer func() { - if err := shutdown(ctx); err != nil { - log.Fatal("failed to shutdown TracerProvider: %w", err) + if err := shutdownMeterProvider(ctx); err != nil { + log.Fatalf("failed to shutdown MeterProvider: %s", err) } }() tracer := otel.Tracer("test-tracer") + meter := otel.Meter("test-meter") // Attributes represent additional key-value descriptors that can be bound // to a metric observer or recorder. @@ -101,7 +151,12 @@ func main() { attribute.String("attrC", "vanilla"), } - // work begins + runCount, err := meter.Int64Counter("run", metric.WithDescription("The number of times the iteration ran")) + if err != nil { + log.Fatal(err) + } + + // Work begins ctx, span := tracer.Start( ctx, "CollectorExporter-Example", @@ -109,6 +164,7 @@ func main() { defer span.End() for i := 0; i < 10; i++ { _, iSpan := tracer.Start(ctx, fmt.Sprintf("Sample-%d", i)) + runCount.Add(ctx, 1, metric.WithAttributes(commonAttrs...)) log.Printf("Doing really hard work (%d / 10)\n", i+1) <-time.After(time.Second)