mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-29 21:23:55 +08:00
152 lines
4.4 KiB
Python
152 lines
4.4 KiB
Python
import platform
|
|
import re
|
|
import sys
|
|
import textwrap
|
|
|
|
from ddtrace.vendor import six
|
|
|
|
__all__ = [
|
|
'httplib',
|
|
'iteritems',
|
|
'PY2',
|
|
'Queue',
|
|
'stringify',
|
|
'StringIO',
|
|
'urlencode',
|
|
'parse',
|
|
'reraise',
|
|
]
|
|
|
|
PYTHON_VERSION_INFO = sys.version_info
|
|
PY2 = sys.version_info[0] == 2
|
|
PY3 = sys.version_info[0] == 3
|
|
|
|
# Infos about python passed to the trace agent through the header
|
|
PYTHON_VERSION = platform.python_version()
|
|
PYTHON_INTERPRETER = platform.python_implementation()
|
|
|
|
try:
|
|
StringIO = six.moves.cStringIO
|
|
except ImportError:
|
|
StringIO = six.StringIO
|
|
|
|
httplib = six.moves.http_client
|
|
urlencode = six.moves.urllib.parse.urlencode
|
|
parse = six.moves.urllib.parse
|
|
Queue = six.moves.queue.Queue
|
|
iteritems = six.iteritems
|
|
reraise = six.reraise
|
|
reload_module = six.moves.reload_module
|
|
|
|
stringify = six.text_type
|
|
string_type = six.string_types[0]
|
|
msgpack_type = six.binary_type
|
|
# DEV: `six` doesn't have `float` in `integer_types`
|
|
numeric_types = six.integer_types + (float, )
|
|
|
|
# Pattern class generated by `re.compile`
|
|
if PYTHON_VERSION_INFO >= (3, 7):
|
|
pattern_type = re.Pattern
|
|
else:
|
|
pattern_type = re._pattern_type
|
|
|
|
|
|
def is_integer(obj):
|
|
"""Helper to determine if the provided ``obj`` is an integer type or not"""
|
|
# DEV: We have to make sure it is an integer and not a boolean
|
|
# >>> type(True)
|
|
# <class 'bool'>
|
|
# >>> isinstance(True, int)
|
|
# True
|
|
return isinstance(obj, six.integer_types) and not isinstance(obj, bool)
|
|
|
|
|
|
try:
|
|
from time import time_ns
|
|
except ImportError:
|
|
from time import time as _time
|
|
|
|
def time_ns():
|
|
return int(_time() * 10e5) * 1000
|
|
|
|
|
|
if PYTHON_VERSION_INFO[0:2] >= (3, 4):
|
|
from asyncio import iscoroutinefunction
|
|
|
|
# Execute from a string to get around syntax errors from `yield from`
|
|
# DEV: The idea to do this was stolen from `six`
|
|
# https://github.com/benjaminp/six/blob/15e31431af97e5e64b80af0a3f598d382bcdd49a/six.py#L719-L737
|
|
six.exec_(textwrap.dedent("""
|
|
import functools
|
|
import asyncio
|
|
|
|
|
|
def make_async_decorator(tracer, coro, *params, **kw_params):
|
|
\"\"\"
|
|
Decorator factory that creates an asynchronous wrapper that yields
|
|
a coroutine result. This factory is required to handle Python 2
|
|
compatibilities.
|
|
|
|
:param object tracer: the tracer instance that is used
|
|
:param function f: the coroutine that must be executed
|
|
:param tuple params: arguments given to the Tracer.trace()
|
|
:param dict kw_params: keyword arguments given to the Tracer.trace()
|
|
\"\"\"
|
|
@functools.wraps(coro)
|
|
@asyncio.coroutine
|
|
def func_wrapper(*args, **kwargs):
|
|
with tracer.trace(*params, **kw_params):
|
|
result = yield from coro(*args, **kwargs) # noqa: E999
|
|
return result
|
|
|
|
return func_wrapper
|
|
"""))
|
|
|
|
else:
|
|
# asyncio is missing so we can't have coroutines; these
|
|
# functions are used only to ensure code executions in case
|
|
# of an unexpected behavior
|
|
def iscoroutinefunction(fn):
|
|
return False
|
|
|
|
def make_async_decorator(tracer, fn, *params, **kw_params):
|
|
return fn
|
|
|
|
|
|
# DEV: There is `six.u()` which does something similar, but doesn't have the guard around `hasattr(s, 'decode')`
|
|
def to_unicode(s):
|
|
""" Return a unicode string for the given bytes or string instance. """
|
|
# No reason to decode if we already have the unicode compatible object we expect
|
|
# DEV: `six.text_type` will be a `str` for python 3 and `unicode` for python 2
|
|
# DEV: Double decoding a `unicode` can cause a `UnicodeEncodeError`
|
|
# e.g. `'\xc3\xbf'.decode('utf-8').decode('utf-8')`
|
|
if isinstance(s, six.text_type):
|
|
return s
|
|
|
|
# If the object has a `decode` method, then decode into `utf-8`
|
|
# e.g. Python 2 `str`, Python 2/3 `bytearray`, etc
|
|
if hasattr(s, 'decode'):
|
|
return s.decode('utf-8')
|
|
|
|
# Always try to coerce the object into the `six.text_type` object we expect
|
|
# e.g. `to_unicode(1)`, `to_unicode(dict(key='value'))`
|
|
return six.text_type(s)
|
|
|
|
|
|
def get_connection_response(conn):
|
|
"""Returns the response for a connection.
|
|
|
|
If using Python 2 enable buffering.
|
|
|
|
Python 2 does not enable buffering by default resulting in many recv
|
|
syscalls.
|
|
|
|
See:
|
|
https://bugs.python.org/issue4879
|
|
https://github.com/python/cpython/commit/3c43fcba8b67ea0cec4a443c755ce5f25990a6cf
|
|
"""
|
|
if PY2:
|
|
return conn.getresponse(buffering=True)
|
|
else:
|
|
return conn.getresponse()
|