SigNoz
Docs
PricingCustomers
Get Started - Free
Docs
IntroductionContributingMigrate from DatadogSigNoz API
OpenTelemetry
What is OpenTelemetryOpenTelemetry Collector GuideOpenTelemetry Demo
Community
Support
Slack
X
Launch Week
Changelog
Dashboard Templates
DevOps Wordle
Newsletter
KubeCon, Atlanta 2025
More
SigNoz vs DatadogSigNoz vs New RelicSigNoz vs GrafanaSigNoz vs Dynatrace
Careers
AboutTermsPrivacySecurity & Compliance
SigNoz Logo
SigNoz
All systems operational
HIPAASOC-2
SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

Send Metrics from Python application

This guide shows you how to send metrics from your Python application (Flask, Django, FastAPI, Celery, Runtime) to SigNoz using OpenTelemetry.

Most steps are identical. To adapt this guide, update the endpoint and remove the ingestion key header as shown in Cloud → Self-Hosted.

Prerequisites

  • Python 3.9+
  • A SigNoz Cloud account or self-hosted SigNoz instance

Tested with Python 3.11 and OpenTelemetry Python SDK v1.41.1.

Send metrics to SigNoz

A VM is a virtual computer that runs on physical hardware. This includes:

  • Cloud VMs: AWS EC2, Google Compute Engine, Azure VMs, DigitalOcean Droplets
  • On-premise VMs: VMware, VirtualBox, Hyper-V, KVM
  • Bare metal servers: Physical servers running Linux/Unix directly

Use this section if you're deploying your Python application directly on a server or VM without containerization.

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_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_SERVICE_NAME="<service-name>"
export OTEL_METRICS_EXPORTER="otlp"
export OTEL_TRACES_EXPORTER="none"
export OTEL_METRIC_EXPORT_INTERVAL="60000"

Verify these values:

  • <region>: Your SigNoz Cloud region
  • <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: 60000 for 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_EXPORTER_OTLP_PROTOCOL
  value: 'http/protobuf'
- 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'

Verify these values:

  • <region>: Your SigNoz Cloud region
  • <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: 60000 for 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_EXPORTER_OTLP_PROTOCOL = "http/protobuf"
$env:OTEL_SERVICE_NAME = "<service-name>"
$env:OTEL_METRICS_EXPORTER = "otlp"
$env:OTEL_TRACES_EXPORTER = "none"
$env:OTEL_METRIC_EXPORT_INTERVAL = "60000"

Verify these values:

  • <region>: Your SigNoz Cloud region.
  • <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: 60000 for 60 seconds).

Step 1. Set environment variables in Dockerfile

Add environment variables to your Dockerfile:

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_EXPORTER_OTLP_PROTOCOL="http/protobuf"
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_EXPORTER_OTLP_PROTOCOL="http/protobuf" \
    -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

Verify these values:

  • <region>: Your SigNoz Cloud region
  • <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: 60000 for 60 seconds).

The bootstrap command (Step 3) installs instrumentations for all detected libraries, including web frameworks like Flask, Django, and FastAPI. These instrumentations generate traces (spans) for every incoming HTTP request.

Since opentelemetry-distro enables traces by default, these traces would be sent to SigNoz even though this guide only covers metrics. For apps handling many requests, this can generate significant trace volume and costs.

Setting OTEL_TRACES_EXPORTER to none disables traces while keeping metrics working as expected. If you want traces later, you can change it to otlp or remove this variable altogether. See the Python traces instrumentation guide for more details.

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():

app.py
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.

  • http.server.request.duration - Duration of HTTP server requests (histogram, seconds)
  • http.server.active_requests - Number of active HTTP server requests (up-down counter)
Instrumentation docs

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:

app.py
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 percentage
  • system.memory.usage - Memory usage in bytes
  • system.memory.utilization - Memory utilization as a ratio
  • system.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 generation
  • cpython.gc.collected_objects - Objects collected by GC

See the OpenTelemetry semantic conventions for the complete list:

  • System metrics
  • Process metrics
  • CPython runtime metrics

Troubleshooting

Metrics not appearing?

  1. Check Environment Variables: Ensure OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_PROTOCOL are set correctly:

    • Endpoint: https://ingest.<region>.signoz.cloud:443
    • Protocol: http/protobuf
  2. Check Exporter Protocol: This guide uses http/protobuf. Ensure OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf is set.

  3. Check Console Errors: The OpenTelemetry SDK prints errors to stderr by default. Check your application logs for any connection refused or authentication errors.

  4. Resource Attributes: Ensure OTEL_SERVICE_NAME is set. This helps you filter metrics by service in SigNoz.

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

Last updated: May 8, 2026

Edit on GitHub

Was this page helpful?

Your response helps us improve this page.

Prev
Node.js
Next
Rust
On this page
Prerequisites
Send metrics to SigNoz
Step 1. Set environment variables
Step 1. Set environment variables
Step 1. Set environment variables (PowerShell)
Step 1. Set environment variables in Dockerfile
Step 2. Install OpenTelemetry packages
Step 3. Install instrumentation for your dependencies
Step 4. Add custom metrics
Step 5. Run your application
Validate
Library Metrics
Custom Metrics Examples
Synchronous Instruments
Asynchronous Instruments
Runtime Metrics
Install
Usage
Exported Metrics
Troubleshooting
Metrics not appearing?
Authentication errors
"Connection Refused" errors
SSL/TLS errors
Setup OpenTelemetry Collector (Optional)
What is the OpenTelemetry Collector?
Why use it?
Next Steps

Is this page helpful?

Your response helps us improve this page.