> ## 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 Integrating Traces With Logs

> Explains configuring OpenTelemetry logging and tracing in Python so log records automatically include trace and span identifiers for correlating logs with traces.

Earlier we configured Python logging and wired the standard library logger to forward records to [OpenTelemetry](https://opentelemetry.io/). That initial setup correctly emitted log records, but the records did not include any trace or span identifiers because tracing had not been configured.

Below is the original logging setup used for the demo:

```python theme={null}
logger_provider.add_log_record_processor(processor)

set_logger_provider(logger_provider=logger_provider)

logger = get_logger("flight-booking", "0.1.2")
handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)
logging.basicConfig(handlers=[handler], level=logging.NOTSET)

def book_flight():
    # Previously we emitted a LogRecord directly:
    # logger.emit(LogRecord(body="Starting the booking flight process",
    #                       timestamp=time.time_ns(), severity_text="INFO",
    #                       severity_number=SeverityNumber.INFO))
    logging.info("starting booking process")
    search_flights()
```

Why trace IDs were missing

* OpenTelemetry can automatically attach `trace_id` and `span_id` to log records, but only when a tracer is configured and a span is active.
* With no tracer, logs still include other metadata (file, function, line) but will show zeroed or empty trace/span identifiers.

Example log record produced before tracing was configured (note the zeroed `trace_id` and `span_id`):

```json theme={null}
{
  "body": "WARNING:root:Reserving flight",
  "severity_number": 13,
  "severity_text": "WARN",
  "attributes": {
    "code.file.path": "/Users/sanjeev/Documents/courses/logs-demo/main.py",
    "code.function.name": "reserve_flight",
    "code.line.number": 37
  },
  "dropped_attributes": 0,
  "timestamp": "2025-09-18T23:23:48.279612Z",
  "observed_timestamp": "2025-09-18T23:23:48.279616Z",
  "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": ""
}
```

Complete corrected setup
To automatically correlate logs with traces, install and configure both a logging provider and a tracing provider. First import the required OpenTelemetry modules:

```python theme={null}
import logging
import time

from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry._logs import set_logger_provider, get_logger
from opentelemetry.sdk._logs.export import ConsoleLogExporter, BatchLogRecordProcessor
from opentelemetry._logs.severity import SeverityNumber

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
```

Next configure the logging pipeline and a simple tracing pipeline that export to the console. This ensures spans and log records are printed and that logs created while a span is active will include the span and trace identifiers.

```python theme={null}
# --- Logging setup ---
logger_provider = LoggerProvider()
log_exporter = ConsoleLogExporter()
log_processor = BatchLogRecordProcessor(log_exporter)
logger_provider.add_log_record_processor(log_processor)
set_logger_provider(logger_provider=logger_provider)

handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)
logging.basicConfig(handlers=[handler], level=logging.NOTSET)
logger = get_logger("flight-booking", "0.1.2")

# --- Tracing setup ---
tracer_provider = TracerProvider()
span_exporter = ConsoleSpanExporter()
span_processor = SimpleSpanProcessor(span_exporter)
tracer_provider.add_span_processor(span_processor)
trace.set_tracer_provider(tracer_provider)
tracer = trace.get_tracer(__name__)
```

Note: with the tracer in place, any log records emitted while a span is active will include that span's `trace_id` and `span_id` automatically.

<Callout icon="lightbulb" color="#1CB2FE">
  The `tracer.start_as_current_span` method can be used either as a context manager or as a decorator. When used as a decorator, the decorated function runs with the new span as the current active span for the duration of the function.
</Callout>

Wrap logical operations with spans
Update your functions so each logical operation runs inside a span. When logging occurs inside those spans, the log records will have the associated `trace_id` and `span_id`, enabling automatic correlation between logs and traces.

```python theme={null}
@tracer.start_as_current_span("Book Flight")
def book_flight():
    logging.info("starting booking process")
    search_flights()
    reserve_flight()


@tracer.start_as_current_span("Search Flight")
def search_flights():
    logging.info("Searching for flights")


@tracer.start_as_current_span("Reserve Flight")
def reserve_flight():
    logging.warning("Reserving flight")
```

What you will see on the console

* Spans printed by the `ConsoleSpanExporter` include `trace_id` and `span_id`.
* Log records printed by the `ConsoleLogExporter` include the same `trace_id` and `span_id` when generated while the span is active.

Example span output (representative/truncated):

```json theme={null}
{
  "name": "Book Flight",
  "context": {
    "trace_id": "0x753bf54e586511c2888937f1d468f2be",
    "span_id": "0xc591f89f61e3b890",
    "trace_state": "[]"
  },
  "kind": "SpanKind.INTERNAL",
  "parent_id": null,
  "start_time": "2025-09-18T23:28:20.545641Z",
  "end_time": "2025-09-18T23:28:20.546201Z",
  "status": { "status_code": "UNSET" },
  "attributes": {},
  "events": [],
  "links": [],
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.37.0",
      "service.name": "unknown_service"
    },
    "schema_url": ""
  }
}
```

Corresponding log record for the "Book Flight" operation (now containing non-zero trace/span IDs):

```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": 38
  },
  "timestamp": "2025-09-18T23:28:20.546122Z",
  "observed_timestamp": "2025-09-18T23:28:20.546130Z",
  "trace_id": "0x753bf54e586511c2888937f1d468f2be",
  "span_id": "0xc591f89f61e3b890",
  "trace_flags": 1,
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.37.0",
      "service.name": "unknown_service"
    },
    "schema_url": ""
  },
  "event_name": ""
}
```

"Reserve Flight" span and matching log record (same `trace_id`, unique `span_id`):

```json theme={null}
{
  "name": "Reserve Flight",
  "context": {
    "trace_id": "0x753bf54e586511c2888937f1d468f2be",
    "span_id": "0x76384adc45c2dc48",
    "trace_state": "[]"
  },
  "kind": "SpanKind.INTERNAL",
  "parent_id": "0xc591f89f61e3b89b",
  "start_time": "2025-09-18T23:28:20.546112Z",
  "end_time": "2025-09-18T23:28:20.546152Z",
  "status": { "status_code": "UNSET" },
  "attributes": {},
  "events": [],
  "links": [],
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.37.0",
      "service.name": "unknown_service"
    },
    "schema_url": ""
  }
}
```

```json theme={null}
{
  "body": "WARNING:root:Reserving flight",
  "severity_number": 13,
  "severity_text": "WARN",
  "attributes": {
    "code.file.path": "/Users/sanjeev/Documents/courses/logs-demo/main.py",
    "code.function.name": "reserve_flight",
    "code.line.number": 50
  },
  "timestamp": "2025-09-18T23:28:20.546122Z",
  "observed_timestamp": "2025-09-18T23:28:20.546130Z",
  "trace_id": "0x753bf54e586511c2888937f1d468f2be",
  "span_id": "0x76384adc45c2dc48",
  "trace_flags": 1,
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.37.0",
      "service.name": "unknown_service"
    },
    "schema_url": ""
  },
  "event_name": ""
}
```

Why this helps

* Automatic log-trace correlation makes root-cause analysis much faster: you can jump from a log entry directly to the full trace to see timing, parent/child spans, and contextual attributes.
* This approach requires minimal changes: set up a tracer and ensure operations run inside spans.

Run the script
Add a standard entry point and run the program to see correlated spans and logs on the console:

```python theme={null}
if __name__ == "__main__":
    book_flight()
```

Summary table — components used

| Component | Purpose | Example / Notes |
| - | - | - |
| `LoggerProvider` | Provides the logging SDK pipeline | Used with `BatchLogRecordProcessor` and `ConsoleLogExporter` |
| `LoggingHandler` | Bridges Python `logging` to OpenTelemetry | Attach to `logging.basicConfig` handlers |
| `TracerProvider` | Provides tracer instances and span processors | Add `SimpleSpanProcessor` + `ConsoleSpanExporter` |
| `tracer.start_as_current_span` | Creates an active span context | Can be used as decorator or context manager |

Further reading and references

* [OpenTelemetry Python](https://opentelemetry.io/docs/instrumentation/python/)
* [Logging semantic conventions](https://opentelemetry.io/docs/reference/specification/logs/)
* [OpenTelemetry SDK for Python — GitHub](https://github.com/open-telemetry/opentelemetry-python)

This setup demonstrates how to attach trace and span identifiers to log records automatically by configuring both OpenTelemetry logging and tracing. Once enabled, logs produced while spans are active will include `trace_id` and `span_id`, giving you fast, reliable links from logs to traces for debugging and observability.

<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/388176b6-225e-49d9-b25c-3b90f2418f16" />
</CardGroup>


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