Code import

This commit is contained in:
Jan Groß
2017-07-20 18:02:16 +02:00
parent 2ab406905d
commit 5c348ffe84
1807 changed files with 257494 additions and 0 deletions

View File

@@ -0,0 +1 @@
__all__ = ['ttypes', 'constants']

View File

@@ -0,0 +1,14 @@
#
# Autogenerated by Thrift Compiler (0.8.0)
#
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
#
#
from thrift.Thrift import TType, TMessageType, TException
from ttypes import *
CLIENT_SEND = "cs"
CLIENT_RECV = "cr"
SERVER_SEND = "ss"
SERVER_RECV = "sr"

View File

@@ -0,0 +1,452 @@
#
# Autogenerated by Thrift Compiler (0.8.0)
#
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
#
#
from thrift.Thrift import TType, TMessageType, TException
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol, TProtocol
try:
from thrift.protocol import fastbinary
except:
fastbinary = None
class AnnotationType:
BOOL = 0
BYTES = 1
I16 = 2
I32 = 3
I64 = 4
DOUBLE = 5
STRING = 6
_VALUES_TO_NAMES = {
0: "BOOL",
1: "BYTES",
2: "I16",
3: "I32",
4: "I64",
5: "DOUBLE",
6: "STRING",
}
_NAMES_TO_VALUES = {
"BOOL": 0,
"BYTES": 1,
"I16": 2,
"I32": 3,
"I64": 4,
"DOUBLE": 5,
"STRING": 6,
}
class Endpoint:
"""
Attributes:
- ipv4
- port
- service_name
"""
thrift_spec = (
None, # 0
(1, TType.I32, 'ipv4', None, None, ), # 1
(2, TType.I16, 'port', None, None, ), # 2
(3, TType.STRING, 'service_name', None, None, ), # 3
)
def __init__(self, ipv4=None, port=None, service_name=None,):
self.ipv4 = ipv4
self.port = port
self.service_name = service_name
def read(self, iprot):
if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
return
iprot.readStructBegin()
while True:
(fname, ftype, fid) = iprot.readFieldBegin()
if ftype == TType.STOP:
break
if fid == 1:
if ftype == TType.I32:
self.ipv4 = iprot.readI32();
else:
iprot.skip(ftype)
elif fid == 2:
if ftype == TType.I16:
self.port = iprot.readI16();
else:
iprot.skip(ftype)
elif fid == 3:
if ftype == TType.STRING:
self.service_name = iprot.readString();
else:
iprot.skip(ftype)
else:
iprot.skip(ftype)
iprot.readFieldEnd()
iprot.readStructEnd()
def write(self, oprot):
if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
return
oprot.writeStructBegin('Endpoint')
if self.ipv4 is not None:
oprot.writeFieldBegin('ipv4', TType.I32, 1)
oprot.writeI32(self.ipv4)
oprot.writeFieldEnd()
if self.port is not None:
oprot.writeFieldBegin('port', TType.I16, 2)
oprot.writeI16(self.port)
oprot.writeFieldEnd()
if self.service_name is not None:
oprot.writeFieldBegin('service_name', TType.STRING, 3)
oprot.writeString(self.service_name)
oprot.writeFieldEnd()
oprot.writeFieldStop()
oprot.writeStructEnd()
def validate(self):
return
def __repr__(self):
L = ['%s=%r' % (key, value)
for key, value in self.__dict__.iteritems()]
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
def __eq__(self, other):
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
def __ne__(self, other):
return not (self == other)
class Annotation:
"""
Attributes:
- timestamp
- value
- host
"""
thrift_spec = (
None, # 0
(1, TType.I64, 'timestamp', None, None, ), # 1
(2, TType.STRING, 'value', None, None, ), # 2
(3, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 3
)
def __init__(self, timestamp=None, value=None, host=None,):
self.timestamp = timestamp
self.value = value
self.host = host
def read(self, iprot):
if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
return
iprot.readStructBegin()
while True:
(fname, ftype, fid) = iprot.readFieldBegin()
if ftype == TType.STOP:
break
if fid == 1:
if ftype == TType.I64:
self.timestamp = iprot.readI64();
else:
iprot.skip(ftype)
elif fid == 2:
if ftype == TType.STRING:
self.value = iprot.readString();
else:
iprot.skip(ftype)
elif fid == 3:
if ftype == TType.STRUCT:
self.host = Endpoint()
self.host.read(iprot)
else:
iprot.skip(ftype)
else:
iprot.skip(ftype)
iprot.readFieldEnd()
iprot.readStructEnd()
def write(self, oprot):
if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
return
oprot.writeStructBegin('Annotation')
if self.timestamp is not None:
oprot.writeFieldBegin('timestamp', TType.I64, 1)
oprot.writeI64(self.timestamp)
oprot.writeFieldEnd()
if self.value is not None:
oprot.writeFieldBegin('value', TType.STRING, 2)
oprot.writeString(self.value)
oprot.writeFieldEnd()
if self.host is not None:
oprot.writeFieldBegin('host', TType.STRUCT, 3)
self.host.write(oprot)
oprot.writeFieldEnd()
oprot.writeFieldStop()
oprot.writeStructEnd()
def validate(self):
return
def __repr__(self):
L = ['%s=%r' % (key, value)
for key, value in self.__dict__.iteritems()]
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
def __eq__(self, other):
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
def __ne__(self, other):
return not (self == other)
class BinaryAnnotation:
"""
Attributes:
- key
- value
- annotation_type
- host
"""
thrift_spec = (
None, # 0
(1, TType.STRING, 'key', None, None, ), # 1
(2, TType.STRING, 'value', None, None, ), # 2
(3, TType.I32, 'annotation_type', None, None, ), # 3
(4, TType.STRUCT, 'host', (Endpoint, Endpoint.thrift_spec), None, ), # 4
)
def __init__(self, key=None, value=None, annotation_type=None, host=None,):
self.key = key
self.value = value
self.annotation_type = annotation_type
self.host = host
def read(self, iprot):
if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
return
iprot.readStructBegin()
while True:
(fname, ftype, fid) = iprot.readFieldBegin()
if ftype == TType.STOP:
break
if fid == 1:
if ftype == TType.STRING:
self.key = iprot.readString();
else:
iprot.skip(ftype)
elif fid == 2:
if ftype == TType.STRING:
self.value = iprot.readString();
else:
iprot.skip(ftype)
elif fid == 3:
if ftype == TType.I32:
self.annotation_type = iprot.readI32();
else:
iprot.skip(ftype)
elif fid == 4:
if ftype == TType.STRUCT:
self.host = Endpoint()
self.host.read(iprot)
else:
iprot.skip(ftype)
else:
iprot.skip(ftype)
iprot.readFieldEnd()
iprot.readStructEnd()
def write(self, oprot):
if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
return
oprot.writeStructBegin('BinaryAnnotation')
if self.key is not None:
oprot.writeFieldBegin('key', TType.STRING, 1)
oprot.writeString(self.key)
oprot.writeFieldEnd()
if self.value is not None:
oprot.writeFieldBegin('value', TType.STRING, 2)
oprot.writeString(self.value)
oprot.writeFieldEnd()
if self.annotation_type is not None:
oprot.writeFieldBegin('annotation_type', TType.I32, 3)
oprot.writeI32(self.annotation_type)
oprot.writeFieldEnd()
if self.host is not None:
oprot.writeFieldBegin('host', TType.STRUCT, 4)
self.host.write(oprot)
oprot.writeFieldEnd()
oprot.writeFieldStop()
oprot.writeStructEnd()
def validate(self):
return
def __repr__(self):
L = ['%s=%r' % (key, value)
for key, value in self.__dict__.iteritems()]
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
def __eq__(self, other):
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
def __ne__(self, other):
return not (self == other)
class Span:
"""
Attributes:
- trace_id
- name
- id
- parent_id
- annotations
- binary_annotations
"""
thrift_spec = (
None, # 0
(1, TType.I64, 'trace_id', None, None, ), # 1
None, # 2
(3, TType.STRING, 'name', None, None, ), # 3
(4, TType.I64, 'id', None, None, ), # 4
(5, TType.I64, 'parent_id', None, None, ), # 5
(6, TType.LIST, 'annotations', (TType.STRUCT,(Annotation, Annotation.thrift_spec)), None, ), # 6
None, # 7
(8, TType.LIST, 'binary_annotations', (TType.STRUCT,(BinaryAnnotation, BinaryAnnotation.thrift_spec)), None, ), # 8
)
def __init__(self, trace_id=None, name=None, id=None, parent_id=None, annotations=None, binary_annotations=None,):
self.trace_id = trace_id
self.name = name
self.id = id
self.parent_id = parent_id
self.annotations = annotations
self.binary_annotations = binary_annotations
def read(self, iprot):
if iprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None and fastbinary is not None:
fastbinary.decode_binary(self, iprot.trans, (self.__class__, self.thrift_spec))
return
iprot.readStructBegin()
while True:
(fname, ftype, fid) = iprot.readFieldBegin()
if ftype == TType.STOP:
break
if fid == 1:
if ftype == TType.I64:
self.trace_id = iprot.readI64();
else:
iprot.skip(ftype)
elif fid == 3:
if ftype == TType.STRING:
self.name = iprot.readString();
else:
iprot.skip(ftype)
elif fid == 4:
if ftype == TType.I64:
self.id = iprot.readI64();
else:
iprot.skip(ftype)
elif fid == 5:
if ftype == TType.I64:
self.parent_id = iprot.readI64();
else:
iprot.skip(ftype)
elif fid == 6:
if ftype == TType.LIST:
self.annotations = []
(_etype3, _size0) = iprot.readListBegin()
for _i4 in xrange(_size0):
_elem5 = Annotation()
_elem5.read(iprot)
self.annotations.append(_elem5)
iprot.readListEnd()
else:
iprot.skip(ftype)
elif fid == 8:
if ftype == TType.LIST:
self.binary_annotations = []
(_etype9, _size6) = iprot.readListBegin()
for _i10 in xrange(_size6):
_elem11 = BinaryAnnotation()
_elem11.read(iprot)
self.binary_annotations.append(_elem11)
iprot.readListEnd()
else:
iprot.skip(ftype)
else:
iprot.skip(ftype)
iprot.readFieldEnd()
iprot.readStructEnd()
def write(self, oprot):
if oprot.__class__ == TBinaryProtocol.TBinaryProtocolAccelerated and self.thrift_spec is not None and fastbinary is not None:
oprot.trans.write(fastbinary.encode_binary(self, (self.__class__, self.thrift_spec)))
return
oprot.writeStructBegin('Span')
if self.trace_id is not None:
oprot.writeFieldBegin('trace_id', TType.I64, 1)
oprot.writeI64(self.trace_id)
oprot.writeFieldEnd()
if self.name is not None:
oprot.writeFieldBegin('name', TType.STRING, 3)
oprot.writeString(self.name)
oprot.writeFieldEnd()
if self.id is not None:
oprot.writeFieldBegin('id', TType.I64, 4)
oprot.writeI64(self.id)
oprot.writeFieldEnd()
if self.parent_id is not None:
oprot.writeFieldBegin('parent_id', TType.I64, 5)
oprot.writeI64(self.parent_id)
oprot.writeFieldEnd()
if self.annotations is not None:
oprot.writeFieldBegin('annotations', TType.LIST, 6)
oprot.writeListBegin(TType.STRUCT, len(self.annotations))
for iter12 in self.annotations:
iter12.write(oprot)
oprot.writeListEnd()
oprot.writeFieldEnd()
if self.binary_annotations is not None:
oprot.writeFieldBegin('binary_annotations', TType.LIST, 8)
oprot.writeListBegin(TType.STRUCT, len(self.binary_annotations))
for iter13 in self.binary_annotations:
iter13.write(oprot)
oprot.writeListEnd()
oprot.writeFieldEnd()
oprot.writeFieldStop()
oprot.writeStructEnd()
def validate(self):
return
def __repr__(self):
L = ['%s=%r' % (key, value)
for key, value in self.__dict__.iteritems()]
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
def __eq__(self, other):
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
def __ne__(self, other):
return not (self == other)

View File

@@ -0,0 +1,186 @@
import os
import sys
import time
import struct
import socket
import random
from eventlet.green import threading
from eventlet.zipkin._thrift.zipkinCore import ttypes
from eventlet.zipkin._thrift.zipkinCore.constants import SERVER_SEND
client = None
_tls = threading.local() # thread local storage
def put_annotation(msg, endpoint=None):
""" This is annotation API.
You can add your own annotation from in your code.
Annotation is recorded with timestamp automatically.
e.g.) put_annotation('cache hit for %s' % request)
:param msg: String message
:param endpoint: host info
"""
if is_sample():
a = ZipkinDataBuilder.build_annotation(msg, endpoint)
trace_data = get_trace_data()
trace_data.add_annotation(a)
def put_key_value(key, value, endpoint=None):
""" This is binary annotation API.
You can add your own key-value extra information from in your code.
Key-value doesn't have a time component.
e.g.) put_key_value('http.uri', '/hoge/index.html')
:param key: String
:param value: String
:param endpoint: host info
"""
if is_sample():
b = ZipkinDataBuilder.build_binary_annotation(key, value, endpoint)
trace_data = get_trace_data()
trace_data.add_binary_annotation(b)
def is_tracing():
""" Return whether the current thread is tracking or not """
return hasattr(_tls, 'trace_data')
def is_sample():
""" Return whether it should record trace information
for the request or not
"""
return is_tracing() and _tls.trace_data.sampled
def get_trace_data():
if is_tracing():
return _tls.trace_data
def set_trace_data(trace_data):
_tls.trace_data = trace_data
def init_trace_data():
if is_tracing():
del _tls.trace_data
def _uniq_id():
"""
Create a random 64-bit signed integer appropriate
for use as trace and span IDs.
XXX: By experimentation zipkin has trouble recording traces with ids
larger than (2 ** 56) - 1
"""
return random.randint(0, (2 ** 56) - 1)
def generate_trace_id():
return _uniq_id()
def generate_span_id():
return _uniq_id()
class TraceData(object):
END_ANNOTATION = SERVER_SEND
def __init__(self, name, trace_id, span_id, parent_id, sampled, endpoint):
"""
:param name: RPC name (String)
:param trace_id: int
:param span_id: int
:param parent_id: int or None
:param sampled: lets the downstream servers know
if I should record trace data for the request (bool)
:param endpoint: zipkin._thrift.zipkinCore.ttypes.EndPoint
"""
self.name = name
self.trace_id = trace_id
self.span_id = span_id
self.parent_id = parent_id
self.sampled = sampled
self.endpoint = endpoint
self.annotations = []
self.bannotations = []
self._done = False
def add_annotation(self, annotation):
if annotation.host is None:
annotation.host = self.endpoint
if not self._done:
self.annotations.append(annotation)
if annotation.value == self.END_ANNOTATION:
self.flush()
def add_binary_annotation(self, bannotation):
if bannotation.host is None:
bannotation.host = self.endpoint
if not self._done:
self.bannotations.append(bannotation)
def flush(self):
span = ZipkinDataBuilder.build_span(name=self.name,
trace_id=self.trace_id,
span_id=self.span_id,
parent_id=self.parent_id,
annotations=self.annotations,
bannotations=self.bannotations)
client.send_to_collector(span)
self.annotations = []
self.bannotations = []
self._done = True
class ZipkinDataBuilder:
@staticmethod
def build_span(name, trace_id, span_id, parent_id,
annotations, bannotations):
return ttypes.Span(
name=name,
trace_id=trace_id,
id=span_id,
parent_id=parent_id,
annotations=annotations,
binary_annotations=bannotations
)
@staticmethod
def build_annotation(value, endpoint=None):
if isinstance(value, unicode):
value = value.encode('utf-8')
return ttypes.Annotation(time.time() * 1000 * 1000,
str(value), endpoint)
@staticmethod
def build_binary_annotation(key, value, endpoint=None):
annotation_type = ttypes.AnnotationType.STRING
return ttypes.BinaryAnnotation(key, value, annotation_type, endpoint)
@staticmethod
def build_endpoint(ipv4=None, port=None, service_name=None):
if ipv4 is not None:
ipv4 = ZipkinDataBuilder._ipv4_to_int(ipv4)
if service_name is None:
service_name = ZipkinDataBuilder._get_script_name()
return ttypes.Endpoint(
ipv4=ipv4,
port=port,
service_name=service_name
)
@staticmethod
def _ipv4_to_int(ipv4):
return struct.unpack('!i', socket.inet_aton(ipv4))[0]
@staticmethod
def _get_script_name():
return os.path.basename(sys.argv[0])

View File

@@ -0,0 +1,56 @@
import base64
import warnings
from scribe import scribe
from thrift.transport import TTransport, TSocket
from thrift.protocol import TBinaryProtocol
from eventlet import GreenPile
CATEGORY = 'zipkin'
class ZipkinClient(object):
def __init__(self, host='127.0.0.1', port=9410):
"""
:param host: zipkin collector IP addoress (default '127.0.0.1')
:param port: zipkin collector port (default 9410)
"""
self.host = host
self.port = port
self.pile = GreenPile(1)
self._connect()
def _connect(self):
socket = TSocket.TSocket(self.host, self.port)
self.transport = TTransport.TFramedTransport(socket)
protocol = TBinaryProtocol.TBinaryProtocol(self.transport,
False, False)
self.scribe_client = scribe.Client(protocol)
try:
self.transport.open()
except TTransport.TTransportException as e:
warnings.warn(e.message)
def _build_message(self, thrift_obj):
trans = TTransport.TMemoryBuffer()
protocol = TBinaryProtocol.TBinaryProtocolAccelerated(trans=trans)
thrift_obj.write(protocol)
return base64.b64encode(trans.getvalue())
def send_to_collector(self, span):
self.pile.spawn(self._send, span)
def _send(self, span):
log_entry = scribe.LogEntry(CATEGORY, self._build_message(span))
try:
self.scribe_client.Log([log_entry])
except Exception as e:
msg = 'ZipkinClient send error %s' % str(e)
warnings.warn(msg)
self._connect()
def close(self):
self.transport.close()

View File

@@ -0,0 +1,33 @@
from eventlet import greenthread
from eventlet.zipkin import api
__original_init__ = greenthread.GreenThread.__init__
__original_main__ = greenthread.GreenThread.main
def _patched__init(self, parent):
# parent thread saves current TraceData from tls to self
if api.is_tracing():
self.trace_data = api.get_trace_data()
__original_init__(self, parent)
def _patched_main(self, function, args, kwargs):
# child thread inherits TraceData
if hasattr(self, 'trace_data'):
api.set_trace_data(self.trace_data)
__original_main__(self, function, args, kwargs)
def patch():
greenthread.GreenThread.__init__ = _patched__init
greenthread.GreenThread.main = _patched_main
def unpatch():
greenthread.GreenThread.__init__ = __original_init__
greenthread.GreenThread.main = __original_main__

View File

@@ -0,0 +1,61 @@
import warnings
from eventlet.support import six
from eventlet.green import httplib
from eventlet.zipkin import api
# see https://twitter.github.io/zipkin/Instrumenting.html
HDR_TRACE_ID = 'X-B3-TraceId'
HDR_SPAN_ID = 'X-B3-SpanId'
HDR_PARENT_SPAN_ID = 'X-B3-ParentSpanId'
HDR_SAMPLED = 'X-B3-Sampled'
if six.PY2:
__org_endheaders__ = httplib.HTTPConnection.endheaders
__org_begin__ = httplib.HTTPResponse.begin
def _patched_endheaders(self):
if api.is_tracing():
trace_data = api.get_trace_data()
new_span_id = api.generate_span_id()
self.putheader(HDR_TRACE_ID, hex_str(trace_data.trace_id))
self.putheader(HDR_SPAN_ID, hex_str(new_span_id))
self.putheader(HDR_PARENT_SPAN_ID, hex_str(trace_data.span_id))
self.putheader(HDR_SAMPLED, int(trace_data.sampled))
api.put_annotation('Client Send')
__org_endheaders__(self)
def _patched_begin(self):
__org_begin__(self)
if api.is_tracing():
api.put_annotation('Client Recv (%s)' % self.status)
def patch():
if six.PY2:
httplib.HTTPConnection.endheaders = _patched_endheaders
httplib.HTTPResponse.begin = _patched_begin
if six.PY3:
warnings.warn("Since current Python thrift release \
doesn't support Python 3, eventlet.zipkin.http \
doesn't also support Python 3 (http.client)")
def unpatch():
if six.PY2:
httplib.HTTPConnection.endheaders = __org_endheaders__
httplib.HTTPResponse.begin = __org_begin__
if six.PY3:
pass
def hex_str(n):
"""
Thrift uses a binary representation of trace and span ids
HTTP headers use a hexadecimal representation of the same
"""
return '%0.16x' % (n,)

View File

@@ -0,0 +1,19 @@
import logging
from eventlet.zipkin import api
__original_handle__ = logging.Logger.handle
def _patched_handle(self, record):
__original_handle__(self, record)
api.put_annotation(record.getMessage())
def patch():
logging.Logger.handle = _patched_handle
def unpatch():
logging.Logger.handle = __original_handle__

View File

@@ -0,0 +1,41 @@
from eventlet.zipkin import http
from eventlet.zipkin import wsgi
from eventlet.zipkin import greenthread
from eventlet.zipkin import log
from eventlet.zipkin import api
from eventlet.zipkin.client import ZipkinClient
def enable_trace_patch(host='127.0.0.1', port=9410,
trace_app_log=False, sampling_rate=1.0):
""" Apply monkey patch to trace your WSGI application.
:param host: Scribe daemon IP address (default: '127.0.0.1')
:param port: Scribe daemon port (default: 9410)
:param trace_app_log: A Boolean indicating if the tracer will trace
application log together or not. This facility assume that
your application uses python standard logging library.
(default: False)
:param sampling_rate: A Float value (0.0~1.0) that indicates
the tracing frequency. If you specify 1.0, all request
are traced (and sent to Zipkin collecotr).
If you specify 0.1, only 1/10 requests are traced. (default: 1.0)
"""
api.client = ZipkinClient(host, port)
# monkey patch for adding tracing facility
wsgi.patch(sampling_rate)
http.patch()
greenthread.patch()
# monkey patch for capturing application log
if trace_app_log:
log.patch()
def disable_trace_patch():
http.unpatch()
wsgi.unpatch()
greenthread.unpatch()
log.unpatch()
api.client.close()

View File

@@ -0,0 +1,78 @@
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__