Package: signalfx-instrumentation-tornado
This package enables distributed tracing in Tornado projects viaThe OpenTracing Project. Once a production system contends with real concurrency or splits into many services, crucial (and formerly easy) tasks become difficult: user-facing latency optimization, root-cause analysis of backend errors, communication about distinct pieces of a now-distributed system, etc. Distributed tracing follows a request on its journey from inception to completion from mobile/browser all the way to the microservices.As core services and libraries adopt OpenTracing, the application builder is no longer burdened with the task of adding basic tracing instrumentation to their own code. In this way, developers can build their applications with the tools they prefer and benefit from built-in tracing instrumentation. OpenTracing implementations exist for major distributed tracing systems and can be bound or swapped with a one-line configuration change.If you want to learn more about the underlying python API, visit the pythonsource code.InstallationRun the following command:$ pip install signalfx-instrumentation-tornadoSetting up Tracing for All RequestsIn order to implement tracing in your system (for all the requests), add the following lines of code to your site’sApplicationconstructor to enable tracing:importtornado_opentracingfromtornado_opentracing.scope_managersimportTornadoScopeManager# Create your opentracing tracer using TornadoScopeManager for active Span handling.tracer=SomeOpenTracingTracer(scope_manager=TornadoScopeManager())# Initialize tracing before creating the Application objecttornado_opentracing.init_tracing()# And either ONE of these possible values:# 1. Specify a TornadoTracing object.app=Application(''' Other parameters here '''opentracing_tracing=tornado_opentracing.TornadoTracing(tracer),)# 2. Pass a module-level callable, invoked once,# returning an opentracing compliant Tracer with optional parameters.app=Application(''' Other parameters here '''opentracing_tracer_callable='opentracing.mocktracer.MockTracer',opentracing_tracer_parameters={'scope_manager':tornado_opentracing.scope_managers.TornadoScopeManager(),},)It is possible to set additional settings, for advanced usage:app=Application(''' Other parameters here '''opentracing_tracing=tornado_opentracing.TornadoTracing(tracer),opentracing_trace_all=True,# defaults to True.opentracing_trace_client=True,# AsyncHTTPClient tracing, defaults to Trueopentracing_traced_attributes=['method'],# only valid if trace_all==Trueopentracing_start_span_cb=my_start_span_cb,# optional start Span callback.)Note:Valid request attributes to trace are listedhere. When you trace an attribute, this means that created spans will have tags with the attribute name and the request’s value.Tracing All RequestsIn order to trace all requests, setopentracing_trace_all=Truewhen creatingApplication(this is the default value). If you want to record any attributes (as tags) for all requests, then add them toopentracing_traced_attributes. For example, if you wanted to trace the uri and method, then setopentracing_traced_attributes = ['uri', 'method'].opentracing_start_span_cbis a callback invoked after a newSpanhas been created, and it must have two parameters: the newSpanand therequestobject.Tracing requiresinit_tracing()to be called beforeApplicationis created (which will patch theRequestHandler,Applicationand otherTornadocomponents).Tracing Individual RequestsIf you don’t want to trace all requests to your site, then you can use function decorators to trace individual functions. This can be done by managing a globally uniqueTornadoTracingobject yourself, and adding the following lines of code to any get/post/put/delete function of yourRequestHandlersub-classes:tracing=TornadoTracing(some_opentracing_tracer)classMyRequestHandler(tornado.web.RequestHandler):# put the decorator before @tornado.gen.coroutine, if used@tracing.trace(['uri','method'])# optionally pass a list of traced attributesdefget(self):...# do some stuffThis tracing usage doesn’t consume anyopentracing_*setting defined inApplication, and there is not need to callinit_tracing.The optional arguments allow for tracing of request attributes.Tracing HTTP Client RequestsWhen tracing all requests, tracing forAsyncHTTPClientis enabled by default, but this can be disabled by settingopentracing_trace_client=False.For applications tracing individual requests, or using only the http client (notornado.webusage), client tracing can be enabled like this:tornado_opentracing.init_client_tracing(some_opentracing_tracer)init_client_tracingtakes an OpenTracing-compatible tracer, and can optionally take astart_span_cbparameter as callback. Observe this callis notrequired when required when usingtrace_allwith theinit_tracinginitialization.Note: A current limitation ofTornadoScopeManagerprevents scheduling more than one coroutine with activeSpanat a time (see theActive Span Handlingsection below). And since it’s a common pattern to useAsyncHTTPClientto fetch multiple urls at a time, newly createdSpanfor client requests will not be set as active throughScopeManager.Active Span handlingFor activeSpanhandling and propagation, yourTracershould usetornado_opentracing.scope_managers.TornadoScopeManager. Tracing both all requests and individual requests will set up a proper stack context automatically, and the activeSpanwill be propagated from parent coroutines to their children. In any other case, code needs to be run undertracer_stack_context()explicitly:fromtornado_opentracing.scope_managersimporttracer_stack_contextwithtracer_stack_context():ioloop.IOLoop.current().run_sync(main_func)Note: CurrentlyTornadoScopeManagerdoes not support scheduling more than one coroutine setting the activeSpanat a time, as the given context is shared, and thus can be messed up:@tornado.gen.coroutinedefchild_coroutine(name,input_data):# Cannot set Span as active.# However, the parent active Span will still be set,# thus no need to specify it with child_of=withtracer.start_span('child-%s'%name)asspan:...@tornado.gen.corotuinedefparent_coroutine():withtracer.start_active_span('parent'):a=child_coroutine('A',input_a)b=child_coroutine('B',input_b)yield[a,b]ExamplesHere is asimple exampleof aTornadoapplication that log all requests:Other examples are included under the examples directrory.Further InformationIf you’re interested in learning more about the OpenTracing standard, please visitopentracing.ioorjoin the mailing list. If you would like to implement OpenTracing in your project and need help, feel free to send us a note atcommunity@opentracing.io.