Skip to content

Commit 97c309d

Browse files
committed
Add a NOTES file with implementation details.
1 parent 4bf3e70 commit 97c309d

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

NOTES.txt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
SQLAlchemy OpenTracing implementation notes
2+
===========================================
3+
4+
OpenTracing support is implemented through:
5+
6+
1) Decorating objects with 'custom' tracing-related fields
7+
(statements, connections, sessions, execution contexts).
8+
2) Event handling (engine, connections, sessions).
9+
10+
Global Tracer
11+
=============
12+
13+
We make use of a global tracer, which then is consumed from the event handling we
14+
setup first. Using this one we start new span objects. One alternative is to use
15+
an actual object that would keep track itself of the items currently stored at
16+
the global level, and have different spans with different properties.
17+
18+
Statements
19+
==========
20+
21+
For tracing at the Core, we decorate statement objects (Insert, CreateTable, etc),
22+
with tracing and span parent information, which we later consult on the Engine's
23+
before_cursor_execute event - if there's need to do the tracing, we then create
24+
a span and store it in the current execution context, and finish it once the cursor
25+
either finishes (through the after_cursor_execute event), or fails (through the
26+
handle_error event). We also to post-operation cleanup of this tracing fields.
27+
28+
Connection
29+
==========
30+
31+
When tracing a connection, we do trace all the statements happening under it
32+
till either a commit or a rollback happens - these statements follow what is
33+
described in the previous section.
34+
35+
When a commit or rollback happens, the tracing information is cleared up from
36+
the connection object - being a mere facade object that gets discarded easily,
37+
this is not actually needed in many cases, but we do it nevertheless in case
38+
the object is kept around.
39+
40+
Session
41+
=======
42+
43+
Session tracing support is very similar to the described one for Connection -
44+
it relies, though, on a few other events. Specifically, we handle the
45+
'after_begin' event, which happens when a connection is acquired by the Session
46+
object to actually do something - in this case we rely on the previously
47+
described support for Connection. Since a Session *may* have access to more than
48+
one Engine, it's important to keep the handler for this event around -
49+
as long as the Session has valid tracing info.
50+
51+
We finally clean up the decorated fields from the Session object at
52+
either commit or rollback.
53+
54+
Event handlers
55+
==============
56+
57+
Since the SQLAlchemy documentation describes event handling subscription to be
58+
relatively expensive, we leave the handlers for a given Connection/Session
59+
in place, and make use of them *if* the object has valid tracing information
60+
at the time - else, we do nothing.
61+
62+
This is specially handy for Session, which will very likely be kept around.
63+
64+
Alternative approaches
65+
======================
66+
67+
One alternative idea going against decorating the objects with
68+
custom private fields of our own was to use the 'info' dictionary that
69+
exists for both Connection and Session objects. Sadly, such dictionary
70+
is 'moved' around for every Connection of the parent Engine, thus is
71+
not unique, thus we can't use it for thread scenarios.
72+
73+
One alternative was also to have thread local objects - specifically
74+
to hold the current active span. While this may have worked just fine
75+
for us, this is something that has been done and re-done in other
76+
OT libraries/language. Thus we will wait to see how the eventual
77+
solution for such active-span-holder idea unfolds, and integrate it
78+
here, if possible.
79+

0 commit comments

Comments
 (0)