Package: signalfx-tracing
:warning: Deprecation NoticeThe SignalFx Tracing Library for Python is deprecated for Python 3 and will reach End of Support on December 17th, 2022. After that date, this repository will be archived and no longer receive updates. Until then, only critical security fixes and bug fixes will be provided.Going forward, Python 3 applications should use theSplunk Distribution of OpenTelemetry
Python, which offers similar capabilities and fully supports the OpenTelemetry standard. To learn how to migrate, seeMigrate from the SignalFx Python Tracing Library.SignalFx Tracing Library for PythonThe SignalFx Tracing Library for Python automatically instruments your
Python 2.7 or 3.4+ application to capture and report distributed traces to
SignalFx with a single function. The library does so by configuring an
OpenTracing-compatible tracer you can use to capture and export trace spans.
You can use the tracer to embed custom instrumentation in the automatically
generated traces.The SignalFx-Tracing Library for Python works by detecting your libraries and
frameworks and configuring available instrumentors for distributed tracing via
the PythonOpenTracing API 2.0.
By default, its footprint is small and doesn't declare any instrumentors as
dependencies.The library provides helpfulutilitiesto
install each applicable instrumentor along with a compatible tracer. The
bootstrap utility selectively installs custom instrumentors listed in theinstrumentor requirements file. The application
runner creates a tracer with a modifiedJaeger Clientready for
reporting to SignalFx and auto-instruments your app without any required
code changes.The library enables tracing with constant sampling (i.e., 100% chance of tracing)
and reports each span to SignalFx. Where applicable, context propagation usesB3 headers.For more information about automatically instrumenting your application, seeAutomatically instrument a Python application.If you don't want to automatically instrument all applicable libraries and
frameworks, specify your target module to manually instrument your Python
application. For more information about manually instrumenting your application,
seeManually instrument a Python application.Requirements and supported softwareThese are the supported libraries.LibraryVersions supportedInstrumentation name(s)NotesCelery3.1+instrument(celery=True)Django1.8+instrument(django=True)Requiressignalfx_tracingin the project's installed applications.Elasticsearch2.0+instrument(elasticsearch=True)Falcon2.0+instrument(falcon=True)Flask0.10+instrument(flask=True)Psycopg2.7+instrument(psycopg2=True)PyMongo3.1+instrument(pymongo=True)PyMySQL0.8+instrument(pymysql=True)Redis-Py2.10+instrument(redis=True)Requests2.0+instrument(requests=True)Tornado 4.3-6.x4.3-6.xinstrument(tornado=True)If you don't provide aconfigdictionary or don't specify the following items
for your tracer, these environment variables are checked before selecting a
default value:Config kwargenvironment variabledefault valuenotesservice_nameSIGNALFX_SERVICE_NAME'SignalFx-Tracing'The name to identify the service in SignalFx.N/ASIGNALFX_ENV''The environment name to attach to span's process tags and, if log is injection is enabled, to be injected to logs. Can also be set when creating a tracer:create_tracer(config={'tags': {'environment': 'my-prod'}}).jaeger_endpointSIGNALFX_ENDPOINT_URL'http://localhost:9080/v1/trace'The endpoint the tracer sends spans to. Send spans to a Smart Agent, OpenTelemetry Collector, or a SignalFx ingest endpoint.jaeger_passwordSIGNALFX_ACCESS_TOKENNoneThe SignalFx organization access token.N/ASIGNALFX_RECORDED_VALUE_MAX_LENGTH1200The maximum length an attribute value can have. Values longer than this are truncated.N/ASPLUNK_TRACE_RESPONSE_HEADER_ENABLEDtrueEnables adding Server-Timing header to HTTP responses.Automatically instrument a Python applicationInstall the tracing library, use thesfx-py-trace-bootstraputility to
configure instrumentation and create a tracer, and automatically instrument your
application with thesfx-py-traceutility. Install instrumentation and the
Jaeger tracer with thebootstrap utilityand
automatically instrument your application with theapplication runner.sfx-py-tracecan't enable auto-instrumentation of Django projects by itself
because you have to add thesignalfx_tracinginstrumentor in the project settings'
installed applications. Once you specify the application, usesfx-py-traceas
described in theDjango instrumentation documentation.sfx-py-tracecreates a Jaeger tracer instance using the access token specified
with the environment variable or argument to report your spans to SignalFx. It
then callsauto_instrument()before running your target application file in
its own module namespace. Due to potential deadlocks in importing forking code,
you can't initialize the standard Jaeger tracer as a side effect of an import
statement. For more information, seePython threading docandknown Jaeger issue.
Because of this issue, and for general lack of HTTP reporting support, use the
modifiedJaeger tracerthat provides deferred thread creation to
avoid this constraint.sfx-py-traceattempts to instrument all available libraries there are
corresponding instrumentations installed on your system for. If you want to
prevent the tracing of particular libraries at run time, set theSIGNALFX_<LIBRARY_NAME>_ENABLED=Falseenvironment variable when launching thesfx-py-traceprocess. For example, to prevent auto-instrumentation of Tornado,
you could run:$SIGNALFX_TORNADO_ENABLED=Falsesfx-py-tracemy_application.pyThe supported value of each library name is the uppercase form of the
correspondinginstrument()keyword argument.Set the service name, endpoint URL, and access token:# Specify a name and environment for the service in SignalFx.$exportSIGNALFX_SERVICE_NAME="your_service"$exportSIGNALFX_ENV="prod"# Set the endpoint URL for the Smart Agent, OpenTelemetry Collector, or ingest endpoint.$exportSIGNALFX_ENDPOINT_URL="http://localhost:9080/v1/trace"# If you're reporting directly to SignalFx without a Smart Agent or Collector, provide the access token for your SignalFx organization.$exportSIGNALFX_ACCESS_TOKEN="your_access_token"Install the tracing library:$pipinstallsignalfx-tracingRun the bootstrap utility:$sfx-py-trace-bootstrapRun the trace utility:$sfx-py-traceyour_application.py--app_arg_one--app_arg_twoManually configure the tracing library componentsManually configure each applicable instrumentor, tracer, and instrument your
application. Manually instrumenting an application is helpful when you want to
monitor more than the auto-instrumentation process configures or you want to
add custom instrumentation tags.Uninstall any previous instrumentor versions. If you use the bootstrap
utility, it automatically does this for you.Install the tracing library:$pipinstallsignalfx-tracingInstall applicable instrumentors. There are a few ways to do this.Run the bootstrap utility:$sfx-py-trace-bootstrapRun the bootstrap utility and specify a target installation directory that
includes the most recent tracing library provided by PyPI:$sfx-py-trace-bootstrap-t/your/site/packages/directoryRun the bootstrap utility without installing the Jaeger tracer from your
project's source tree:$scripts/bootstrap.py--deps-onlyInstall the supported instrumentors as package extras from a cloned repository:$gitclonehttps://github.com/signalfx/signalfx-python-tracing.git# View setup.py for available package extras.# If you're using a pip version older than version 18, include# --process-dependency-links in the install command.$pipinstall'./signalfx-python-tracing[extra,extra,extra]'Set the service name, endpoint URL, and access token:# Specify a name for the service in SignalFx.$exportSIGNALFX_SERVICE_NAME="your_service"# Set the endpoint URL for the Smart Agent, OpenTelemetry Collector, or ingest endpoint.$exportSIGNALFX_ENDPOINT_URL="http://localhost:9080/v1/trace"# Provide the access token for your SignalFx organization.$exportSIGNALFX_ACCESS_TOKEN="your_access_token"Create a tracer usingsignalfx_tracing.utils.create_tracer(). This sets
the globalopentracing.tracerby default. The tracer uses theSIGNALFX_ACCESS_TOKENenvironment variable. By default,create_tracer()stores the initial tracer created upon first invocation and returns that instance
for subsequent invocations. If you need to use multiple tracers, you can providecreate_tracer(allow_multiple=True)as a named argument.fromsignalfx_tracingimportcreate_tracertracer=create_tracer()If you're instrumenting a Tornado application, import the Tornado Scope Manager
when you create the tracer:fromtornado_opentracing.scope_managersimportTornadoScopeManagerfromsignalfx_tracingimportcreate_tracertracer=create_tracer(scope_manager=TornadoScopeManager)Instrument your code. You can automatically instrument your code or manually
instrument your code. You can convertinstrument()andauto_instrument()to
no-ops by setting theSIGNALFX_TRACING_ENABLEDenvironment variable toFalseor0. This can be helpful when you're developing your application locally or
deploying in a test environment.Automatically instrument your code:fromsignalfx_tracingimportauto_instrument,create_tracertracer=create_tracer()auto_instrument(tracer)Manually instrument your code:fromsignalfx_tracingimportcreate_tracer,instrumenttracer=create_tracer()# or to specify service name and environmenttracer=create_tracer(config={'service_name':'my-python-service','tags':{'environment':'prod'}})instrument(tracer,flask=True)# orinstrument(flask=True)# uses the global Tracer from opentracing.tracer by defaultimportflasktraced_app=flask.Flask('MyTracedApplication')@traced_app.route('/hello_world')deftraced_route():# Obtain active span created by traced middlewarespan=tracer.scope_manager.active.spanspan.set_tag('Hello','World')span.log_kv({'event':'initiated'})return'Hello!'# Span is automatically finished after request handlerAutomatically create spans for custom application logic with a trace decorator:fromsignalfx_tracingimporttraceimportopentracingfrommy_appimportannotate,compute,report@trace# uses global opentracing.tracer set by signalfx_tracing.utils.create_tracer()defmy_function(arg):# default span operation name is the name of the function# span will automatically trace duration of my_function() without any modifications necessaryannotated=annotate(arg)returnMyBusinessLogic().my_other_function(annotated)classMyBusinessLogic:@classmethod# It's necessary to declare @trace after @classmethod and @staticmethod@trace('MyOperation')# Specify span operation namedefmy_other_function(cls,arg):# Using OpenTracing api, it's possible to modify current spans.# This active span is 'MyOperation', the current traced function and child of 'my_function'.span=opentracing.tracer.active_spanspan.set_tag('MyAnnotation',arg)value=cls.my_additional_function(arg)returnreport(value)@staticmethod@trace('MyOtherOperation',# Specify span operation name and tagstags={'tag_name':'tag_value','another_tag_name':'another_tag_value'})defmy_additional_function(arg):span=opentracing.tracer.active_span# This active span is 'MyOtherOperation', the child of 'MyOperation'.value=compute(arg)span.set_tag('ComputedValue',value)returnvalueAny invocation ofmy_function()results in a trace consisting of at least
three spans whose relationship mirrors the call graph. Ifmy_function()were
to be called from another traced function or auto-instrumented request handler,
its resulting span would be parented by that caller function's span.Tracer debug loggingThe tracer can be configured to log debugging information by settingSIGNALFX_TRACING_DEBUGtotrue. This tell the tracer to log additional information that might be
helpful in understanding how it operates. Note that in order for debug logging to work, you application must initialize logging withlogging.basicConfig()first.Inject trace ID, span ID, service name and environment into logsLink individual log entries with trace IDs and span IDs associated with corresponding events. The SignalFx Python instrumentation patcheslogging.Logger.makeRecordmethod to automatically inject trace context into allLogRecordobjects. WhenSIGNALFX_LOGS_INJECTIONenvironment variable is set totrue, the logging instrumentation also sets a custom logging format to automatically inject the trace context into logs. The default format looks like the following:%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(lineno)d] [signalfx.trace_id=%(sfxTraceId)s signalfx.span_id=%(sfxSpanId)s signalfx.service=%(sfxService)s signalfx.environment=%(sfxEnvironment)s] - %(message)sIf you don't want the instrumentation to set a custom logging format and would rather use your format, you can setSIGNALFX_LOGS_INJECTIONtofalseto disable automatic injection. You can then add%(sfxSpanId)sand%(sfxTraceId)sto your log format to inject the trace context. Alternately, you can keep automatic injection enabled and pass your custom logging format to the instrumentation by setting theSIGNALFX_LOGGING_FORMATenv var.Log injection is not enabled by default and can be enabled by settingSIGNALFX_LOGS_INJECTIONenvironment variable totrue.Manually installing instrumentationssfx-py-trace-bootstrapcommand automatically detects and installs the relevant instrumentations for your environment. If for some reason you cannot use the bootstrap command, you can manually install the relevant packages with pip. Following is a list of all the libraries we support and the commands to install their corresponding instrumentation packages.Library/FrameworkInstrumentation Packagecelerysignalfx-instrumentation-celerydjangosignalfx-instrumentation-djangoelasticsearchsignalfx-instrumentation-elasticsearchflasksignalfx-instrumentation-flaskpsycopgsignalfx-instrumentation-dbapipymongosignalfx-instrumentation-pymongopymysqlsignalfx-instrumentation-dbapiredissignalfx-instrumentation-redisrequestssignalfx-instrumentation-requeststornadosignalfx-instrumentation-tornadoExampleIf your Python app is using flask and you want to install flask instrumentation, you'd have to runpip install signalfx-instrumentation-flaskor add the package to yourrequirements.txtfile.