faust.contrib.opentelemetry¶
OpenTelemetry tracing for Faust, and for a co-hosted ASGI application.
Why this exists¶
https://pypi.org/project/opentelemetry-instrumentation-aiokafka/ already wraps
AIOKafkaProducer.send and AIOKafkaConsumer.getmany, which is exactly
what Faust’s aiokafka driver calls. So with that package installed you already
get most of a distributed trace for free:
FastAPI server span
-> aiokafka "{topic} send" (PRODUCER, injects ``traceparent``)
-> [Kafka]
-> aiokafka "{topic} receive" (CONSUMER, extracts ``traceparent``)
-> ???
The last hop is the one nobody outside Faust can supply. Faust’s consumer runs
in its own thread (ConsumerThread), and
contextvars never cross threads – so the receive span is opened
and closed inside getmany, on a thread the agent never runs on. Without
help you get an orphaned receive span and an unparented agent, which reads
worse in a trace viewer than no instrumentation at all.
OpenTelemetrySensor closes that gap. It extracts the trace context
from the Kafka message headers and opens a {topic} process span that stays
current for exactly as long as the stream is processing the event, so anything
the agent does – an HTTP call, a database query, another topic.send() –
nests underneath it.
Usage¶
from faust.contrib.opentelemetry import setup_opentelemetry
app = faust.App("myapp", broker="kafka://localhost:9092")
setup_opentelemetry(app)
Configure an SDK the usual way (opentelemetry-sdk plus an exporter, or the
opentelemetry-instrument CLI). Until you do, the OpenTelemetry API is a
no-op and this module costs effectively nothing.
Install with pip install faust-streaming[opentelemetry].
Notes
This module depends only on
opentelemetry-api. A library must never configure the SDK, so nothing here callsset_tracer_provider().Trace context is read from message headers, never written. On the produce side
opentelemetry-instrumentation-aiokafkaalready injects, and its setter appends unconditionally – a second injector would put twotraceparentheaders on the wire.Faust’s older https://pypi.org/project/opentracing/ support (
faust.sensors.distributed_tracing.TracingSensor) does inject into Kafka headers. Do not run both;setup_opentelemetry()warns if it sees one already registered.
- class faust.contrib.opentelemetry.OpenTelemetrySensor(*, tracer: Optional[Any] = None, **kwargs: Any)[source]¶
Open an OpenTelemetry span around each event a stream processes.
The span is parented to the producer’s span via the
traceparentheader on the Kafka message, and stays current for the duration of processing.- on_stream_event_in(tp: TP, offset: int, stream: StreamT, event: EventT) Optional[Dict][source]¶
Start a
processspan and make it current.- Return type:
_UnionGenericAlias[_SpecialGenericAlias,None]
- on_stream_event_out(tp: TP, offset: int, stream: StreamT, event: EventT, state: Optional[Dict[Any, Any]] = None) None[source]¶
Detach the context and end the span.
- Return type:
None
- logger: logging.Logger = <Logger faust.contrib.opentelemetry (WARNING)>¶
- faust.contrib.opentelemetry.instrument_asgi_app(asgi_app: Any, *, tracer_provider: Any = None, force: bool = False) bool[source]¶
Attach OpenTelemetry instrumentation to a FastAPI/Starlette app.
Returns
Trueif instrumentation was attached.Does nothing – and returns
False– when the instrumentation package is missing, when no SDK has been configured (unlessforce), or when the application is already instrumented (for example because it was started underopentelemetry-instrument).- Return type:
- faust.contrib.opentelemetry.opentelemetry_available() bool[source]¶
Return
Trueif the OpenTelemetry API is importable.- Return type:
- faust.contrib.opentelemetry.sdk_is_configured() bool[source]¶
Return
Trueif a realTracerProvideris installed.The OpenTelemetry API ships a proxy/no-op provider until an application calls
set_tracer_provider(). Treating that as “tracing is off” is what lets this integration be enabled by default without doing anything behind an operator’s back.- Return type:
- faust.contrib.opentelemetry.setup_opentelemetry(app: AppT, *, tracer: Optional[Any] = None) Optional[OpenTelemetrySensor][source]¶
Register the OpenTelemetry sensor on
app.Returns the sensor, or
Noneif OpenTelemetry is not installed.- Return type:
_UnionGenericAlias[OpenTelemetrySensor,None]