Skip to content

Commit 68190b0

Browse files
committed
updating library for release version
1 parent 444f163 commit 68190b0

File tree

11 files changed

+319
-170
lines changed

11 files changed

+319
-170
lines changed

tracereq/__init__.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,46 @@
33
_installer_lock = Lock()
44
_installed_integrations = {}
55

6-
def get_default_integrations(wsgi_app):
7-
from .customhttplib import CustomHttpLib
8-
yield CustomHttpLib()
96

10-
from .flasklib import FlaskLib
11-
yield FlaskLib(wsgi_app)
7+
def get_core_integrations():
8+
from .customlib import CustomlibIntegration
9+
yield CustomlibIntegration()
1210

1311

14-
def setup_integrations(wsgi_app):
12+
def get_custom_integrations(**kwargs):
13+
if kwargs.get('flask_wsgi_app'):
14+
from .flasklib import FlasklibIntegration
15+
yield FlasklibIntegration(kwargs.get('flask_wsgi_app'))
16+
17+
18+
def setup_integrations(*args, **kwargs):
1519
integrations = list()
16-
for integration in get_default_integrations(wsgi_app):
17-
if not any(isinstance(x, type(integration)) for x in integrations):
18-
integrations.append(integration)
20+
21+
core_integrations = get_core_integrations()
22+
custom_integrations = get_custom_integrations(**kwargs)
23+
for instance in core_integrations:
24+
if not any(isinstance(x, type(instance)) for x in integrations):
25+
integrations.append(instance)
26+
27+
for instance in custom_integrations:
28+
if not any(isinstance(x, type(instance)) for x in integrations):
29+
integrations.append(instance)
1930

2031
for integration in integrations:
2132
integration()
2233

2334

2435
class Integration(object):
25-
identifier = None
36+
integration_key = None
2637

2738
def install(self):
2839
raise NotImplementedError()
2940

3041
def __call__(self, environ=None, start_response=None):
31-
assert self.identifier
42+
assert self.integration_key
3243
with _installer_lock:
33-
if self.identifier in _installed_integrations:
44+
if self.integration_key in _installed_integrations:
3445
return
3546

3647
self.install()
37-
_installed_integrations[self.identifier] = self
48+
_installed_integrations[self.integration_key] = self

tracereq/api.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
from .hub import Hub
1+
from .engine import Engine
22
from .client import Client
33
from . import setup_integrations
44

5-
__all__ = ['Hub', 'Client']
5+
__all__ = ['Engine', 'Client']
6+
67

78
def public(f):
89
__all__.append(f.__name__)
910
return f
1011

12+
1113
@public
12-
def init(flask_wsgi_app, *args, **kwargs):
13-
client = Client(*args, **kwargs)
14-
Hub.master.attach_client(client)
15-
setup_integrations(flask_wsgi_app)
14+
def init(token, *args, **kwargs):
15+
client = Client(token, *args, **kwargs)
16+
Engine.main.attach_client(client)
17+
setup_integrations(*args, **kwargs)

tracereq/client.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
from .constants import DESTINATION_URL
1+
from .constants import DESTINATION_URL, SENSITIVE_HEADERS
22
from .transport import HTTPTransport
33

4+
45
class Client(object):
56
def __init__(
67
self,
78
token: str = '',
8-
dest: str = DESTINATION_URL,
99
*args,
1010
**kwargs
1111
):
1212
self._token = token
13-
self._dest = dest
13+
self._dest = DESTINATION_URL
14+
self._exclude_url_paths = kwargs.get('exclude_url_paths', [])
15+
self._exclude_urls_regex = kwargs.get('exclude_urls_regex', [])
16+
self._exclude_functions = kwargs.get('exclude_functions', [])
17+
self._exclude_sensitive_headers = kwargs.get('exclude_sensitive_headers', SENSITIVE_HEADERS)
1418
self._transport = HTTPTransport(self._token, self._dest)
1519

1620
@property

tracereq/constants.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
HEADER_NAME = 'TRACEREQ_TOKEN'
1+
HEADER_NAME = 'TRACEREQ-TOKEN'
22
REQUEST = 'request'
33
RESPONSE = 'response'
44
TRANSPORT_SEND_TIMEOUT = 1000.0
5-
DESTINATION_URL = 'https://app.tracereq.com'
5+
DESTINATION_URL = 'https://ingest.tracereq.com'
6+
SENSITIVE_HEADERS = [
7+
'Authorization',
8+
'Cookie'
9+
]

tracereq/customhttplib.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

tracereq/customlib.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from . import Integration
2+
from .engine import Engine
3+
from .constants import HEADER_NAME, DESTINATION_URL
4+
from urllib.parse import urlsplit
5+
6+
7+
try:
8+
from httplib import HTTPConnection
9+
except ImportError:
10+
from http.client import HTTPConnection
11+
12+
13+
class CustomlibIntegration(Integration):
14+
integration_key = "customlib"
15+
16+
def __init__(self):
17+
self.custom_httplib_connection = HTTPConnection
18+
19+
def install_httplib(self):
20+
original_putrequest = self.custom_httplib_connection.putrequest
21+
original_getresponse = self.custom_httplib_connection.getresponse
22+
23+
def custom_putrequest(self, method, url, *args, **kwargs):
24+
self.engine = Engine.current
25+
req = original_putrequest(self, method, url, *args, **kwargs)
26+
if DESTINATION_URL in self.host:
27+
return req
28+
29+
parsed_url = urlsplit(url)
30+
31+
self._trace = self.engine.get_trace()
32+
33+
span = self._trace.start_new_span(span_type='http.client')
34+
self._trace.set_span_data(span, 'http.method', method)
35+
self._trace.set_span_data(span, 'http.path', parsed_url.path)
36+
self._trace.set_span_data(span, 'http.query', parsed_url.query)
37+
38+
if self._trace:
39+
self.putheader(HEADER_NAME, span.construct_trace_header_info())
40+
41+
self._span = span
42+
return req
43+
44+
def custom_getresponse(self, *args, **kwargs):
45+
res = original_getresponse(self, *args, **kwargs)
46+
if DESTINATION_URL in self.host:
47+
return res
48+
49+
self._trace = self.engine.get_trace()
50+
51+
current_span_event = self._span
52+
self._trace.mark_finish(current_span_event)
53+
self._trace.set_span_data(current_span_event, 'reason', res.reason)
54+
self._trace.set_span_data(current_span_event, 'status_code', res.status)
55+
56+
self.engine.client.transport.send(current_span_event.to_json())
57+
return res
58+
59+
HTTPConnection.putrequest = custom_putrequest
60+
HTTPConnection.getresponse = custom_getresponse
61+
62+
def install(self):
63+
self.install_httplib()

tracereq/engine.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from threading import local
2+
3+
_local = local()
4+
5+
6+
class ParentEngine(type):
7+
@property
8+
def current(cls):
9+
try:
10+
existing_engine = _local.engine
11+
except AttributeError:
12+
_local.engine = existing_engine = Engine(MAIN_ENGINE)
13+
return existing_engine
14+
15+
@property
16+
def main(cls):
17+
return MAIN_ENGINE
18+
19+
20+
def with_metaclass(meta, *bases):
21+
class metaclass(type):
22+
def __new__(cls, name, this_bases, d):
23+
return meta(name, bases, d)
24+
25+
return type.__new__(metaclass, "temporary_class", (), {})
26+
27+
28+
class Engine(with_metaclass(ParentEngine)):
29+
def __init__(self, _engine=None):
30+
if isinstance(_engine, Engine):
31+
engine = _engine
32+
client = engine._client
33+
else:
34+
client = _engine
35+
36+
self._client = client
37+
self._trace = None
38+
self._request_in_process = None
39+
40+
def set_trace(self, trace):
41+
self._trace = trace
42+
43+
def get_trace(self):
44+
return self._trace
45+
46+
def set_request_data(self, request_data):
47+
self._request_in_process = request_data
48+
49+
def get_request_data(self):
50+
return self._request_in_process
51+
52+
@property
53+
def client(self):
54+
return self._client
55+
56+
def attach_client(self, client):
57+
self._client = client
58+
59+
60+
MAIN_ENGINE = Engine()
61+
_local.engine = MAIN_ENGINE

tracereq/flasklib.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
from flask import Flask, request
1+
from flask import Flask, _request_ctx_stack
22
from flask.signals import request_started, request_finished
33
from . import Integration
4-
from .hub import Hub
5-
from .tracing import generate_trace_req_packet, Trace
4+
from .engine import Engine
5+
from .tracing import generate_trace_event, Trace, generalize_request
66

77

8-
class FlaskLibIntegration(Integration):
9-
identifier = "flasklib"
8+
class FlasklibIntegration(Integration):
9+
integration_key = "flasklib"
1010

1111
def install(self):
1212
request_started.connect(_request_started)
13+
request_finished.connect(_request_finished)
1314

1415
def tracereq_wsgi_app(self, environ, start_response):
15-
hub = Hub.current
16+
engine = Engine.current
1617

17-
trace_id = Trace.get_trace_from_headers(environ)
18-
hub.set_trace(trace_id)
18+
trace = Trace.get_trace_from_environ(environ, span_type='http.server')
19+
engine.set_trace(trace)
1920
return self.wsgi_app(environ, start_response)
2021

2122
Flask.__call__ = tracereq_wsgi_app
@@ -25,7 +26,18 @@ def __init__(self, wsgi_app):
2526

2627

2728
def _request_started(app, **kwargs):
28-
hub = Hub.current
29-
current_trace = hub.get_trace()
30-
current_req_packet = generate_trace_req_packet(current_trace, request)
31-
hub.client.transport.send(current_req_packet)
29+
engine = Engine.current
30+
current_request_data = generalize_request(_request_ctx_stack.top.request)
31+
32+
engine.set_request_data(current_request_data)
33+
34+
35+
def _request_finished(app, response, **kwargs):
36+
engine = Engine.current
37+
current_trace = engine.get_trace()
38+
Trace.mark_finish(current_trace)
39+
40+
current_request_data = engine.get_request_data()
41+
current_trace_event = generate_trace_event(current_trace, current_request_data, response)
42+
43+
engine.client.transport.send(current_trace_event)

tracereq/hub.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)