forked from instana/python-sensor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtracer.py
159 lines (127 loc) · 5.21 KB
/
tracer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from __future__ import absolute_import
import os
import re
import time
import traceback
import opentracing as ot
from basictracer import BasicTracer
from .binary_propagator import BinaryPropagator
from .http_propagator import HTTPPropagator
from .text_propagator import TextPropagator
from .recorder import StandardRecorder, InstanaSampler
from .span import InstanaSpan, RegisteredSpan, SpanContext
from .util import generate_id
class InstanaTracer(BasicTracer):
def __init__(self, scope_manager=None, recorder=None):
if recorder is None:
recorder = StandardRecorder()
super(InstanaTracer, self).__init__(
recorder, InstanaSampler(), scope_manager)
self._propagators[ot.Format.HTTP_HEADERS] = HTTPPropagator()
self._propagators[ot.Format.TEXT_MAP] = TextPropagator()
self._propagators[ot.Format.BINARY] = BinaryPropagator()
def handle_fork(self):
# Nothing to do for the Tracer; Pass onto Recorder
self.recorder.handle_fork()
def start_active_span(self,
operation_name,
child_of=None,
references=None,
tags=None,
start_time=None,
ignore_active_span=False,
finish_on_close=True):
# create a new Span
span = self.start_span(
operation_name=operation_name,
child_of=child_of,
references=references,
tags=tags,
start_time=start_time,
ignore_active_span=ignore_active_span,
)
return self.scope_manager.activate(span, finish_on_close)
def start_span(self,
operation_name=None,
child_of=None,
references=None,
tags=None,
start_time=None,
ignore_active_span=False):
"Taken from BasicTracer so we can override generate_id calls to ours"
start_time = time.time() if start_time is None else start_time
# See if we have a parent_ctx in `references`
parent_ctx = None
if child_of is not None:
parent_ctx = (
child_of if isinstance(child_of, SpanContext)
else child_of.context)
elif references is not None and len(references) > 0:
# TODO only the first reference is currently used
parent_ctx = references[0].referenced_context
# retrieve the active SpanContext
if not ignore_active_span and parent_ctx is None:
scope = self.scope_manager.active
if scope is not None:
parent_ctx = scope.span.context
# Assemble the child ctx
gid = generate_id()
ctx = SpanContext(span_id=gid)
if parent_ctx is not None and parent_ctx.trace_id is not None:
if parent_ctx._baggage is not None:
ctx._baggage = parent_ctx._baggage.copy()
ctx.trace_id = parent_ctx.trace_id
ctx.sampled = parent_ctx.sampled
else:
ctx.trace_id = gid
ctx.sampled = self.sampler.sampled(ctx.trace_id)
# Tie it all together
span = InstanaSpan(self,
operation_name=operation_name,
context=ctx,
parent_id=(None if parent_ctx is None else parent_ctx.span_id),
tags=tags,
start_time=start_time)
if parent_ctx is not None:
span.synthetic = parent_ctx.synthetic
if operation_name in RegisteredSpan.EXIT_SPANS:
self.__add_stack(span)
elif operation_name in RegisteredSpan.ENTRY_SPANS:
# For entry spans, add only a backtrace fingerprint
self.__add_stack(span, limit=2)
return span
def inject(self, span_context, format, carrier):
if format in self._propagators:
return self._propagators[format].inject(span_context, carrier)
else:
raise ot.UnsupportedFormatException()
def extract(self, format, carrier):
if format in self._propagators:
return self._propagators[format].extract(carrier)
else:
raise ot.UnsupportedFormatException()
def __add_stack(self, span, limit=None):
""" Adds a backtrace to this span """
span.stack = []
frame_count = 0
tb = traceback.extract_stack()
tb.reverse()
for frame in tb:
if limit is not None and frame_count >= limit:
break
# Exclude Instana frames unless we're in dev mode
if "INSTANA_DEBUG" not in os.environ:
if re_tracer_frame.search(frame[0]) is not None:
continue
if re_with_stan_frame.search(frame[2]) is not None:
continue
span.stack.append({
"c": frame[0],
"n": frame[1],
"m": frame[2]
})
if limit is not None:
frame_count += 1
# Used by __add_stack
re_tracer_frame = re.compile(r"/instana/.*\.py$")
re_with_stan_frame = re.compile('with_instana')