Back to Blog
Tutorial July 21, 2026 ⏱ 6 min read

A Beginner's Guide to Instrumenting Python Apps with OpenTelemetry

If you can write a logging.getLogger() call, you already know most of what you need. Here's the rest, step by step.

X
XplurData Team
Platform Engineering

What You Need Before Starting

You need a Python service that already uses the standard logging module, and an OTLP endpoint to send telemetry to — either a running OpenTelemetry Collector, or a backend that accepts OTLP directly. If you don't have a Collector running yet, see our Collector configuration guide first.

Step 1: Install the SDK

bash
pip install opentelemetry-sdk opentelemetry-exporter-otlp

This gives you the core SDK plus the OTLP exporter package, which handles serializing telemetry into the OTLP protocol and sending it over gRPC or HTTP.

Step 2: Configure the Logger Provider

logging_setup.py
import logging
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter

provider = LoggerProvider()
provider.add_log_record_processor(
    BatchLogRecordProcessor(
        OTLPLogExporter(endpoint="http://<YOUR_HOST>:4318/v1/logs")
    )
)
set_logger_provider(provider)

logger = logging.getLogger("my-service")
logger.addHandler(LoggingHandler(logger_provider=provider))
logger.setLevel(logging.INFO)

The BatchLogRecordProcessor batches log records before sending, matching the same batching principle covered in the Collector configuration guide — sending one log at a time creates unnecessary network overhead.

Step 3: Log Normally

app.py
logger.info("Order processed", extra={"order_id": "ord_1234", "amount": 42.50})
logger.error("Payment failed", extra={"order_id": "ord_1234", "reason": "card_declined"})

Once the handler is attached, ordinary logger.info() and logger.error() calls are automatically exported as OTLP log records — no changes needed to how the rest of your application logs. The extra dictionary becomes structured attributes rather than being flattened into a plain-text message, which matters for searchability later.

Verifying It's Working

Send a test request that triggers a log line, then check your observability platform's log explorer, filtered to service_name="my-service". If nothing arrives, the most common culprits are an incorrect endpoint port (4318 for HTTP, 4317 for gRPC), a missing trailing /v1/logs path on the HTTP exporter, or a firewall blocking the connection between your app and the Collector.

Where to Go From Here

Once logs are flowing, the natural next step is adding trace context so your logs and traces correlate — covered conceptually in Logs vs Metrics vs Traces. If your app runs in Kubernetes rather than as a standalone process, the deployment pattern changes slightly; see Kubernetes Observability with OTel.

Conclusion

Instrumenting a Python app with OpenTelemetry logging is a small, additive change — you keep your existing logging calls and add an exporter underneath them. The bigger payoff comes once every service in your stack does the same thing consistently, giving you a uniform telemetry format across your whole system rather than a patchwork of custom log formats.

Send Python Logs to XplurData

Point the OTLP exporter at your XplurData Collector endpoint — no additional configuration needed.

Deploy XplurData
XD

XplurData Engineering Team

Building the next generation open-source observability platform.

The XplurData Engineering Team focuses on scalable observability, OpenTelemetry, Apache Doris, distributed systems and high-performance analytics.