This guide shows you how to send metrics from your Python application (Flask, Django, FastAPI, Celery, Runtime) to SigNoz using OpenTelemetry.
Prerequisites
- Python 3.9 or later
- A SigNoz Cloud account or self-hosted SigNoz instance
Send metrics to SigNoz
Step 1. Set environment variables
Set the following environment variables to configure the OpenTelemetry exporter:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_SERVICE_NAME="<service-name>"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_TRACES_EXPORTER="none"
export OTEL_METRIC_EXPORT_INTERVAL="60000"
Replace the following:
<region>: Your SigNoz Cloud region (us,eu, orin). See endpoints.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,payment-service).<export-interval>: How often to export metrics in milliseconds (default:60000for 60 seconds).
Step 1. Set environment variables
Add these environment variables to your deployment manifest:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: 'https://ingest.<region>.signoz.cloud:443'
- name: OTEL_EXPORTER_OTLP_HEADERS
value: 'signoz-ingestion-key=<your-ingestion-key>'
- name: OTEL_SERVICE_NAME
value: '<service-name>'
- name: OTEL_METRICS_EXPORTER
value: 'otlp'
- name: OTEL_TRACES_EXPORTER
value: 'none'
- name: OTEL_METRIC_EXPORT_INTERVAL
value: '60000'
Replace the following:
<region>: Your SigNoz Cloud region (us,eu, orin). See endpoints.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,payment-service).<export-interval>: How often to export metrics in milliseconds (default:60000for 60 seconds).
Step 1. Set environment variables (PowerShell)
$env:OTEL_EXPORTER_OTLP_ENDPOINT = "https://ingest.<region>.signoz.cloud:443"
$env:OTEL_EXPORTER_OTLP_HEADERS = "signoz-ingestion-key=<your-ingestion-key>"
$env:OTEL_SERVICE_NAME = "<service-name>"
$env:OTEL_METRICS_EXPORTER = "otlp"
$env:OTEL_TRACES_EXPORTER = "none"
$env:OTEL_METRIC_EXPORT_INTERVAL = "60000"
Replace the following:
<region>: Your SigNoz Cloud region (us,eu, orin).<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service.<export-interval>: How often to export metrics in milliseconds (default:60000for 60 seconds).
Step 1. Set environment variables in Dockerfile
Add environment variables to your Dockerfile:
# ... build stages ...
# Set OpenTelemetry environment variables
ENV OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
ENV OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
ENV OTEL_SERVICE_NAME="<service-name>"
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_TRACES_EXPORTER="none"
ENV OTEL_METRIC_EXPORT_INTERVAL="60000"
CMD ["opentelemetry-instrument", "python", "app.py"]
Or pass them at runtime using docker run:
docker run -e OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.<region>.signoz.cloud:443" \
-e OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>" \
-e OTEL_SERVICE_NAME="<service-name>" \
-e OTEL_METRICS_EXPORTER="otlp" \
-e OTEL_TRACES_EXPORTER="none" \
-e OTEL_METRIC_EXPORT_INTERVAL="60000" \
your-image:latest
Replace the following:
<region>: Your SigNoz Cloud region (us,eu, orin). See endpoints.<your-ingestion-key>: Your SigNoz ingestion key.<service-name>: A descriptive name for your service (e.g.,payment-service).<export-interval>: How often to export metrics in milliseconds (default:60000for 60 seconds).
Step 2. Install OpenTelemetry packages
pip install opentelemetry-distro opentelemetry-exporter-otlp
Step 3. Install instrumentation for your dependencies
This command detects your installed packages and adds the corresponding instrumentation libraries:
opentelemetry-bootstrap --action=install
Run this after installing all your application dependencies. It will only instrument packages that are already installed.
Step 4. Add custom metrics
Add custom metrics to your application using metrics.get_meter():
from opentelemetry import metrics
# Get a meter - MeterProvider is auto-configured by opentelemetry-instrument
meter = metrics.get_meter("my.meter.name")
# Create a counter instrument
request_counter = meter.create_counter(
name="requests.total",
unit="1",
description="Total number of requests"
)
def handle_request(endpoint: str):
# Record the metric with attributes
request_counter.add(1, {"endpoint": endpoint})
# ... handle the request ...
This example shows a Counter, which only increases. OpenTelemetry supports other metric types like UpDownCounter, Histogram, and Observable Gauge. See Custom Metrics Examples for complete examples of each type.
Step 5. Run your application
Use opentelemetry-instrument to run your application. This command auto-configures the OpenTelemetry SDK based on your environment variables:
opentelemetry-instrument <your_run_command>
The opentelemetry-instrument command automatically collects metrics from supported libraries like Flask, Django, FastAPI, and Celery without any code changes. This includes HTTP metrics such as request duration and active requests. See Library Metrics for the full list of metrics available for your framework.
Validate
Once you have configured your application to start sending metrics to SigNoz, you can start visualizing the metrics in the metrics explorer.
Want more metrics? See Library Metrics to collect framework-specific metrics from Flask, Django, FastAPI, and other libraries. For system-level metrics like CPU, memory, and disk usage, see Runtime Metrics.
Library Metrics
Library instrumentation automatically collects metrics from supported frameworks like Flask, Django, and FastAPI. Choose your framework below to see the specific run command:
Web Frameworks
Flask
opentelemetry-instrument flask run --no-reload
Or if running directly:
opentelemetry-instrument python app.py
Always use --no-reload with Flask. The reloader spawns a child process that breaks OpenTelemetry instrumentation.
Custom Metrics Examples
OpenTelemetry supports six metric instrument types. Here's a complete example demonstrating all of them:
Synchronous Instruments
Synchronous instruments are called inline with your application code.
Counter - A value that only increases (e.g., total requests, bytes sent):
counter = meter.create_counter(
name="requests.total",
unit="1",
description="Total number of requests"
)
# Record a value
counter.add(1, {"endpoint": "/api/users"})
UpDownCounter - A value that can increase or decrease (e.g., active connections, queue size):
updown_counter = meter.create_up_down_counter(
name="connections.active",
unit="1",
description="Number of active connections"
)
# Increment
updown_counter.add(1)
# Decrement
updown_counter.add(-1)
Histogram - A distribution of values (e.g., request latency, response sizes):
histogram = meter.create_histogram(
name="request.duration",
unit="ms",
description="Request duration in milliseconds"
)
# Record a value
histogram.record(45.5, {"endpoint": "/api/users"})
Asynchronous Instruments
Asynchronous instruments use callback functions that are invoked during metric collection.
ObservableCounter - Observes a monotonically increasing value (e.g., CPU time, page faults):
from typing import Iterable
from opentelemetry.metrics import CallbackOptions, Observation
def observable_counter_callback(options: CallbackOptions) -> Iterable[Observation]:
# Return current cumulative value
yield Observation(get_total_cpu_time(), {"cpu": "cpu0"})
observable_counter = meter.create_observable_counter(
name="system.cpu.time",
callbacks=[observable_counter_callback],
unit="s",
description="CPU time"
)
ObservableUpDownCounter - Observes a value that can go up or down (e.g., memory usage, thread count):
def observable_updown_callback(options: CallbackOptions) -> Iterable[Observation]:
yield Observation(get_current_memory_usage(), {})
observable_updown = meter.create_observable_up_down_counter(
name="process.memory.usage",
callbacks=[observable_updown_callback],
unit="By",
description="Memory usage in bytes"
)
ObservableGauge - Observes a point-in-time value (e.g., temperature, current CPU utilization):
def observable_gauge_callback(options: CallbackOptions) -> Iterable[Observation]:
yield Observation(get_current_temperature(), {"location": "server-room"})
gauge = meter.create_observable_gauge(
name="temperature.current",
callbacks=[observable_gauge_callback],
unit="Cel",
description="Current temperature"
)
Runtime Metrics
To collect system metrics (CPU, memory, disk, network) and Python runtime metrics (garbage collection, thread counts), use the SystemMetricsInstrumentor.
Install
pip install opentelemetry-instrumentation-system-metrics
Usage
Add the instrumentor to your application code:
from opentelemetry.instrumentation.system_metrics import SystemMetricsInstrumentor
# Start collecting system and runtime metrics
SystemMetricsInstrumentor().instrument()
# Your application code here...
Then run with opentelemetry-instrument:
opentelemetry-instrument python app.py
Exported Metrics
When you call SystemMetricsInstrumentor().instrument(), it automatically exports 35+ metrics including:
System Metrics:
system.cpu.time- CPU time spent in different modes (user, system, idle)system.cpu.utilization- CPU utilization percentagesystem.memory.usage- Memory usage in bytessystem.memory.utilization- Memory utilization as a ratiosystem.disk.io- Disk I/O in bytes (read/write)system.network.io- Network I/O in bytes (transmit/receive)
Process Metrics:
process.cpu.time- Process CPU time (user/system)process.memory.usage- Process memory usage (resident set size)process.thread.count- Process thread count
CPython Runtime Metrics:
cpython.gc.collections- Garbage collection count by generationcpython.gc.collected_objects- Objects collected by GC
See the OpenTelemetry semantic conventions for the complete list:
Troubleshooting
Metrics not appearing?
Check Environment Variables: Ensure
OTEL_EXPORTER_OTLP_ENDPOINTis set correctly:- For gRPC (default):
https://ingest.<region>.signoz.cloud:443 - For HTTP:
https://ingest.<region>.signoz.cloud:443/v1/metrics
- For gRPC (default):
Check Exporter Protocol: This guide uses
otlp-proto-grpc. If you are behind a proxy that only supports HTTP/1.1, switch tootlp-proto-http.Check Console Errors: The OpenTelemetry SDK prints errors to stderr by default. Check your application logs for any connection refused or authentication errors.
Resource Attributes: Ensure
OTEL_SERVICE_NAMEis set. This helps you filter metrics by service in SigNoz.Verify Package Installation: Ensure all required packages are installed:
pip list | grep opentelemetry
Authentication errors
If you see errors like "Unauthorized" or "403 Forbidden":
- Verify your ingestion key is correct in
OTEL_EXPORTER_OTLP_HEADERS - Ensure the header format is exactly:
signoz-ingestion-key=<your-key>(no extra spaces) - Check that your ingestion key is active in the SigNoz Cloud dashboard
"Connection Refused" errors
- If running locally and sending to SigNoz Cloud, check your internet connection and firewall.
- If sending to a self-hosted collector, ensure the collector is running and listening on port 4317 (gRPC) or 4318 (HTTP).
SSL/TLS errors
If you encounter SSL certificate errors:
- Ensure you're using
https://in the endpoint URL - For self-hosted setups with self-signed certificates, you may need to configure the exporter to trust your CA
Setup OpenTelemetry Collector (Optional)
What is the OpenTelemetry Collector?
Think of the OTel Collector as a middleman between your app and SigNoz. Instead of your application sending data directly to SigNoz, it sends everything to the Collector first, which then forwards it along.
Why use it?
- Cleaning up data — Filter out noisy metrics you don't care about, or remove sensitive info before it leaves your servers.
- Keeping your app lightweight — Let the Collector handle batching, retries, and compression instead of your application code.
- Adding context automatically — The Collector can tag your data with useful info like which Kubernetes pod or cloud region it came from.
- Future flexibility — Want to send data to multiple backends later? The Collector makes that easy without changing your app.
See Switch from direct export to Collector for step-by-step instructions to convert your setup.
For more details, see Why use the OpenTelemetry Collector? and the Collector configuration guide.
Next Steps
- Create Dashboards to visualize your metrics.
- Set up Alerts on your metrics.
- Instrument your Python application with traces to correlate metrics with traces for better observability.