foley.obs.trace#

The OpenTelemetry MIRROR seam for foley’s observability (#11).

foley’s reproducible run-artifact (the RunManifest) is built by the recorder from its own clock + id-factory, **independent of any tracer** — so a bare pip install foley still emits a complete manifest with zero dependencies. This module is only the optional OpenTelemetry mirror: when the foley[obs] extra is installed, foley additionally emits vendor-neutral OTel GenAI spans (consumable by Langfuse / Datadog / Honeycomb / …); when it is not, a stdlib NoOpTracer makes every instrumentation call a free no-op.

opentelemetry is imported lazily inside OTelTracer only, never at module top level, so importing this module (and import foley) stays dol-only. foley never configures an SDK / exporter — that is the host application’s job (trace.set_tracer_provider(...)); until it does, even the OTel-backed tracer is a free ProxyTracer no-op, so instrumentation is safe and ~zero-cost by default.

Module Attributes

GENAI

The GenAI semantic-convention attribute keys foley emits.

Functions

get_tracer(*[, prefer_otel])

Return the effective Tracer (OTel-backed when available, else no-op).

Classes

NoOpSpan()

A zero-cost span: every method does nothing; trace_id is always None.

NoOpTracer()

The default Tracer — yields the shared _NOOP_SPAN, zero deps.

OTelTracer()

An OpenTelemetry-backed Tracer (lazy import; requires foley[obs]).

Span(*args, **kwargs)

The minimal mirror-span surface foley code calls (structural).

Tracer(*args, **kwargs)

Starts mirror spans; the DI seam (default no-op, OTel-backed when present).

foley.obs.trace.GENAI = {'data_source_id': 'gen_ai.data_source.id', 'error_type': 'error.type', 'finish_reasons': 'gen_ai.response.finish_reasons', 'input_tokens': 'gen_ai.usage.input_tokens', 'operation': 'gen_ai.operation.name', 'output_tokens': 'gen_ai.usage.output_tokens', 'provider': 'gen_ai.provider.name', 'request_model': 'gen_ai.request.model', 'response_model': 'gen_ai.response.model'}#

The GenAI semantic-convention attribute keys foley emits. HARDCODED as strings on purpose — the opentelemetry.semconv._incubating constants are Development- stability and shift across minor versions. This dict is the single place they are named.

class foley.obs.trace.NoOpSpan[source]#

Bases: object

A zero-cost span: every method does nothing; trace_id is always None.

class foley.obs.trace.NoOpTracer[source]#

Bases: object

The default Tracer — yields the shared _NOOP_SPAN, zero deps.

start_as_current_span(name, *, kind=None, attributes=None)[source]#

Yield the no-op span (context-manager protocol; nothing is recorded).

class foley.obs.trace.OTelTracer[source]#

Bases: object

An OpenTelemetry-backed Tracer (lazy import; requires foley[obs]).

start_as_current_span(name, *, kind=None, attributes=None)[source]#

Open a real OTel span, mapping kind to SpanKind and yielding a mirror.

class foley.obs.trace.Span(*args, **kwargs)[source]#

Bases: Protocol

The minimal mirror-span surface foley code calls (structural).

class foley.obs.trace.Tracer(*args, **kwargs)[source]#

Bases: Protocol

Starts mirror spans; the DI seam (default no-op, OTel-backed when present).

foley.obs.trace.get_tracer(*, prefer_otel=True)[source]#

Return the effective Tracer (OTel-backed when available, else no-op).

Parameters:

prefer_otel (bool) – When True (default) and opentelemetry is importable, return an OTelTracer (itself a free no-op until the host configures an SDK); any construction failure falls back to the no-op. False forces the stdlib NoOpTracer — the hermetic-test lever (this dev env may have otel).

Return type:

Tracer

Returns:

A Tracer (never raises).