Skip to content

Tracing

  • Start here: Tracing guide
  • Common recipes: @instrument to emit spans and enrich log records. Trace() component to install an OTel TracerProvider for the app's lifetime.

grelmicro.trace

Tracing.

Unified instrumentation. Creates OTel spans and enriches log records with structured context through a single decorator.

Trace

Trace(
    *,
    name: str = "default",
    config: TraceConfig | None = None,
    service_name: str | None = None,
    exporter: TraceExporterType | None = None,
    endpoint: str | None = None,
    headers: dict[str, str] | None = None,
    basic_auth: tuple[str, str] | None = None,
    processor: TraceProcessorType | None = None,
    sampler: TraceSamplerType | None = None,
    sample_ratio: float | None = None,
    resource_attributes: dict[str, str] | None = None,
    instrument: InstrumentDirective = True,
    shutdown_timeout: float | None = None,
    env_load: bool | None = None,
)

Trace component: installs an OTel TracerProvider for the app's lifetime.

Registered as micro.trace after Grelmicro.use(Trace(...)). On enter, builds a TracerProvider from the resolved config and installs it as the process-global provider. On exit, the provider is shut down and the previously-installed provider (if any) is restored.

OTel's set_tracer_provider refuses to override an already-installed provider, so Trace writes the process-global directly. This means a single process should not run two Grelmicro apps with Trace components concurrently: their lifecycles share one OTel global. Sequential apps (the common test scenario) work fine.

Example
from grelmicro import Grelmicro
from grelmicro.trace import Trace

micro = Grelmicro(uses=[Trace(service_name="payments-api")])

async with micro:
    ...

The OTLP exporters are lazy-imported when selected. Install the matching exporter package: opentelemetry-exporter-otlp-proto-http or opentelemetry-exporter-otlp-proto-grpc.

Read more in the Tracing docs.

Initialize the component (defer provider build until __aenter__).

PARAMETER DESCRIPTION
name

Registration name. Trace installs the process-global OTel tracer provider, so only one may be registered per app.

TYPE: str DEFAULT: 'default'

config

Pre-built configuration. When provided, individual kwargs must be None. The env path is bypassed.

TYPE: TraceConfig | None DEFAULT: None

service_name

Service name resource attribute.

TYPE: str | None DEFAULT: None

exporter

Span exporter.

TYPE: TraceExporterType | None DEFAULT: None

endpoint

Exporter endpoint.

TYPE: str | None DEFAULT: None

headers

Exporter headers.

TYPE: dict[str, str] | None DEFAULT: None

basic_auth

HTTP Basic auth credentials as a (username, password) pair. grelmicro builds the Authorization: Basic header and attaches it to the OTLP exporter directly, so it never goes through the fragile OTEL_EXPORTER_OTLP_HEADERS encoding. From the environment, set GREL_TRACE_BASIC_AUTH_USERNAME and GREL_TRACE_BASIC_AUTH_PASSWORD instead.

TYPE: tuple[str, str] | None DEFAULT: None

processor

Span processor.

TYPE: TraceProcessorType | None DEFAULT: None

sampler

Sampler.

TYPE: TraceSamplerType | None DEFAULT: None

sample_ratio

Sample ratio for traceidratio sampler.

TYPE: float | None DEFAULT: None

resource_attributes

Extra resource attributes.

TYPE: dict[str, str] | None DEFAULT: None

instrument

Auto-instrumentation selection for active providers and the FastAPI app, bound to this app's tracer provider. True (the default) instruments every active provider plus the FastAPI app. A missing opentelemetry-instrumentation-* package is a no-op, so default-on does nothing until the extras are installed.

  • False: instrument nothing (the @instrument decorator still works).
  • "redis" or ["redis", "fastapi"]: instrument only the named targets. An unknown name raises.
  • {"redis": False}: instrument every active target except the named ones.

TYPE: InstrumentDirective DEFAULT: True

shutdown_timeout

Maximum seconds to wait for the TracerProvider.shutdown() flush. On timeout the call is abandoned (the daemon shutdown thread keeps running but cannot block loop teardown), a warning is logged, and the rest of __aexit__ proceeds. Pending spans may be dropped.

TYPE: float | None DEFAULT: None

env_load

Whether to read GREL_TRACE_* environment variables. When None (default), follow GREL_ENV_LOAD.

TYPE: bool | None DEFAULT: None

kind class-attribute

kind: str = 'trace'

singleton class-attribute

singleton: bool = True

name property

name: str

Return the registration name.

instrument property

instrument: InstrumentDirective

Return the auto-instrumentation selection directive.

config property

config: TraceConfig

Return the resolved TraceConfig.

RAISES DESCRIPTION
RuntimeError

If accessed before the component has been entered.

provider property

provider: Any

Return the installed OTel TracerProvider.

RAISES DESCRIPTION
RuntimeError

If accessed before the component has been entered, or when the exporter auto-disables so no provider is installed.

active property

active: bool

Whether entering installs a TracerProvider for this app.

False when the exporter auto-disables: the default auto exporter with no endpoint configured. An auto-disabled Trace is a no-op, so it can be registered unconditionally in dev, test, and CI.

from_config classmethod

from_config(
    config: TraceConfig, *, name: str = "default"
) -> Self

Construct a Trace from a pre-built TraceConfig.

PARAMETER DESCRIPTION
config

The pre-built trace configuration.

Use this path when the configuration is assembled at startup from a settings tree (for example YAML, Vault, or a pydantic-settings aggregator). The environment path is bypassed and the config is used as-is.

TYPE: TraceConfig

name

Registration name. Defaults to 'default'.

TYPE: str DEFAULT: 'default'

owns_global_state

owns_global_state() -> bool

Whether entering patches the process-global tracer provider.

Consulted by the app's single-active-app guard. An auto-disabled Trace installs nothing, so overlapping apps may each carry one.

TraceConfig

Bases: BaseModel

Trace Config.

service_name class-attribute instance-attribute

service_name: str | None = None

Service name resource attribute. Falls back to OTEL_SERVICE_NAME when unset.

exporter class-attribute instance-attribute

exporter: TraceExporterType = AUTO

Span exporter. The default auto resolves to otlp-http when an endpoint is configured (the endpoint field, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, or OTEL_EXPORTER_OTLP_ENDPOINT) and to none otherwise, so an unconfigured Trace() exports nothing instead of falling back to localhost:4318.

endpoint class-attribute instance-attribute

endpoint: str | None = None

Exporter endpoint. Falls back to OTEL_EXPORTER_OTLP_ENDPOINT when unset.

headers class-attribute instance-attribute

headers: dict[str, str] = Field(default_factory=dict)

Exporter headers. Falls back to OTEL_EXPORTER_OTLP_HEADERS when empty.

basic_auth_username class-attribute instance-attribute

basic_auth_username: str | None = None

HTTP Basic auth username for the OTLP exporter. Set together with basic_auth_password to send an Authorization: Basic header, built and attached on the exporter directly so it bypasses the fragile OTEL_EXPORTER_OTLP_HEADERS encoding.

basic_auth_password class-attribute instance-attribute

basic_auth_password: str | None = None

HTTP Basic auth password for the OTLP exporter. Set together with basic_auth_username.

processor class-attribute instance-attribute

Span processor.

sampler class-attribute instance-attribute

Sampler.

sample_ratio class-attribute instance-attribute

sample_ratio: float = 1.0

Sample ratio for traceidratio sampler.

resource_attributes class-attribute instance-attribute

resource_attributes: dict[str, str] = Field(
    default_factory=dict
)

Extra resource attributes.

shutdown_timeout class-attribute instance-attribute

shutdown_timeout: PositiveFloat = 5.0

Maximum seconds to wait for the TracerProvider.shutdown() flush. A slow or broken exporter no longer hangs application shutdown past this deadline.

authorization_header property

authorization_header: str | None

Authorization: Basic value from the credentials, or None.

Encodes username:password as base64 per RFC 7617. Returns None when no Basic credentials are configured.

TraceError

Bases: GrelmicroError

Base trace error.

TraceExporterType

Bases: _CaseInsensitiveEnum

Span exporter selection.

AUTO class-attribute instance-attribute

AUTO = 'auto'

OTLP_HTTP class-attribute instance-attribute

OTLP_HTTP = 'otlp-http'

OTLP_GRPC class-attribute instance-attribute

OTLP_GRPC = 'otlp-grpc'

CONSOLE class-attribute instance-attribute

CONSOLE = 'console'

NONE class-attribute instance-attribute

NONE = 'none'

TraceProcessorType

Bases: _CaseInsensitiveEnum

Span processor selection.

BATCH class-attribute instance-attribute

BATCH = 'batch'

SIMPLE class-attribute instance-attribute

SIMPLE = 'simple'

TraceSamplerType

Bases: _CaseInsensitiveEnum

Sampler selection.

ALWAYS_ON class-attribute instance-attribute

ALWAYS_ON = 'always_on'

ALWAYS_OFF class-attribute instance-attribute

ALWAYS_OFF = 'always_off'

PARENTBASED_ALWAYS_ON class-attribute instance-attribute

PARENTBASED_ALWAYS_ON = 'parentbased_always_on'

TRACEIDRATIO class-attribute instance-attribute

TRACEIDRATIO = 'traceidratio'

TraceSettingsValidationError

TraceSettingsValidationError(error: ValidationError | str)

Bases: TraceError, SettingsValidationError

Trace Settings Validation Error.

add_context

add_context(**fields: object) -> None

Add fields to the current span's context.

Creates a new frame snapshot (safe for concurrent async tasks). Updates the active OTel span if tracing is configured. No-op if called outside a span.

Example::

@instrument
async def process(order_id: str):
    result = charge()
    add_context(payment_id=result.id, status=result.status)
    logger.info("payment done")  # includes payment_id, status

get_context

get_context() -> dict[str, Any]

Get merged context from all active spans (bottom to top).

instrument

instrument(func: Callable[P, R]) -> Callable[P, R]
instrument(
    *,
    name: str | None = None,
    skip: Set[str] | None = None,
    skip_all: bool = False,
) -> Callable[[Callable[P, R]], Callable[P, R]]
instrument(
    func: Callable[P, R] | None = None,
    *,
    name: str | None = None,
    skip: Set[str] | None = None,
    skip_all: bool = False,
) -> (
    Callable[P, R]
    | Callable[[Callable[P, R]], Callable[P, R]]
)

Instrument a function with span context and logging enrichment.

Creates an OTel span (if tracing configured) and pushes function arguments as context fields into log records. Like Rust's #[instrument].

When an exception propagates, the OTel span is marked as ERROR and the exception is recorded on the span.

PARAMETER DESCRIPTION
func

The function to instrument. Bound automatically when @instrument is used bare. None when called with arguments (@instrument(...)) so the inner decorator can wrap the target.

TYPE: Callable[P, R] | None DEFAULT: None

name

Override the span name. Defaults to the wrapped function's qualified name.

TYPE: str | None DEFAULT: None

skip

Argument names to exclude from the span attributes and log context, in addition to the built-in sensitive-name filter (password, token, secret, authorization, cookie, ... matched case-insensitively). Use this for arguments whose string form may carry sensitive data not covered by the default list (raw request bodies, custom auth headers).

TYPE: Set[str] | None DEFAULT: None

skip_all

If True, record no argument values at all. The span is still emitted and the function is still wrapped; only the per-argument attributes are dropped.

TYPE: bool DEFAULT: False

Note

Argument values are stringified (str()) when sent to OTel. Arguments named like common secrets (password, token, secret, authorization, cookie, ...) are filtered out by default. Pass extra names via skip for arguments whose string representation may contain sensitive data outside the default list.

PARAMETER DESCRIPTION
func

The function to instrument (set automatically for bare decorator).

TYPE: Callable[P, R] | None DEFAULT: None

name

Custom span name. Defaults to the function's qualified name.

TYPE: str | None DEFAULT: None

skip

Argument names to exclude from context (any set-like collection).

TYPE: Set[str] | None DEFAULT: None

skip_all

If True, do not record any arguments.

TYPE: bool DEFAULT: False

span

span(
    name: str, **fields: object
) -> Generator[None, None, None]

Create a span that enriches both OTel and logging context.

Use for mid-function instrumentation when @instrument is not enough. When an exception propagates, the OTel span is marked as ERROR.

Example::

@instrument
async def process_order(order_id: str):
    logger.info("started")  # has order_id

    with span("payment", provider="stripe"):
        logger.info("charging")  # has order_id + provider

    logger.info("done")  # back to order_id only
PARAMETER DESCRIPTION
name

Span name.

TYPE: str

**fields

Structured fields added to both OTel span and log context.

TYPE: object DEFAULT: {}