Python

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:
    1python3 --version
    2pip --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:

1python -m venv .venv
2source .venv/bin/activate
3
4# SDK
5pip install middleware-io
6
7# (optional) enable continuous profiling features
8pip install 'middleware-io[profiling]'
9
10# Add OpenTelemetry auto-instrumentation libraries for installed packages (e.g., Flask)
11middleware-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).

  • Auto instrumentation (zero-code) Use the CLI wrapper that the SDK installs; it starts your app with the correct instrumentation:
    1export MW_SERVICE_NAME='MyPythonApp'
    2middleware-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.):

1from middleware import mw_tracker, MWOptions
2
3mw_tracker(MWOptions(
4  service_name="MyPythonApp",
5  console_exporter=True,   # echo telemetry to stdout (dev only)
6  log_level="DEBUG",
7))

Run it with:

1export MW_TRACKER=True
2middleware-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:

1export MW_API_KEY='<MW_API_KEY>'
2export MW_TARGET='https://<MW_UID>.middleware.io:443'
3export MW_SERVICE_NAME='MyPythonApp'
4middleware-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:

1from middleware import mw_tracker, MWOptions, DETECT_AWS_EC2
2
3mw_tracker(MWOptions(
4  access_token="<MW_API_KEY>",
5  target="https://<MW_UID>.middleware.io:443",
6  service_name="MyPythonApp",
7  detectors=[DETECT_AWS_EC2],     # example
8  otel_propagators="b3,tracecontext",
9  console_exporter=True,
10  log_level="DEBUG",
11))

Run it with:

1export MW_TRACKER=True
2middleware-run python app.py

4. Advanced configuration (optional)#

Two ways to set your service name:

1export MW_SERVICE_NAME='MyPythonApp'

Or set service_name in MWOptions(...).

Enable continuous profiling:

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

Pick the run command that matches your server/framework.

1export DJANGO_SETTINGS_MODULE='mysite.settings'
2middleware-run python manage.py runserver
1export MW_API_KEY='<MW_API_KEY>'
2export MW_TARGET='https://<MW_UID>.middleware.io:443'
3export DJANGO_SETTINGS_MODULE='demo.settings'
4middleware-run gunicorn -c conf/gunicorn.conf.py --workers=4 --bind 0.0.0.0:8000 --timeout 120 demo.wsgi
1export MW_API_KEY='<MW_API_KEY>'
2export MW_TARGET='https://<MW_UID>.middleware.io:443'
3middleware-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:

1from opentelemetry.metrics import get_meter_provider
2
3meter = get_meter_provider().get_meter("custom_meter")
4
5request_counter = meter.create_counter(
6  "request_counter", description="Counts the number of requests"
7)
8
9request_counter.add(1, {"endpoint": "/home"})

Create and use a tracer to send custom spans:

1from opentelemetry.trace import get_tracer
2
3tracer = get_tracer("custom_tracer")
4
5with tracer.start_as_current_span("custom_span"):
6  print("Doing some work within the span")

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

1import logging
2
3logging.info("info sample")
4logging.warning("Sample Warning Log")
5logging.error("Sample Error Log.", extra={"tester": "Alex"})

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

1from opentelemetry.trace import get_tracer
2
3tracer = get_tracer("custom_tracer")
4
5with tracer.start_as_current_span("span_with_attributes") as span:
6  span.set_attribute("user.email", "[email protected]")
7  span.set_attribute("user.id", 1234)

Record an exception and its stack trace:

1from middleware import record_exception
2
3try:
4  print("Divide by zero:", 1 / 0)
5except Exception as e:
6  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.

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?