Skip to main content
This page covers instrumenting a Python application with the OpenTelemetry SDK to send logs and traces to Bronto over OTLP/HTTP via a local OTel Collector. Both signals are co-equal: logs are bridged from Python’s standard logging module — no log statement changes needed — and traces are emitted via a tracer provider.
If you don’t have a Collector and want to export directly from your application to Bronto, see Direct export to Bronto at the bottom of this page.

Prerequisites

Install dependencies

Configure the log bridge

The OTel Python SDK ships a LoggingHandler that bridges Python’s standard logging module into OTel. Attach it to the root logger (or any specific logger) and all log records flow through the OTel pipeline.
Pass a specific logger name to logging.getLogger("my_app") if you only want to instrument part of your application.

Configure the OTLP exporter

Wire a BatchLogRecordProcessor and OTLPLogExporter into the LoggerProvider. By default the OTel Collector listens for OTLP/HTTP on port 4318 — no authentication is needed here since the Collector handles the connection to Bronto.
If your Collector runs on a different host or port, update the endpoint accordingly.

Set resource attributes

Resource attributes are attached to every log record exported from this process. Two attributes drive how Bronto organises incoming logs: Pass a Resource when constructing the LoggerProvider:

Complete example

The snippet below puts all the pieces together. Copy it into your application’s startup code and call it once before your first log statement.
configure_logging.py

Verify delivery

After running your application, check both signals in Bronto:
  • Logs: open the Search page and filter by the dataset name you set in service.name — your log records should appear within a few seconds.
  • Traces: open the Explore Traces page and filter by the same service.name — your spans should appear within a few seconds.
If no logs appear, check:
  • The OTel Collector is running and reachable at the configured endpoint.
  • The Collector’s pipeline includes a logs pipeline with an otlp receiver and the Bronto exporter — see Connect Open Telemetry to Bronto.
  • BatchLogRecordProcessor exports on a background thread — make sure your process does not exit before the first flush. For short-lived scripts, replace it with SimpleLogRecordProcessor to export synchronously.
Synchronous export for scripts

Traces

For Django, Flask, FastAPI, SQLAlchemy, requests, and other popular libraries, the opentelemetry-instrument CLI wrapper auto-instruments your app at startup with no code changes — install opentelemetry-instrumentation and opentelemetry-instrumentation-<framework> (e.g. opentelemetry-instrumentation-flask), then run your app via opentelemetry-instrument python app.py. See Python auto-instrumentation for setup and the full list of supported libraries.

Install tracing dependencies

No additional packages are needed — opentelemetry-sdk and opentelemetry-exporter-otlp-proto-http already include tracing support.

Configure the tracer provider

Create a TracerProvider using the same Resource you built for logging, then register it as the global tracer provider.
configure_tracing.py
Sharing the Resource ensures service.name and service.namespace are identical on both logs and traces.

Creating spans

Get a tracer from the global provider and wrap operations in spans:
Any log emitted inside an active span automatically receives the trace_id and span_id — no manual propagation needed.

Complete example

app.py

GenAI semantic conventions

If your application calls an LLM (OpenAI, Anthropic, Amazon Bedrock, etc.), OpenTelemetry defines a dedicated set of GenAI semantic conventionsgen_ai.* attributes for model, token usage, and prompt/response content. Python has the richest GenAI auto-instrumentation of any OTel SDK today.
This page was verified on July 17, 2026. GenAI libraries and semantic conventions are evolving rapidly, so package configuration and emitted attributes can change between releases. Keep your instrumentation current and verify the fields emitted by the version you deploy.

Auto-instrumentation

Install the instrumentation package for your provider alongside the SDK packages from Install dependencies:
Then instrument with the zero-code wrapper — no application code changes:
This patches the provider SDK client so every model call produces a span such as chat gpt-4o-mini carrying gen_ai.provider.name (the deprecated gen_ai.system on older instrumentation versions), gen_ai.request.model, gen_ai.usage.input_tokens / output_tokens, and gen_ai.response.finish_reasons, instead of a plain HTTP client span.
The Anthropic package installed by pip install opentelemetry-instrumentation-anthropic is maintained as part of OpenLLMetry, not OTel contrib. See OpenLLMetry for setup, schema guidance, and content-capture controls.
For LangChain applications, opentelemetry-instrumentation-langchain traces chain/runnable steps in addition to the underlying model call — see LangChain.

Experimental: capturing prompt and response content

The official Python instrumentations (openai-v2, botocore) control content capture with two environment variables, both off by default:
Where content lands depends on the mode. With the legacy true setting, content is emitted as log records (OTel log events such as gen_ai.user.message / gen_ai.choice) — it flows through the logs pipeline, correlated to the span by trace_id, and is not queryable on the span itself. With span_only (or span_and_event), content is written directly to span attributes (gen_ai.input.messages / gen_ai.output.messages), which Bronto surfaces as searchable trace fields — prefer this mode where your instrumentation supports it.Where it doesn’t, emit the content as a structured log record correlated by trace_id, using the log bridge configured above. See LLM Observability for the recommended attribute names, a worked logging example, and Bronto search queries.

Manual spans

Where no auto-instrumentation package exists for your provider, set the gen_ai.* attributes yourself on a span, following the same conventions:
See LLM Observability for the full recommended attribute set, including gen_ai.input.messages / gen_ai.output.messages, and how to search and aggregate GenAI fields in Bronto.

Direct export to Bronto

If you are not using an OTel Collector, export directly to Bronto by replacing the exporter endpoints and adding your API key:
See API Keys for how to create a key with ingestion permissions. No other changes to the rest of the setup are required.