# kaya-otel OpenTelemetry tracing and metrics for the Kaya web framework. Provides `OTelMixin`, a `KayaMixin` that instruments HTTP requests and WebSocket connections with OpenTelemetry spans and exports HTTP server metrics, shipping everything to an OTLP/HTTP collector. ## Usage ```python from kaya.core import KayaApp, HttpContext from kaya.otel import OTelMixin app = KayaApp(mixins=[ OTelMixin( service_name='my-service', endpoint='http://localhost:4318', ) ]) @app.GET('/') async def home(ctx: HttpContext): await ctx.send_str(200, 'Hello World!') ``` ## Parameters - `service_name`: value of the `service.name` resource attribute. - `endpoint`: base URL of an OTLP/HTTP collector; the signal paths `/v1/traces` and `/v1/metrics` are appended. When `None`, the exporters use their own defaults, including the standard `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable. - `headers`: extra HTTP headers sent to the collector (e.g. authentication). - `metric_export_interval_millis`: metric export interval (default `60000`). - `tracer_provider` / `meter_provider`: inject custom providers (e.g. with in-memory exporters for tests) instead of the OTLP defaults. The mixin only shuts down providers it created itself. - `resource_attributes`: extra resource attributes merged with `service.name` when the mixin creates the providers. - `excluded_paths` / `excluded_path_regexes`: skip tracing and metrics for matching paths (useful for health checks and metrics endpoints). - `capture_request_headers` / `capture_response_headers`: opt-in HTTP header capture as `http.request.header.` / `http.response.header.` span attributes. Header names are normalized to lowercase with `-` replaced by `_`; values are captured as string lists. - `sanitize_headers`: headers captured as `REDACTED` (default: `authorization`, `proxy-authorization`, `cookie`, `set-cookie`). - `server_request_hook` / `server_response_hook` / `websocket_connect_hook` / `websocket_close_hook`: optional synchronous callbacks invoked with the span and the Kaya context/websocket at the corresponding lifecycle point. Hook exceptions are logged and do not fail the request. - `metrics_include_raw_path`: when `True`, metrics use raw `url.path` attributes (legacy, potentially high cardinality). The default `False` keeps metrics low-cardinality by using `http.route` when Kaya can resolve a route template. - `websocket_error_close_codes`: close codes that mark a websocket span as failed. Defaults to protocol/application error codes such as `1002`, `1003` and `1007`-`1011`. ## Behavior - Every HTTP request gets a `SERVER` span named ` ` with the usual HTTP semantic attributes (`http.request.method`, `url.path`, `client.address`, `server.address`, ...). When Kaya resolves a route template, the span name is updated to ` ` and `http.route` is set. The response status code is recorded as `http.response.status_code` when the handler sends the response; 5xx statuses mark the span as failed. Exceptions escaping the handler are recorded on the span and also mark it as failed. - Every WebSocket connection gets one span for its whole lifetime. The close code is recorded as `kaya.websocket.close_code`; exceptions and configured error close codes mark the span as failed. - W3C `traceparent`/`tracestate` headers on incoming requests are honored, so traces propagate from upstream services. - Metrics: - `http.server.request.duration` (histogram, seconds), with `http.request.method`, `http.route` when known and `http.response.status_code` attributes. - `http.server.active_requests` (up-down counter), with `http.request.method` attributes. `OTelMixin` is a `KayaMixin`, so the app stays a `KayaApp` and both ASGI and RSGI keep working.