Python

Use the Middleware Python APM SDK to collect traces, metrics, logs and profiles from Python applications such as Django, Flask and FastAPI, with automatic instrumentation. The table shows which data types it collects.

TracesMetricsApp LogsCustom LogsProfiling
✅✅✅✅✅

1. Prerequisites#

Before you instrument anything, make sure the basics are in place:

  • Python 3.9+ and pip 23.1.2+ – verify your versions:
    bash
    python3 --version
    pip --version
  • (Host mode only) If your app runs in a container, point it at the Host Agent using MW_AGENT_SERVICE.
    • Docker default bridge gateway: 172.17.0.1
    • Kubernetes service name: mw-service.mw-agent-ns.svc.cluster.local (discover with kubectl get service --all-namespaces | grep mw-service).

2. Install#

Create an isolated environment, install the SDK, then add auto-instrumentation shims for your frameworks:

bash
python -m venv .venv
source .venv/bin/activate

# SDK
pip install middleware-io

# (optional) enable continuous profiling features
pip install 'middleware-io[profiling]'

# Add OpenTelemetry auto-instrumentation libraries for installed packages (e.g., Flask)
middleware-bootstrap -a install

What middleware-bootstrap -a install does: it scans your active site-packages and installs the matching opentelemetry-instrumentation-* libraries for any frameworks you already have (e.g., Flask → opentelemetry-instrumentation-flask).

You can confirm with pip list | grep -i flask. For containers, add RUN middleware-bootstrap -a install to your Dockerfile.

3. Instrumentation#

Pick Host (with the Middleware Host Agent) or Serverless (send directly to Middleware). Within each, choose Auto (zero-code) or Manual (call the tracker in code).

Use the CLI wrapper that the SDK installs; it starts your app with the correct instrumentation:

bash
export MW_SERVICE_NAME='MyPythonApp'
middleware-run python app.py

The SDK adds a middleware-run CLI to your venv; use it instead of raw commands like flask run so telemetry is captured. In Host mode, the OTLP target defaults to the local agent (http://localhost:9319).

Call mw_tracker(...) once at startup for more control (sampling, detectors, debug output, etc.):

python
from middleware import mw_tracker, MWOptions

mw_tracker(MWOptions(
  service_name="MyPythonApp",
  console_exporter=True,   # echo telemetry to stdout (dev only)
  log_level="DEBUG",
))

Run it with:

bash
export MW_TRACKER=True
middleware-run python app.py

MW_TRACKER=True is required when you instrument using mw_tracker().

Set the tenant endpoint and API key, then start with the same runner:

bash
export MW_API_KEY='<MW_API_KEY>'
export MW_TARGET='https://<MW_UID>.middleware.io:443'
export MW_SERVICE_NAME='MyPythonApp'
middleware-run python app.py

In serverless mode the app exports directly to Middleware, so both MW_API_KEY and MW_TARGET are required. (docs.middleware.io)

Supply the target and token via MWOptions:

python
from middleware import mw_tracker, MWOptions, DETECT_AWS_EC2

mw_tracker(MWOptions(
  access_token="<MW_API_KEY>",
  target="https://<MW_UID>.middleware.io:443",
  service_name="MyPythonApp",
  detectors=[DETECT_AWS_EC2],     # example
  otel_propagators="b3,tracecontext",
  console_exporter=True,
  log_level="DEBUG",
))

Run it with:

bash
export MW_TRACKER=True
middleware-run python app.py

4. Advanced configuration (optional)#

Two ways to set your service name:

bash
export MW_SERVICE_NAME='MyPythonApp'

Or set service_name in MWOptions(...).

Enable continuous profiling:

bash
pip install 'middleware-io[profiling]'
export MW_APM_COLLECT_PROFILING=True
# serverless requires MW_API_KEY + MW_TARGET as above

Pick the run command that matches your server/framework.

bash
export DJANGO_SETTINGS_MODULE='mysite.settings'
middleware-run python manage.py runserver
bash
export MW_API_KEY='<MW_API_KEY>'
export MW_TARGET='https://<MW_UID>.middleware.io:443'
export DJANGO_SETTINGS_MODULE='demo.settings'
middleware-run gunicorn -c conf/gunicorn.conf.py --workers=4 --bind 0.0.0.0:8000 --timeout 120 demo.wsgi
bash
export MW_API_KEY='<MW_API_KEY>'
export MW_TARGET='https://<MW_UID>.middleware.io:443'
middleware-run uvicorn main:app --host localhost --port 5002

If you’re running in a container with Host mode, set MW_AGENT_SERVICE so your app can reach the Host Agent:

  • Docker default gateway: 172.17.0.1
  • Kubernetes service: mw-service.mw-agent-ns.svc.cluster.local

What “Zero-code” actually does: automatic patching via monkey-patching of popular libraries at runtime (e.g., Flask), driven by the instrumentation packages you installed with middleware-bootstrap.

5. Sending custom data#

Create and use a meter to send custom metrics:

python
from opentelemetry.metrics import get_meter_provider

meter = get_meter_provider().get_meter("custom_meter")

request_counter = meter.create_counter(
  "request_counter", description="Counts the number of requests"
)

request_counter.add(1, {"endpoint": "/home"})

Create and use a tracer to send custom spans:

python
from opentelemetry.trace import get_tracer

tracer = get_tracer("custom_tracer")

with tracer.start_as_current_span("custom_span"):
  print("Doing some work within the span")

Use logging to emit logs. If your app already has a logger wrapper, add these calls there:

python
import logging

logging.info("info sample")
logging.warning("Sample Warning Log")
logging.error("Sample Error Log.", extra={"tester": "Alex"})

Attach attributes to spans (they become filter/group dimensions in Middleware):

python
from opentelemetry.trace import get_tracer

tracer = get_tracer("custom_tracer")

with tracer.start_as_current_span("span_with_attributes") as span:
  span.set_attribute("user.email", "johndoe@gmail.com")
  span.set_attribute("user.id", 1234)

Record an exception and its stack trace:

python
from middleware import record_exception

try:
  print("Divide by zero:", 1 / 0)
except Exception as e:
  record_exception(e)

6. Environment variables#

OTel env vars are supported and take the highest priority if present. Then Middleware env vars, then code options.

Config attributeEnvironment variable(s)Description/defaultExample
access_tokenMW_API_KEYAuth token (required for serverless/direct).xxxxxxxx…
service_nameMW_SERVICE_NAME, OTEL_SERVICE_NAMEService name shown in APM.payments-api
collect_tracesMW_APM_COLLECT_TRACESEnable traces (default true).true
collect_metricsMW_APM_COLLECT_METRICSEnable metrics (default true).true
collect_logsMW_APM_COLLECT_LOGSEnable logs (default true).true
collect_profilingMW_APM_COLLECT_PROFILINGEnable profiling (requires profiling extra).true
log_levelMW_LOG_LEVEL, OTEL_LOG_LEVELLogging level (default INFO).DEBUG
mw_agent_serviceMW_AGENT_SERVICEHost Agent address in containers.172.17.0.1 / mw-service.mw-agent-ns...
targetMW_TARGET, OTEL_EXPORTER_OTLP_ENDPOINTOTLP endpoint (Host default: http://localhost:9319).https://<MW_UID>.middleware.io:443
custom_resource_attributesMW_CUSTOM_RESOURCE_ATTRIBUTESComma-sep k=v list.call_id=123,region=us-east-1
otel_propagatorsMW_PROPAGATORS, OTEL_PROPAGATORSContext propagation (default b3).b3,tracecontext
console_exporterMW_CONSOLE_EXPORTEREcho telemetry to console (dev).true
debug_log_fileMW_DEBUG_LOG_FILELog telemetry to files (with console exporter).true
project_nameMW_PROJECT_NAMELogical app/project name.ShopApp
sample_rateMW_SAMPLE_RATE0..1 (AlwaysOn=1, AlwaysOff=0).0.5
detectorsMW_DETECTORSe.g., aws_lambda,gcp,azure,envvars.aws_lambda,gcp

7. View your data#

After you start the app, give it 3–5 minutes, then open APM → Traces, Logs, and APM → Continuous Profiling in Middleware. See “Application Instrumentation” for where to find dashboards, trace viewer, Log Explorer, and Alerts.

8. Troubleshooting#

  • No data (Host mode): Ensure you’re using middleware-run, the Host Agent is installed, and (in containers) MW_AGENT_SERVICE is set to the correct address/service.
  • No data (Serverless): Make sure both MW_API_KEY and MW_TARGET are exported before starting.
  • Instrumentation didn’t hook: Re-run middleware-bootstrap -a install after adding frameworks, and verify with pip list that opentelemetry-instrumentation-* packages exist.
  • Need to confirm register/init ran? Temporarily set MW_CONSOLE_EXPORTER=true (and MW_DEBUG_LOG_FILE=true) to echo spans/logs to stdout/files while you test.
  • Kubernetes reachability: find the service, then set MW_AGENT_SERVICE=mw-service.mw-agent-ns.svc.cluster.local.

OpenTelemetry Python#

Use this option if you want upstream OpenTelemetry auto-instrumentation (opentelemetry-distro, opentelemetry-instrument) and OTLP export directly to Middleware.

Need assistance or want to learn more about Middleware? Get in touch with us via our Contact Us or join our Slack channel.

What did you think of this content?