> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Using Python Stdlib

> Demonstrates emitting OpenTelemetry logs in Python by comparing manual LogRecord creation with forwarding standard library logging into OpenTelemetry using a LoggingHandler.

In this lesson we compare two approaches to emitting logs with OpenTelemetry in Python:

* Verbose: manually creating and emitting `LogRecord` objects via an OpenTelemetry logger.
* Concise: using the Python standard library `logging` module and forwarding those records into OpenTelemetry.

We first show the verbose approach (explicit, but repetitive), then the standard-library approach (concise), and finally how to wire the stdlib logger into OpenTelemetry so your existing `logging.info(...)` calls produce OpenTelemetry log records automatically.

## At-a-glance comparison

| Approach | Pros | Cons | When to use |
| - | - | - | - |
| Manual `LogRecord` (OpenTelemetry SDK) | Full control over every field; explicit structure | Verbose — must set timestamp, severity, attributes manually | Low-level integrations, custom pre-processing |
| Python `logging` + forwarder | Concise and familiar API; auto-populates severity, timestamps, code attributes | Slight indirection; requires handler configuration | Most apps — minimal changes to existing codebases |

## 1) Verbose: emitting OpenTelemetry `LogRecord` directly

This approach constructs `LogRecord` objects and emits them through an OpenTelemetry `Logger`. It's explicit, but repetitive: every log must include timestamp, severity, body, and other fields.

```python theme={null}
import time
import logging
from opentelemetry.sdk._logs import LoggerProvider, LogRecord
from opentelemetry._logs import set_logger_provider, get_logger
from opentelemetry.sdk._logs.export import ConsoleLogExporter, BatchLogRecordProcessor
from opentelemetry._logs.severity import SeverityNumber

# OpenTelemetry setup
logger_provider = LoggerProvider()
exporter = ConsoleLogExporter()
processor = BatchLogRecordProcessor(exporter=exporter)
logger_provider.add_log_record_processor(processor)
set_logger_provider(logger_provider=logger_provider)

logger = get_logger("flight-booking", "0.1.2")

def book_flight():
    # Verbose: construct and emit a LogRecord manually
    logger.emit(
        LogRecord(
            body="Starting the booking flight process",
            timestamp=time.time_ns(),
            severity_text="INFO",
            severity_number=SeverityNumber.INFO,
        )
    )
    search_flights()
    reserve_flight()

def search_flights():
    pass

def reserve_flight():
    pass
```

This is useful when you need precise control over the OpenTelemetry `LogRecord` payload, but it quickly becomes cumbersome for everyday application logging.

## 2) Simpler: Python standard library `logging`

The Python standard logging module is concise and widely used. By default it writes human-readable text to the console (or to files/handlers you configure), but those records are not OpenTelemetry `LogRecord`s until you forward them.

```python theme={null}
import logging

# Configure the stdlib logger to accept all levels
logging.basicConfig(level=logging.NOTSET)

def book_flight():
    logging.info("starting booking process")
    search_flights()
    reserve_flight()

def search_flights():
    logging.info("Searching for flights")

def reserve_flight():
    logging.warning("Reserving flight")
```

Running the script produces the typical stdlib output:

```text theme={null}
Documents/courses/logs-demo via 🐍 v3.11.13 (.venv) on ☁ (us-east-1)
> python main.py
INFO:root:starting booking process
```

This is concise and convenient for everyday development, but those messages are not structured OpenTelemetry logs unless forwarded.

## 3) Forward stdlib `logging` to OpenTelemetry

You can wire the Python stdlib logger into OpenTelemetry using a `LoggingHandler` provided by the OpenTelemetry SDK. The handler converts `logging.LogRecord` instances into OpenTelemetry `LogRecord`s and forwards them to the configured `LoggerProvider`. With this in place, existing `logging.info(...)` calls generate structured OpenTelemetry logs automatically.

Example: forward stdlib logs to OpenTelemetry and export to the console as JSON.

```python theme={null}
import time
import logging
from opentelemetry.sdk._logs import LoggerProvider, LogRecord, LoggingHandler
from opentelemetry._logs import set_logger_provider, get_logger
from opentelemetry.sdk._logs.export import ConsoleLogExporter, BatchLogRecordProcessor
from opentelemetry._logs.severity import SeverityNumber

# OpenTelemetry provider and exporter setup
logger_provider = LoggerProvider()
exporter = ConsoleLogExporter()
processor = BatchLogRecordProcessor(exporter=exporter)
logger_provider.add_log_record_processor(processor)
set_logger_provider(logger_provider=logger_provider)

# Create a LoggingHandler that forwards stdlib logs to OpenTelemetry
handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)

# Configure stdlib logging to use that handler
logging.basicConfig(handlers=[handler], level=logging.NOTSET)

# Use the standard library logger throughout your app
def book_flight():
    logging.info("starting booking process")
    search_flights()
    reserve_flight()

def search_flights():
    logging.info("Searching for flights")

def reserve_flight():
    logging.warning("Reserving flight")
```

Notes:

* If you still want the original stdlib text output on the console in addition to OpenTelemetry JSON output, attach a standard `logging.StreamHandler()` alongside the `LoggingHandler`.
* The `LoggingHandler` will populate fields such as severity text/number, timestamps, and code attributes (file path, function name, line number) automatically.

Exporter output (ConsoleLogExporter) — formatted for readability:

```json theme={null}
{
    "body": "INFO:root:starting booking process",
    "severity_number": 9,
    "severity_text": "INFO",
    "attributes": {
        "code.file.path": "/Users/sanjeev/Documents/courses/logs-demo/main.py",
        "code.function.name": "book_flight",
        "code.line.number": 25
    },
    "dropped_attributes": 0,
    "timestamp": "2025-09-18T23:22:33.738287Z",
    "observed_timestamp": "2025-09-18T23:22:33.738303Z",
    "trace_id": "0x00000000000000000000000000000000",
    "span_id": "0x0000000000000000",
    "trace_flags": 0,
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.37.0",
            "service.name": "unknown_service"
        },
        "schema_url": ""
    },
    "event_name": ""
}
```

<Callout icon="lightbulb" color="#1CB2FE">
  Forwarding the Python stdlib logger to OpenTelemetry lets existing codebases emit structured OpenTelemetry logs with minimal changes — configure the handler once and continue using `logging` everywhere.
</Callout>

## Links and references

* OpenTelemetry: [https://opentelemetry.io/](https://opentelemetry.io/)
* Python logging documentation: [https://docs.python.org/3/library/logging.html](https://docs.python.org/3/library/logging.html)
* OpenTelemetry Python SDK: [https://github.com/open-telemetry/opentelemetry-python](https://github.com/open-telemetry/opentelemetry-python)

If you want a quick checklist for adopting stdlib-forwarding:

| Step | Action |
| - | - |
| 1 | Install OpenTelemetry Python SDK and exporter packages. |
| 2 | Create and configure a `LoggerProvider` and exporter (e.g., `ConsoleLogExporter`). |
| 3 | Create `LoggingHandler` with the `logger_provider` and attach it to `logging`. |
| 4 | Optionally attach `StreamHandler` if you also want human-readable console logs. |
| 5 | Run your app — `logging` calls will now produce OpenTelemetry `LogRecord`s. |

This setup gives you the familiarity of the Python `logging` API with the structured, observable benefits of OpenTelemetry logging.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/prep-course-opentelemetry-certified-associate-certification-otca/module/021c9c6f-284e-4d7e-8cda-b202c1e3bf2c/lesson/dfb1b0f5-9314-4205-aa90-605c765e537b" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.