Skip to content

Commit b025d3c

Browse files
committed
Update our code to properly finish queries causing errors.
1 parent d2d5088 commit b025d3c

File tree

1 file changed

+57
-25
lines changed

1 file changed

+57
-25
lines changed

sqlalchemy_opentracing/__init__.py

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
from sqlalchemy.event import listen
2-
from sqlalchemy.engine import Connectable
3-
4-
import opentracing
52

63
g_tracer = None
74

8-
def set_tracer(tracer):
5+
def init_tracing(tracer):
96
'''
107
Set our global tracer.
118
Tracer objects from our pyramid/flask/django libraries
@@ -17,42 +14,77 @@ def set_tracer(tracer):
1714
else:
1815
g_tracer = tracer
1916

20-
def set_parent_span(stmt, parent_span):
17+
def set_parent_span(stmt_obj, parent_span):
2118
'''
2219
Start tracing a given statement under
2320
a specific span.
2421
'''
25-
stmt._parent_span = parent_span
22+
stmt_obj._parent_span = parent_span
2623

27-
def has_parent_span(stmt):
24+
def has_parent_span(stmt_obj):
2825
'''
2926
Get whether or not the statement has
3027
a parent span.
3128
'''
32-
return hasattr(stmt, '_parent_span')
29+
return hasattr(stmt_obj, '_parent_span')
3330

34-
def _before_handler(conn, clauseelement, multiparams, params):
35-
parent_span = getattr(clauseelement, '_parent_span', None)
36-
span = tracer.start_span(operation_name='sql?', child_of=parent_span) # (xxx) operation name
31+
def get_span(stmt_obj):
32+
'''
33+
Get the span of a statement object, if any.
34+
'''
35+
return getattr(stmt_obj, '_span', None)
3736

38-
clauseelement._span = span
37+
def register_connectable(obj):
38+
'''
39+
Register an object to have its events be traced.
40+
Any Connectable object is accepted, which
41+
includes Connection and Engine.
42+
'''
43+
listen(obj, 'before_cursor_execute', _before_cursor_handler)
44+
listen(obj, 'after_cursor_execute', _after_cursor_handler)
45+
listen(obj, 'handle_error', _error_handler)
3946

40-
def _after_handler(conn, clauseelement, multiparams, params):
41-
if getattr(clauseelement, '_span', None) is None:
47+
def _get_operation_name(stmt_obj):
48+
return stmt_obj.__visit_name__
49+
50+
def _normalize_stmt(statement):
51+
return statement.strip().replace('\n', '').replace('\t', '')
52+
53+
def _before_cursor_handler(conn, cursor, statement, parameters, context, executemany):
54+
if context.compiled is None: # PRAGMA
55+
return
56+
57+
stmt_obj = context.compiled.statement
58+
parent_span = getattr(stmt_obj, '_parent_span', None)
59+
operation_name = _get_operation_name(stmt_obj)
60+
61+
# Start a new span for this query.
62+
span = g_tracer.start_span(operation_name=operation_name, child_of=parent_span)
63+
64+
span.set_tag('component', 'sqlalchemy')
65+
span.set_tag('db.type', 'sql')
66+
span.set_tag('db.statement', _normalize_stmt(statement))
67+
68+
stmt_obj._span = span
69+
70+
def _after_cursor_handler(conn, cursor, statement, parameters, context, executemany):
71+
if context.compiled is None: # PRAGMA
72+
return
73+
74+
stmt_obj = context.compiled.statement
75+
span = get_span(stmt_obj)
76+
if span is None:
4277
return
4378

44-
span = clauseelement._span
4579
span.finish()
4680

47-
def register_tracing(obj):
48-
'''
49-
Register an object to have its events be traced.
50-
'''
51-
if isinstance(obj, Connectable): # Engine or Connection instance.
52-
listen(obj, 'before_cursor_execute', _before_cursor_handler)
53-
listen(obj, 'after_cursor_execute', _after_cursor_handler)
81+
def _error_handler(exception_context):
82+
execution_context = exception_context.execution_context
83+
stmt_obj = execution_context.compiled.statement
84+
span = get_span(stmt_obj)
85+
if span is None:
86+
return
5487

55-
#elif isinstance(obj, MetaData): # Schema changes
56-
# listen(obj, "before_create", _schema_before_handler)
57-
# listen(obj, "after_create", _schema_after_handler)
88+
span.set_tag('error', 'true')
89+
span.finish()
5890

0 commit comments

Comments
 (0)