> ## 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 Instrumenting Application Configuring OpenTelemetry

> Guide to instrumenting a simple Python payment app with OpenTelemetry tracing, creating nested spans, printing to console, and configuring exporters for backend telemetry

In this lesson we'll instrument a small Python application using OpenTelemetry tracing. The demo app is intentionally tiny so tracing concepts are clear — the same ideas apply to other languages (JavaScript, Java, C#, etc.). By the end you'll have a working example that prints spans locally and a clear path to send telemetry to a backend.

What you'll learn

* How to add OpenTelemetry packages to a Python project
* How to configure a TracerProvider and ConsoleSpanExporter
* How to create spans that represent operations and nested child operations
* Where to go next to export traces to a backend (OTLP, Jaeger, Zipkin)

Prerequisites

* Python 3.7+
* pip

Demo application (simple payment flow)

```python theme={null}
def process_payment():
    print("processing payment")
    validate_card()
    charge_bank()

def validate_card():
    print("validating card")

def charge_bank():
    print("charging bank")

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

This tiny application represents a dummy payment service:

* `process_payment()` starts the flow.
* `validate_card()` simulates credit-card validation.
* `charge_bank()` simulates charging the user's bank.

We will instrument these functions so running the program generates trace spans for each step.

Installing OpenTelemetry packages
Install the core API and SDK packages:

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

Example of packages installed (condensed):

```plaintext theme={null}
Successfully installed opentelemetry-api-1.36.0 opentelemetry-sdk-1.36.0 opentelemetry-semantic-conventions-0.57b0 typing-extensions-4.15.0 importlib-metadata-8.7.0 zipp-3.23.0
```

<Callout icon="lightbulb" color="#1CB2FE">
  OpenTelemetry is split into API and SDK: the API provides the interfaces you call from application code, while the SDK provides concrete implementations (exporters, processors, and providers) that produce and export telemetry.
</Callout>

Configuring tracing in Python
Below is a small helper that configures a tracer provider, a span processor, and a `ConsoleSpanExporter`. The `ConsoleSpanExporter` prints spans to stdout — this is useful for local development and debugging.

```python theme={null}
# payment.py (tracing configuration)
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor

def configure_tracer():
    # Export spans to the console (useful for local testing)
    exporter = ConsoleSpanExporter()
    span_processor = SimpleSpanProcessor(exporter)

    # TracerProvider is the root object that manages tracers and span processors
    provider = TracerProvider()
    provider.add_span_processor(span_processor)

    # Make this provider the global default so trace.get_tracer() works across modules
    trace.set_tracer_provider(provider)

    # Return a named tracer for this service (name and optional version)
    return trace.get_tracer("payment", "0.1.0")
```

Instrumenting the application to generate spans
Use the tracer returned by `configure_tracer()` to create spans. The recommended pattern is to use the context manager `start_as_current_span` so spans are properly nested and automatically ended.

Complete instrumented example:

```python theme={null}
# payment.py (complete)
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor

def configure_tracer():
    exporter = ConsoleSpanExporter()
    span_processor = SimpleSpanProcessor(exporter)

    provider = TracerProvider()
    provider.add_span_processor(span_processor)

    trace.set_tracer_provider(provider)
    return trace.get_tracer("payment", "0.1.0")

def process_payment(tracer):
    # Create a root span for the payment processing flow
    with tracer.start_as_current_span("process_payment"):
        print("processing payment")
        validate_card(tracer)
        charge_bank(tracer)

def validate_card(tracer):
    # Child span for card validation
    with tracer.start_as_current_span("validate_card"):
        print("validating card")

def charge_bank(tracer):
    # Child span for charging the bank
    with tracer.start_as_current_span("charge_bank"):
        print("charging bank")

if __name__ == "__main__":
    tracer = configure_tracer()
    process_payment(tracer)
```

Running the instrumented application

```bash theme={null}
$ python payment.py
processing payment
validating card
charging bank
```

Because we used `ConsoleSpanExporter`, you will also see formatted span output printed to the console. A simplified example of what `ConsoleSpanExporter` might print (exact formatting may vary by OpenTelemetry version):

```plaintext theme={null}
Span(name="process_payment", context=TraceId(0x...), parent=None, kind=SpanKind.INTERNAL, status=Status(StatusCode.UNSET), start_time=..., end_time=..., attributes={})
Span(name="validate_card", context=TraceId(0x...), parent=..., kind=SpanKind.INTERNAL, status=Status(StatusCode.UNSET), start_time=..., end_time=..., attributes={})
Span(name="charge_bank", context=TraceId(0x...), parent=..., kind=SpanKind.INTERNAL, status=Status(StatusCode.UNSET), start_time=..., end_time=..., attributes={})
```

Exporters and next steps
When you move beyond local testing, replace `ConsoleSpanExporter` with an exporter for your backend. Common choices:

| Exporter | Use case                                                         | Docs                                                                                                                                         |
| -------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| OTLP     | Send traces to the OpenTelemetry Collector or supported backends | [https://opentelemetry.io/docs/instrumentation/python/exporters/otlp/](https://opentelemetry.io/docs/instrumentation/python/exporters/otlp/) |
| Jaeger   | Send traces directly to a Jaeger backend                         | [https://www.jaegertracing.io/](https://www.jaegertracing.io/)                                                                               |
| Zipkin   | Send traces directly to Zipkin                                   | [https://zipkin.io/](https://zipkin.io/)                                                                                                     |

You can also configure the OpenTelemetry Collector to receive OTLP and forward traces to many backends. See the OpenTelemetry Collector docs for pipeline examples.

Best practices and considerations

* Add meaningful span names, attributes, and events to capture the context that helps debugging (e.g., masked card identifier, user id, HTTP status).
* Use automatic instrumentation libraries for frameworks and popular libraries when available; complement them with manual spans for business logic.
* Keep spans short-lived and focused on logical units of work.
* Avoid logging sensitive data to spans or attributes. Use masking or hashing when necessary.

<Callout icon="warning" color="#FF6B6B">
  Do not store unmasked sensitive data (full card numbers, personal identifiers, secrets) in span attributes. Use masking or tokenization to protect user data in telemetry.
</Callout>

Links and references

* OpenTelemetry: [https://opentelemetry.io/](https://opentelemetry.io/)
* OpenTelemetry Python instrumentation: [https://opentelemetry.io/docs/instrumentation/python/](https://opentelemetry.io/docs/instrumentation/python/)
* OTLP exporter docs: [https://opentelemetry.io/docs/instrumentation/python/exporters/otlp/](https://opentelemetry.io/docs/instrumentation/python/exporters/otlp/)
* OpenTelemetry Collector: [https://opentelemetry.io/docs/collector/](https://opentelemetry.io/docs/collector/)
* Jaeger: [https://www.jaegertracing.io/](https://www.jaegertracing.io/)
* Zipkin: [https://zipkin.io/](https://zipkin.io/)

<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/d97970ef-6201-45c2-813e-e03bc75ad77a/lesson/59f4df72-f060-49ab-9e7d-e475b134b20b" />
</CardGroup>
