Files
deb-python-eventlet/eventlet/zipkin/wsgi.py
Yuichi Bando 654a271b82 New feature: Add zipkin tracing to eventlet
Zipkin is a trend distributed tracing framewrok developed at Twitter.
Such tracing is useful for both developers and operatos to
understand the behavior of complex distributed systems
and find performance bottlenecks.

This patch provides a WSGI application using eventlet
with tracing facility that complies with Zipkin.

Signed-off-by: Yuichi Bando <bando.yuichi@lab.ntt.co.jp>

Original commit modified for PEP-8 fixes.
https://github.com/eventlet/eventlet/pull/218
2017-03-17 22:42:27 +03:00

79 lines
2.2 KiB
Python

import random
from eventlet import wsgi
from eventlet.zipkin import api
from eventlet.zipkin._thrift.zipkinCore.constants import \
SERVER_RECV, SERVER_SEND
from eventlet.zipkin.http import \
HDR_TRACE_ID, HDR_SPAN_ID, HDR_PARENT_SPAN_ID, HDR_SAMPLED
_sampler = None
__original_handle_one_response__ = wsgi.HttpProtocol.handle_one_response
def _patched_handle_one_response(self):
api.init_trace_data()
trace_id = int_or_none(self.headers.getheader(HDR_TRACE_ID))
span_id = int_or_none(self.headers.getheader(HDR_SPAN_ID))
parent_id = int_or_none(self.headers.getheader(HDR_PARENT_SPAN_ID))
sampled = bool_or_none(self.headers.getheader(HDR_SAMPLED))
if trace_id is None: # front-end server
trace_id = span_id = api.generate_trace_id()
parent_id = None
sampled = _sampler.sampling()
ip, port = self.request.getsockname()[:2]
ep = api.ZipkinDataBuilder.build_endpoint(ip, port)
trace_data = api.TraceData(name=self.command,
trace_id=trace_id,
span_id=span_id,
parent_id=parent_id,
sampled=sampled,
endpoint=ep)
api.set_trace_data(trace_data)
api.put_annotation(SERVER_RECV)
api.put_key_value('http.uri', self.path)
__original_handle_one_response__(self)
if api.is_sample():
api.put_annotation(SERVER_SEND)
class Sampler(object):
def __init__(self, sampling_rate):
self.sampling_rate = sampling_rate
def sampling(self):
# avoid generating unneeded random numbers
if self.sampling_rate == 1.0:
return True
r = random.random()
if r < self.sampling_rate:
return True
return False
def int_or_none(val):
if val is None:
return None
return int(val, 16)
def bool_or_none(val):
if val == '1':
return True
if val == '0':
return False
return None
def patch(sampling_rate):
global _sampler
_sampler = Sampler(sampling_rate)
wsgi.HttpProtocol.handle_one_response = _patched_handle_one_response
def unpatch():
wsgi.HttpProtocol.handle_one_response = __original_handle_one_response__