Python

TracesMetricsApp LogsCustom LogsProfiling

1. Prerequisites

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

  • Python 3.8+ 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).

Host (with Middleware Host Agent)
Serverless (no Host Agent)
  • 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).

  • Manual instrumentation (in code) 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().

  • Auto instrumentation (zero-code) 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)

  • Manual instrumentation (in code) 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)

  • Service name (two ways):
    1export MW_SERVICE_NAME='MyPythonApp'
    Or set service_name in MWOptions(...).
  • Continuous profiling:
    1pip install 'middleware-io[profiling]'
    2    export MW_APM_COLLECT_PROFILING=True
    3    # serverless requires MW_API_KEY + MW_TARGET as above

Framework-specific run examples:

  • Django

    1export DJANGO_SETTINGS_MODULE='mysite.settings'
    2middleware-run python manage.py runserver
  • Gunicorn

    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
  • Uvicorn (FastAPI/Starlette)

    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
  • Use the serverless env set if you’re not running a Host Agent.)

  • Host networking in containers:

    • Docker default gateway is 172.17.0.1.
    • On Kubernetes, find the service and set MW_AGENT_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

  • Custom Metrics

    Create and use a meter to send custom metrics:

    1from opentelemetry.metrics import get_meter_provider
    2
    3# Create a meter
    4meter = get_meter_provider().get_meter("custom_meter")
    5
    6# Create a counter
    7request_counter = meter.create_counter(
    8    "request_counter", description="Counts the number of requests"
    9)
    10
    11# Use the counter
    12request_counter.add(1, {"endpoint": "/home"})
  • Custom Traces

    Create and use a tracer to send custom spans:

    1from opentelemetry.trace import get_tracer
    2
    3# Create a tracer
    4tracer = get_tracer("custom_tracer")
    5
    6# Start a span
    7with tracer.start_as_current_span("custom_span"):
    8    print("Doing some work within the span")
  • Custom Logs

    Utilize logging method to send logs with a given priority. It is recommended to integrate these calls function inside your existing logger:

    1logging.info("info sample")
    2logging.warning("Sample Warning Log") 
    3logging.error("Sample Error Log.", extra={'tester': 'Alex'})
  • Custom Attributes

    All custom attributes collected will be available as filtering and grouping functions inside of the Middleware platform.

    Using similar methods from the above Traces and Logs sections you can attach custom attributes to any trace, span or log:

    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)
  • Adding Stack Traces

    Use record_exception() method to record a stack trace when an exception occurs:

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

Need assistance or want to learn more about Middleware? Contact our support team at [email protected] or join our Slack channel.