Docs » µAPM Instrumentation Guide » Python Instrumentation

Python Instrumentation 🔗

Important

Before you start instrumenting your applications, review the information in Instrumentation Overview.

The OpenTracing API Contributions community has provided tracing instrumentation utilities and wrappers for a growing number of popular Python web frameworks, web clients, and database drivers. In order to make use of these instrumentations, it’s been the case that you need to replace your core route handler registrations and client initializations with their tracing equivalents throughout your applications. This can become a burdensome task for cross-team deployments, where service owners and instrumentors don’t share memberships, or when legacy components are currently without SMEs. Fortunately, SignalFx provides a helpful library for auto-instrumenting your applications: SignalFx-Tracing for Python.

Auto-instrumentation 🔗

In order to install any applicable, feature-ready instrumentors along with a compatible tracer, run the following commands:

$ pip install signalfx-tracing
$ sfx-py-trace-bootstrap

In many cases, if direct code modification is not easily feasible, the SignalFx Tracing utility for Python provides an application runner that will automatically replace all instrumentable client and application instances with their tracing versions:

$ SIGNALFX_ACCESS_TOKEN=<MyAccessToken> sfx-py-trace my_application.py \
    --app_arg_one --app_arg_two

If your application startup logic is modifiable by the instrumenting team, easy OpenTracing-compatible tracer creation and auto-instrumentation are made possible with a series of helper functions:

from signalfx_tracing import auto_instrument, create_tracer, trace

tracer = create_tracer('<MyAccessToken>', service_name='MyTracedApplication')
auto_instrument(tracer)

@trace
def my_function():
    # do something
    return 'Traced!'

@trace('MyOperationName')
def my_other_function():
    # do something
    return my_function()

@trace(operation_name='MyOtherOperationName', tags=dict(desired_tag='desired_value'))
def my_additional_function():
    # Obtain active span created by traced middleware
    span = tracer.scope_manager.active_span
    span.log_kv(dict(event='status'))
    span.set_tag('MyTag', 'MyValue')

    # do other things

    return 'MyValue'

Currently, the following libraries are provided with auto-instrumentation:

Library Supported Versions
Celery 3.1+
Django 1.8+
Elasticsearch 2.0+
Flask 0.10+
Psycopg 2.7+
PyMongo 3.1+
PyMySQL 0.8+
Redis-Py 2.10
Requests 2.0+
Tornado 4.3+

Custom instrumentation 🔗

We are aware that your applications are not just client and framework scaffolding. You are the best judge of the meaning and value behind the procedures initiated by your users. In situations where you desire more powerful, introspective performance-monitoring capabilities, you are able to build upon the provided instrumentations by modifying and adding to the traces automatically generated throughout your applications.

import opentracing
from signalfx_tracing import create_tracer

create_tracer(service_name='MyTracedApplication')

def my_function():
    tracer = opentracing.tracer
    with tracer.start_active_span('my_operation') as scope:
        parent_span = scope.span
        parent_span.set_tag('my_tag', 'my_value')
        try:
            # do something

            # create child span
            with tracer.start_active_span('child_operation') as child_scope:
                child_span = child_scope.span
                child_span.set_tag('child_tag', 'child_value')
                try:
                    utility_value = my_utility()
                    child_span.set_tag('my_utility.returned', utility_value)
                except Exception:
                    child_span.set_tag('error', True)
                    child_span.log_kv({'event': 'error',
                                       'error.object': traceback.format_exc()})

        except Exception:
            parent_span.set_tag('error', True)
            parent_span.log_kv({'event':'error',
                                'error.object': traceback.format_exc()})

The same functionality can also be obtained without the use of the context manager as shown below:

import opentracing
from signalfx_tracing import create_tracer

create_tracer(service_name='MyOtherTracedApplication')

def my_second_function():
    # Handling span creation without a context manager:
    tracer = opentracing.tracer
    scope = tracer.start_active_span('my_other_operation')

    try:
        fn_span = scope.span
        fn_span.log_kv({'event': 'Process initiated'})
        # do something
    except Exception:
        fn_span.set_tag('error', True)
        fn_span.log_kv({'event': 'error',
                        'error.object': traceback.format_exc()})
    finally:
        scope.close()

For more information on our supported tracer and trace decorator, as well as detailed, library-specific instrumentation instructions and examples, please see the utility’s documentation.

We also have some examples of auto-instrumented applications that you can download, run, interact with and modify.