How do you instrument gRPC and HTTP services with OpenTelemetry?
Quick Answer
OpenTelemetry provides auto-instrumentation libraries for popular HTTP and gRPC frameworks that automatically create spans for incoming and outgoing requests, propagate trace context via headers, and record standard attributes like http.method, http.status_code, and rpc.method. You install framework-specific instrumentation packages and initialize them at application startup, with optional manual instrumentation for business logic spans.
Detailed Answer
Think of auto-instrumentation like installing a dashcam in your car. Once it is mounted, it automatically records every trip without you pressing any buttons. You still have the option to narrate important events by pressing a button (manual instrumentation), but the baseline recording of every start, stop, turn, and speed happens automatically. OpenTelemetry auto-instrumentation works the same way for HTTP and gRPC calls: install the library, and every request is automatically traced with standardized attributes.
For HTTP services, OpenTelemetry provides instrumentation libraries for virtually every popular framework. In Python, opentelemetry-instrumentation-flask instruments Flask applications, opentelemetry-instrumentation-fastapi handles FastAPI, and opentelemetry-instrumentation-django covers Django. In Java, the OpenTelemetry Java agent is a single JAR file that instruments dozens of frameworks automatically via bytecode manipulation, requiring zero code changes. In Go, instrumentation is provided through middleware for net/http, gin, echo, and other frameworks. When auto-instrumentation is active, every incoming HTTP request creates a server span with standardized semantic convention attributes: http.method (GET, POST), http.url or http.route, http.status_code, http.request_content_length, net.host.name, and net.peer.ip. Outgoing HTTP calls via libraries like requests in Python or HttpClient in Java automatically create client spans and inject the trace context (traceparent header) into the outgoing request.
For gRPC services, OpenTelemetry instruments both the client and server sides. The instrumentation registers interceptors on the gRPC channel (client) or server that create spans for each RPC call. Standard attributes include rpc.system (grpc), rpc.service (the protobuf service name like payments.PaymentService), rpc.method (the method name like ProcessPayment), rpc.grpc.status_code (OK, CANCELLED, DEADLINE_EXCEEDED), and net.peer.name. The trace context is propagated through gRPC metadata, which is functionally equivalent to HTTP headers. In the payments-api calling the user-auth-service via gRPC, the client interceptor creates a client span, injects the trace context into the gRPC metadata, and the server interceptor on user-auth-service extracts the context and creates a server span linked to the same trace.
Combining auto-instrumentation with manual instrumentation gives you the best of both worlds. Auto-instrumentation captures the infrastructure layer: every HTTP request, every gRPC call, every database query. Manual instrumentation captures business logic: processing a payment, validating inventory, applying a discount. In the checkout-service, auto-instrumentation automatically creates spans for the incoming POST /api/v1/checkout HTTP request and the outgoing gRPC call to payments-api. You then add manual spans inside the request handler for validate-cart, calculate-tax, and apply-discount, which appear as child spans under the auto-instrumented HTTP span. This gives you a complete picture: the HTTP layer shows you network latency, and the business logic spans show you where time is spent within the service.
In production, there are several important considerations. First, auto-instrumentation can generate high span volume if every health check and readiness probe creates a span. Use the Collector filter processor or SDK-level span filtering to suppress spans for paths like /healthz and /readyz. Second, the http.url attribute can contain sensitive query parameters. Use http.route (the URL template like /users/:id) instead of the full URL with parameters. Most instrumentation libraries support URL sanitization configuration. Third, gRPC streaming RPCs create spans that can remain open for minutes or hours. Configure appropriate timeouts and understand that long-lived spans consume memory in the SDK until they are exported. Fourth, the order of instrumentation initialization matters. The tracing provider must be configured before instrumentation libraries are applied, or spans will be silently dropped.