> ## 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 Metrics Instrumentation

> Instrumenting a minimal Flask application with OpenTelemetry metrics, configuring a MeterProvider and exporters, creating instruments, recording requests, and validating local exports before production backends

In this lesson we'll instrument a minimal Flask application with OpenTelemetry metrics. The goal is to introduce metrics support incrementally:

* add and configure an OpenTelemetry MeterProvider,
* register a metrics reader and exporter,
* create metric instruments (counters, histograms, etc.),
* record metrics from request handlers,
* and validate exports locally (Console exporter) before moving to a production backend such as Prometheus.

Minimal Flask app
This is the starting point — a minimal Flask API that exposes a single GET endpoint at `/products`:

```python theme={null}
from flask import Flask

app = Flask(__name__)

@app.get("/products")
def get_products():
    return "Get All Products"

if __name__ == "__main__":
    app.run()
```

We will extend this application to collect and export metrics using OpenTelemetry.

Installation
Install the OpenTelemetry API and SDK for Python:

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

You can verify the installed packages with:

```bash theme={null}
pip freeze
```

(Exact versions will vary by environment.)

Configure metrics
Encapsulate the OpenTelemetry setup in a `configure_meter()` helper. The function:

* creates a metric exporter (ConsoleMetricExporter for local testing),
* creates a metrics reader (PeriodicExportingMetricReader) that periodically exports metrics,
* builds a `MeterProvider` with the reader and a `Resource`,
* sets it as the global meter provider,
* and returns a `Meter` instance for creating instruments.

Example implementation (place this in `main.py` or in a separate module that you import):

```python theme={null}
# main.py
from flask import Flask
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.metrics import set_meter_provider, get_meter_provider

def configure_meter(export_interval_millis: int = 5000):
    """
    Configure and install a MeterProvider that periodically exports metrics.

    Args:
        export_interval_millis: Export interval in milliseconds (default: 5000).

    Returns:
        opentelemetry.metrics.Meter: A Meter instance to create instruments.
    """
    # Export metrics to the console (useful for development/testing)
    exporter = ConsoleMetricExporter()

    # Periodically export metrics every `export_interval_millis` milliseconds
    reader = PeriodicExportingMetricReader(exporter, export_interval_millis=export_interval_millis)

    # Create a MeterProvider with the reader. You can add service attributes to the Resource.
    provider = MeterProvider(metric_readers=[reader], resource=Resource.create({}))

    # Set this provider as the global provider so the rest of the app can access it
    set_meter_provider(provider)

    # Return a Meter instance to create instruments from.
    return get_meter_provider().get_meter(name="shopping-app", version="0.1.2")
```

Key components

| Component                     |                                                          Purpose | Example / Notes                                                        |
| ----------------------------- | ---------------------------------------------------------------: | ---------------------------------------------------------------------- |
| ConsoleMetricExporter         |           Sends metric data to stdout for quick local validation | Useful in development; not for production                              |
| PeriodicExportingMetricReader |        Periodically collects and forwards metrics to an exporter | `PeriodicExportingMetricReader(exporter, export_interval_millis=5000)` |
| MeterProvider                 |                 Central provider that manages meters and readers | `MeterProvider(metric_readers=[reader], resource=Resource.create({}))` |
| Resource                      | Describes the application/service (attributes like service.name) | `Resource.create({})` — replace with attributes as needed              |

Integrate with the Flask app
Call `configure_meter()` at application startup, then create instruments from the returned `meter`. Record metrics inside request handlers.

A compact `main.py` that includes the configuration and a counter instrument:

```python theme={null}
# main.py
from flask import Flask
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.metrics import set_meter_provider, get_meter_provider

def configure_meter(export_interval_millis: int = 5000):
    exporter = ConsoleMetricExporter()
    reader = PeriodicExportingMetricReader(exporter, export_interval_millis=export_interval_millis)
    provider = MeterProvider(metric_readers=[reader], resource=Resource.create({}))
    set_meter_provider(provider)
    return get_meter_provider().get_meter(name="shopping-app", version="0.1.2")

app = Flask(__name__)

# Configure metrics and obtain a Meter
meter = configure_meter()

# Create instruments from the meter
request_counter = meter.create_counter(
    "shopping_requests",
    description="Number of requests received by the shopping API"
)

@app.get("/products")
def get_products():
    # Increment request counter by 1 for each GET /products call
    request_counter.add(1, {"endpoint": "/products", "method": "GET"})
    return "Get All Products"

if __name__ == "__main__":
    app.run()
```

Tips and best practices

<Callout icon="lightbulb" color="#1CB2FE">
  Use attributes (labels) on metric recordings to slice metrics by endpoint, HTTP method, status code, or other dimensions. For production, add meaningful `Resource` attributes such as `service.name`, `service.version`, and environment tags.
</Callout>

Running the app
Start the application:

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

Typical Flask output:

```plaintext theme={null}
 * Serving Flask app 'main'
 * Debug mode off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000/
Press CTRL+C to quit
```

While the app runs, the `PeriodicExportingMetricReader` will invoke the `ConsoleMetricExporter` at the configured interval (default 5 seconds). You should see exported metric lines printed to stdout when metrics have been recorded.

Warnings

<Callout icon="warning" color="#FF6B6B">
  ConsoleMetricExporter and Flask's built-in development server are intended for local development and testing only. For production, use a proper exporter (e.g., OTLP or Prometheus exporter) and a production WSGI server such as Gunicorn or uWSGI.
</Callout>

Next steps

* Add more instruments: histograms for request latency, up-down counters for in-flight requests, or observable instruments.
* Export to production backends:
  * Prometheus: use the Prometheus exporter/agent to scrape metrics.
  * OTLP: send metrics to an OpenTelemetry Collector and then route to your backend.
* Enrich `Resource.create({})` with metadata such as:
  * `service.name`, `service.instance.id`, `service.version`.

Links and references

* OpenTelemetry Python Metrics: [https://opentelemetry.io/docs/instrumentation/python/](https://opentelemetry.io/docs/instrumentation/python/)
* Prometheus: [https://prometheus.io](https://prometheus.io)
* OpenTelemetry Collector: [https://opentelemetry.io/docs/collector/](https://opentelemetry.io/docs/collector/)

This guide gives you a minimal, reproducible path from a simple Flask app to basic OpenTelemetry metrics collection and local export. From here you can extend the instrumentation and switch exporters to match your observability stack.

<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/6fce855c-4275-48c0-9297-a7f98a292285/lesson/97b726bd-9938-4032-b79d-d3e25123d237" />
</CardGroup>
