> ## 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.

# Instrumentation Libraries

> Explains OpenTelemetry instrumentation libraries for Python, comparing manual and automatic tracing, auto-instrumentation with RequestsInstrumentor, and design goals for SDK-agnostic reusable instrumentations

Next, we'll learn how to instrument the libraries your application depends on.

This guide walks through a small example application that calls a slow HTTP endpoint and demonstrates two approaches:

* Manual (code-based) instrumentation, and
* Automatic instrumentation using an OpenTelemetry instrumentation library.

## Example application (uninstrumented)

A minimal Python app that performs an HTTP request via the `requests` library:

```python theme={null}
# app.py
import requests

def call_slow_api():
    url = "http://httpbin.org/delay/2"
    response = requests.get(url)
    return response.text

def main():
    print("Calling slow API...")
    result = call_slow_api()
    print("Done! Response length:", len(result))

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

The call to `requests.get(url)` makes a network call to a remote service. We want to measure how long that HTTP call takes and capture additional metadata about the request and response.

## Manual instrumentation (explicit spans)

You can create spans manually around application code to record timing and metadata. This requires setting up a TracerProvider, span processor, and exporter, and creating spans with the tracer API:

```python theme={null}
# manual_instrumentation.py
import requests

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

# SDK setup (so spans are recorded and exported)
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)
trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))

def call_slow_api():
    # Manually create a span around the HTTP call
    with tracer.start_as_current_span("call_httpbin_delay"):
        url = "http://httpbin.org/delay/2"
        response = requests.get(url)
        return response.text

def main():
    with tracer.start_as_current_span("main_function_span"):
        print("Calling slow API...")
        result = call_slow_api()
        print("Done! Response length:", len(result))

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

A console exporter prints spans similar to the following (abbreviated):

```json theme={null}
{
  "name": "call_httpbin_delay",
  "kind": "SPAN_KIND_INTERNAL",
  "start_time": "2023-05-16T11:17:59.783592Z",
  "end_time": "2023-05-16T11:17:59.979302Z",
  "attributes": {},
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.31.1",
      "service.name": "unknown_service"
    }
  }
}
```

Manual instrumentation works well for targeted tracing, but applying it across many libraries and frameworks you do not own is time-consuming and error-prone.

## The challenge: so many frameworks and libraries

The Python ecosystem (and other ecosystems) contains many frameworks and clients — web frameworks, HTTP clients, ORMs, messaging clients, and more. Instrumenting each call site manually across services quickly becomes unrealistic.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/frameworks-tools-categorization-overview.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=d7b8df35ed9dd1235fe0ae7728ff7571" alt="The image lists various frameworks and tools categorized under web frameworks, libraries and clients, ORMs and DB clients, messaging and RPC, and observability targets. It highlights the problem of having too many frameworks." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/frameworks-tools-categorization-overview.jpg" />
</Frame>

What we want:

* Observability out of the box for commonly used libraries
* Minimal effort for application developers
* No vendor lock-in
* Reuse across multiple apps and teams

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-observability-icons.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=5d03b09795c978b606070bbb124ffa6e" alt="The image outlines the need for instrumentation libraries, highlighting four key points: &#x22;Observability out of the box,&#x22; &#x22;Minimal effort,&#x22; &#x22;No vendor lock-in,&#x22; and &#x22;Reuse across apps,&#x22; each represented with a respective icon." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-observability-icons.jpg" />
</Frame>

## OpenTelemetry Instrumentation Libraries

OpenTelemetry instrumentation libraries provide automatic tracing and/or metrics for popular third-party libraries. They are pre-built packages that apply language-specific techniques (in Python this is typically monkey patching) to wrap functions and capture telemetry with minimal or zero changes to your application code.

Common targets:

* HTTP clients: `requests`, `httpx`, `aiohttp`
* Web frameworks: `Flask`, `Django`, `FastAPI`
* ORMs and DB drivers: `SQLAlchemy`, database-specific drivers
* Messaging and RPC: `kafka-python`, `pika`, `celery`
* Cloud SDKs: `boto3`, etc.

Package naming convention (typical):

* `opentelemetry-instrumentation-<library-name>`

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/otel-instrumentation-libraries-features.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=18ff5149a30724838fccf80d13b9be4f" alt="The image lists five features of OTel Instrumentation Libraries: pre-built packages, language-specific techniques, zero-touch observability, comprehensive coverage, and standardized data." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/otel-instrumentation-libraries-features.jpg" />
</Frame>

Examples of instrumentation packages:

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/opentelemetry-instrumentation-examples-list.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=47fdc71776a28371571c8b08c6188836" alt="The image lists three OpenTelemetry instrumentation examples, each with a colorful numbered icon: requests for HTTP calls, Django for apps, and SQLAlchemy for database queries." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/opentelemetry-instrumentation-examples-list.jpg" />
</Frame>

## Auto-instrumenting the example using RequestsInstrumentor

Instead of adding spans manually around each HTTP call, enable the `requests` instrumentation package. Instrumentation libraries themselves use only the OpenTelemetry API — your application still configures the SDK and exporters.

```python theme={null}
# auto_instrument_requests.py
import requests

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter
from opentelemetry.instrumentation.requests import RequestsInstrumentor

# SDK setup (needed so spans are recorded and exported)
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))

# Auto-instrument the requests library (one line)
RequestsInstrumentor().instrument()

def call_slow_api():
    url = "http://httpbin.org/delay/2"
    response = requests.get(url)  # This call is automatically traced
    return response.text

def main():
    print("Calling slow API...")
    result = call_slow_api()
    print("Done! Response length:", len(result))

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

The instrumentation automatically creates spans for the HTTP client with semantic attributes (for example: `http.method`, `http.url`, `http.status_code`). A console-exported span for an instrumented HTTP GET might look like:

```json theme={null}
{
  "name": "HTTP GET",
  "kind": "SpanKind.CLIENT",
  "start_time": "2025-09-26T13:12:30.431667Z",
  "end_time": "2025-09-26T13:12:31.087899Z",
  "status": { "status_code": "ERROR" },
  "attributes": {
    "http.method": "GET",
    "http.url": "http://httpbin.org/delay/2",
    "http.status_code": 503
  },
  "resource": {
    "attributes": {
      "telemetry.sdk.language": "python",
      "telemetry.sdk.name": "opentelemetry",
      "telemetry.sdk.version": "1.14.0",
      "service.name": "unknown_service"
    }
  }
}
```

## How the instrumentation library works (high level)

When you call `RequestsInstrumentor().instrument()`, the instrumentor finds and wraps the relevant methods in the `requests` package (for example, `get`, `post`, `put`, `delete`) and replaces them with instrumented wrappers. This is usually implemented via monkey patching. Each instrumented call typically:

1. Creates a client span using the OpenTelemetry API,
2. Executes the original `requests` call, and
3. Ends the span and attaches semantic attributes based on the response.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-library-functions-diagram.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=81af3a4e3d1c1b185580f30c21e5d383" alt="The image is a diagram explaining the functions of an instrumentation library, highlighting method interception, automatic span creation, and data captured without code changes." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-library-functions-diagram.jpg" />
</Frame>

### Simplified illustration of monkey patching (conceptual)

```python theme={null}
# Conceptual pseudocode (not a real implementation)
original_get = requests.get

def instrumented_get(url, *args, **kwargs):
    # start a client span using the OpenTelemetry API
    # call original_get(url, *args, **kwargs)
    # set span attributes such as http.method, http.url, http.status_code
    # end the span
    return original_get(url, *args, **kwargs)

# Replace requests.get at runtime with the instrumented wrapper
requests.get = instrumented_get
```

## Instrumentation libraries only use the OpenTelemetry API

Instrumentation packages should depend only on the OpenTelemetry API, not on any particular SDK implementation. The application sets up the SDK (TracerProvider, processors, exporters) to record and export telemetry. This separation ensures:

* SDK-agnostic instrumentations,
* App developers can choose exporters and processors,
* Reusable, composable instrumentations across organizations.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-opentelemetry-infographic.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=1688c33f893f5688f62f66a45a64da20" alt="The image is an infographic titled &#x22;Instrumentation Libraries&#x22; depicting three main points: using only OpenTelemetry API, hooking into library behavior, and starting/ending spans." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-opentelemetry-infographic.jpg" />
</Frame>

## When to use instrumentation libraries

Instrumentation libraries are appropriate when:

* You want automatic observability without modifying application source code.
* You need consistent semantic data across services (instrumentations follow OpenTelemetry semantic conventions).
* You want to share observability setup across teams and projects.
* You want to extend OpenTelemetry support for in-house libraries by authoring custom instrumentations.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/opentelemetry-instrumentation-libraries-scenarios.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=2d591d613630a0767056b694bc361c0b" alt="The image outlines four scenarios for using instrumentation libraries with OpenTelemetry, focusing on using and sharing frameworks, extending support for custom libraries, achieving consistent observability, and supporting custom or internal libraries." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/opentelemetry-instrumentation-libraries-scenarios.jpg" />
</Frame>

## What instrumentation libraries include — and what they don't

* They hook into third-party libraries and start spans or collect metrics where appropriate.
* They populate semantic attributes automatically.
* They provide instrumented methods so your source code remains unchanged.

What they do not do:

* They do not configure or export telemetry; the application must set up the SDK, span processors, and exporters.
* They should not depend on a particular SDK implementation.

| Instrumentation libraries include                        | Instrumentation libraries do not include     |
| -------------------------------------------------------- | -------------------------------------------- |
| Hook into third-party libraries and create spans/metrics | Configure SDKs, processors, or exporters     |
| Populate semantic attributes automatically               | Depend on a particular SDK implementation    |
| Provide zero/low-touch observability for apps            | Handle backend-specific exporting or storage |

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-comparison-inclusions-exclusions.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=c78ad1e696dbc1b8397a0e25ec4265f6" alt="The image compares what instrumentation libraries include versus what they don't. It highlights tasks like wrapping third-party libraries and starting spans as included, while exporting telemetry data and configuring processors are aspects not included." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-comparison-inclusions-exclusions.jpg" />
</Frame>

## Design goals when authoring instrumentation libraries

If you author an instrumentation library, follow these design goals:

* Be SDK-agnostic — use only the OpenTelemetry API.
* Allow application developers to configure SDKs and exporters.
* Be composable and pluggable across projects.
* Follow OpenTelemetry semantic conventions for attribute naming and events.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-library-design-goals-diagram.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=8360e2e056d913a7e78a729f75d82ded" alt="The image outlines the design goals of an Instrumentation Library, which include being SDK-agnostic, allowing app developers to configure SDK and exporters, being composable and pluggable, and following semantic conventions." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-library-design-goals-diagram.jpg" />
</Frame>

<Callout icon="lightbulb" color="#1CB2FE">
  When writing an instrumentation, rely only on the OpenTelemetry API (not the SDK). Let applications decide which SDK, processors, and exporters to use.
</Callout>

## Summary — responsibilities: instrumentation libraries vs applications

* Instrumentation libraries: decide what to collect (spans/metrics), how to name/annotate them, and how to hook into library behavior. They should be reusable and depend only on the OpenTelemetry API.
* Applications: decide how to process and export telemetry. Applications configure SDKs, span processors, and exporters to send data to chosen observability backends.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/OYg0ei_WZpJtYDrJ/images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-applications-comparison.jpg?fit=max&auto=format&n=OYg0ei_WZpJtYDrJ&q=85&s=0ac0e00f72a1b3e29a5802a66ab8afb3" alt="The image compares key takeaways between Instrumentation Libraries and Applications, highlighting features like reuse, configuration, and data flow customization in the context of OpenTelemetry." width="1920" height="1080" data-path="images/Prep-Course-OpenTelemetry-Certified-Associate-OTCA-Certification/Instrumentation/Instrumentation-Libraries/instrumentation-libraries-applications-comparison.jpg" />
</Frame>

Further reading and references:

* OpenTelemetry Documentation: [https://opentelemetry.io/docs/](https://opentelemetry.io/docs/)
* Python instrumentation packages: search PyPI for `opentelemetry-instrumentation-<library-name>`

This article covered instrumentation libraries.

<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/1c859e64-d3c2-4519-92a9-a797e05ae804" />
</CardGroup>
