Python Flask uWSGI
Prerequisites
Python 3
Installation
-
Install dependencies:
pip install opentelemetry-distro opentelemetry-exporter-otlp-proto-http opentelemetry-instrumentation-flask
opentelemetry-bootstrap -a install -
Add the highlighted lines below to your project's main file:
app.pyfrom flask import Flask
from uwsgidecorators import postfork
import os
from opentelemetry import trace
from opentelemetry.semconv.resource import ResourceAttributes
from opentelemetry.sdk.trace import TracerProvider, Resource
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
ConsoleSpanExporter,
SimpleSpanProcessor,
)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from socket import gethostname
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
# Additional instrumentations can be enabled by
# following the docs for respective instrumentations at
# https://github.com/open-telemetry/opentelemetry-python-contrib/tree/main/instrumentation
#
# A working example with multiple instrumentations is available at
# https://github.com/cubeapm/sample_app_python_flask_uwsgi
@postfork
def init_tracing():
provider = TracerProvider(resource=Resource({
ResourceAttributes.SERVICE_NAME: os.environ['OTEL_SERVICE_NAME'],
ResourceAttributes.HOST_NAME: gethostname() or 'UNSET',
}))
if os.getenv('OTEL_LOG_LEVEL', '') == 'debug':
processor = SimpleSpanProcessor(ConsoleSpanExporter())
else:
processor = BatchSpanProcessor(OTLPSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
# Note: If uWSGI's `lazy-apps = true` option is used for running the
# app, then `@postfork` above will not work and `init_tracing` needs
# to be called by uncommenting the below line.
#init_tracing()
@app.route('/roll/<number>')
def roll(number):
return number -
Modify the application run command as follows:
OTEL_METRICS_EXPORTER=none \
OTEL_LOGS_EXPORTER=none \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://<ip_address_of_cubeapm_server>:4318/v1/traces \
OTEL_EXPORTER_OTLP_COMPRESSION=gzip \
OTEL_SERVICE_NAME=<app_name> \
uwsgi --http :8000 --wsgi-file app.py --callable app --master --enable-threads --need-app
Capture Exception StackTraces
Any exceptions occuring in your application will be captured and shown on CubeAPM. However, if you are using Flask's global exception handling (e.g., via app.register_error_handler()
), then you may need to take some extra steps as below to ensure that the exceptions get captured.
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode
from werkzeug.exceptions import HTTPException
def handle_unhandled_exception(ex):
current_span = trace.get_current_span()
if current_span:
if not isinstance(ex, HTTPException) or ex.code >= 500:
current_span.record_exception(ex)
current_span.set_status(Status(StatusCode.ERROR))
# your exception handling logic below
print(ex)
return ''
app.register_error_handler(Exception, handle_unhandled_exception)
Troubleshooting
The following can be used for debugging:
OTEL_LOG_LEVEL=debug
The following command can be tried on the application host server to check connectivity to CubeAPM server(s):
telnet <ip_address_of_cubeapm_server> 4318