Coverage for app/backend/src/couchers/tracing.py: 62%
32 statements
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-21 09:29 +0000
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-21 09:29 +0000
1from collections.abc import Sequence
3from opentelemetry import trace
4from opentelemetry.context import Context
5from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
6from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer
7from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
8from opentelemetry.instrumentation.threading import ThreadingInstrumentor
9from opentelemetry.sdk.resources import Resource
10from opentelemetry.sdk.trace import TracerProvider
11from opentelemetry.sdk.trace.export import BatchSpanProcessor
12from opentelemetry.sdk.trace.sampling import ParentBased, Sampler, SamplingResult, TraceIdRatioBased
13from opentelemetry.trace import Link, SpanKind
14from opentelemetry.trace.span import TraceState
15from opentelemetry.util.types import Attributes
17from couchers.config import config
18from couchers.db import _get_base_engine
19from couchers.experimentation import get_global_float_value
22class FeatureFlagRatioSampler(Sampler):
23 """
24 Samples the fraction of traces given by the `trace_sample_ratio` flag (default 0). Wired as the
25 ParentBased root, so it's consulted only for root spans - one flag read per RPC, not per span.
26 """
28 def should_sample(
29 self,
30 parent_context: Context | None,
31 trace_id: int,
32 name: str,
33 kind: SpanKind | None = None,
34 attributes: Attributes = None,
35 links: Sequence[Link] | None = None,
36 trace_state: TraceState | None = None,
37 ) -> SamplingResult:
38 ratio = get_global_float_value("trace_sample_ratio", 0.0)
39 return TraceIdRatioBased(ratio).should_sample(
40 parent_context, trace_id, name, kind, attributes, links, trace_state
41 )
43 def get_description(self) -> str:
44 return "FeatureFlagRatioSampler{flag=trace_sample_ratio}"
47def setup_tracing() -> None:
48 if config.OPENTELEMETRY_ENDPOINT != "":
49 ThreadingInstrumentor().instrument()
51 grpc_server_instrumentor = GrpcInstrumentorServer() # type: ignore[no-untyped-call]
52 grpc_server_instrumentor.instrument()
53 SQLAlchemyInstrumentor().instrument(engine=_get_base_engine(), enable_commenter=True, commenter_options={})
55 tracer = TracerProvider(
56 resource=Resource(attributes={"service.name": "backend"}),
57 sampler=ParentBased(root=FeatureFlagRatioSampler()),
58 )
59 tracer.add_span_processor(
60 BatchSpanProcessor(OTLPSpanExporter(endpoint=config.OPENTELEMETRY_ENDPOINT, insecure=True))
61 )
63 trace.set_tracer_provider(tracer)