> ## 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 Your First Log

> Guide showing how to replace print statements in a flight booking demo with OpenTelemetry structured logs, configuring LoggerProvider, Console exporter, Batch processor, and emitting LogRecord entries

In this lesson you'll convert simple print statements in a small flight-booking demo into structured OpenTelemetry logs. We'll configure a LoggerProvider, attach a Console exporter and a Batch processor, then emit LogRecord entries instead of using `print()`.

This guide contains:

* The original minimal application with `print()` statements
* Installation instructions
* A consolidated runnable example using OpenTelemetry logging
* Notes on processors, severity values, and example output
* Links and resources to extend this setup

## Initial application (before OpenTelemetry)

This is the minimal starting point that uses `print()` for diagnostic output:

```python theme={null}
# main.py (initial version)
def book_flight():
    print("starting the booking flight process")
    search_flights()
    reserve_flight()

def search_flights():
    print("searching for flights.....")

def reserve_flight():
    print("Reserving flight")

if __name__ == "__main__":
    book_flight()
```

Goal: replace these `print()` calls with OpenTelemetry LogRecord emissions for richer, structured logging.

## Installation

Install the OpenTelemetry API and SDK packages for Python:

```bash theme={null}
pip install opentelemetry-api
pip install opentelemetry-sdk
```

You can also add exporters (OTLP) later if you want to send logs to a collector.

## OpenTelemetry logging — components overview

Below are the main components you'll configure when using OpenTelemetry logging:

| Component | Purpose | Example / Note |
| -: | - | - |
| LoggerProvider | Factory and lifecycle manager for loggers | `LoggerProvider()` |
| LogRecord exporter | Sends LogRecord objects somewhere (Console, OTLP, etc.) | `ConsoleLogExporter()` |
| LogRecord processor | Buffers and dispatches records to exporters | `BatchLogRecordProcessor(exporter)` |
| Global provider registration | Lets `get_logger()` return configured loggers | `set_logger_provider(provider)` |
| Logger | Emitting API; create with `get_logger(name, version)` | `logger.emit(LogRecord(...))` |

## Important note about module paths

<Callout icon="lightbulb" color="#1CB2FE">
  Some OpenTelemetry logging modules live under names that begin with an underscore (for example, `opentelemetry.sdk._logs`). This signals an experimental or not-yet-stable API surface. If you see import errors after upgrading packages, check the library release notes or the [OpenTelemetry Python releases](https://github.com/open-telemetry/opentelemetry-python/releases) for updated module paths.
</Callout>

## Consolidated runnable example

The example below replaces the `print()` calls with `LogRecord` emissions and configures a Console exporter and a `BatchLogRecordProcessor`. Save as `main.py` and run `python main.py` to see JSON-like LogRecord entries printed to the terminal.

```python theme={null}
# main.py (OpenTelemetry logging version)
import time
from opentelemetry.sdk._logs import LoggerProvider, LogRecord
from opentelemetry._logs import set_logger_provider, get_logger
from opentelemetry._logs.severity import SeverityNumber
from opentelemetry.sdk._logs.export import ConsoleLogExporter, BatchLogRecordProcessor

# Configure provider, exporter and processor
logger_provider = LoggerProvider()
exporter = ConsoleLogExporter()
processor = BatchLogRecordProcessor(exporter=exporter)
logger_provider.add_log_record_processor(processor)

# Set the global logger provider so get_logger() uses it
set_logger_provider(logger_provider)

# Create a logger for our application
logger = get_logger("flight-booking", "0.1.2")

def book_flight():
    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():
    logger.emit(
        LogRecord(
            body="Searching for flights...",
            timestamp=time.time_ns(),
            severity_text="INFO",
            severity_number=SeverityNumber.INFO,
        )
    )

def reserve_flight():
    logger.emit(
        LogRecord(
            body="Reserving flight",
            timestamp=time.time_ns(),
            severity_text="INFO",
            severity_number=SeverityNumber.INFO,
        )
    )

if __name__ == "__main__":
    book_flight()
```

Run the script:

```bash theme={null}
python main.py
```

## Notes on BatchLogRecordProcessor

* The `BatchLogRecordProcessor` buffers LogRecord objects and sends them to the exporter in batches on a schedule or when the queue fills. This improves throughput by avoiding the overhead of exporting each record synchronously.
* For quick debugging or demos you can swap in a `SimpleLogRecordProcessor` which sends each record immediately; however, `BatchLogRecordProcessor` is preferred for production-like workloads.

## Severity text and numbers

OpenTelemetry provides a `SeverityNumber` enum (for example `SeverityNumber.INFO`) which is more readable and maintainable than hard-coding numeric severity values. Use `severity_text` for a human-readable level and `severity_number` for the numeric enum.

## Example output

Running the example above prints JSON-like LogRecord entries via the `ConsoleLogExporter`. Below is a formatted example of what one entry may look like:

```json theme={null}
{
  "body": "Starting the booking flight process",
  "severity_number": 9,
  "severity_text": "INFO",
  "attributes": null,
  "dropped_attributes": 0,
  "timestamp": "2025-09-18T22:54:52.611260Z",
  "observed_timestamp": "2025-09-18T22:54:52.611320Z",
  "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": ""
}
```

You can programmatically populate additional fields such as `attributes`, resource attributes, or trace/span correlation fields to enrich your logs.

## Summary & next steps

* Replace `print()` statements with `logger.emit(LogRecord(...))` to produce structured logs.
* Configure and set a global `LoggerProvider`, attach an exporter (Console used here) and a processor (`BatchLogRecordProcessor`).
* Use `get_logger()` to obtain a logger wired to your provider, and populate `body`, `timestamp`, `severity_text`, `severity_number`, and `attributes` for richer diagnostics.
* Extend this minimal setup by exporting to an OTLP collector, adding service-specific resource attributes, or correlating logs with traces.

## Links and references

* [OpenTelemetry Python Documentation](https://opentelemetry-python.readthedocs.io/)
* [OpenTelemetry Python SDK on GitHub](https://github.com/open-telemetry/opentelemetry-python)
* [OpenTelemetry Collector / OTLP exporters](https://opentelemetry.io/docs/collector/)
* Release notes and module path changes: [OpenTelemetry Python Releases](https://github.com/open-telemetry/opentelemetry-python/releases)

<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/87aa0679-0123-4079-98b6-5b90bf63bd38" />
</CardGroup>


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