Skip to content

Commit 4bf3e70

Browse files
Merge pull request #3 from carlosalberto/final_refinements
Final refinements
2 parents 41aa56e + fe021b3 commit 4bf3e70

16 files changed

Lines changed: 941 additions & 72 deletions

Makefile

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: test install clean clean-build clean-pyc build
1+
.PHONY: test publish install clean clean-build clean-pyc clean-test build
22

33
install:
44
python setup.py install
@@ -20,6 +20,27 @@ clean-pyc:
2020
find . -name '*~' -exec rm -f {} +
2121
find . -name '__pycache__' -exec rm -fr {} +
2222

23+
clean-test:
24+
rm -f .coverage
25+
26+
test:
27+
py.test -s --cov=sqlalchemy_opentracing
28+
2329
build:
2430
python setup.py build
2531

32+
publish: test build
33+
@git diff-index --quiet HEAD || (echo "git has uncommitted changes. Refusing to publish." && false)
34+
awk 'BEGIN { FS = "." }; { printf("%d.%d.%d", $$1, $$2, $$3+1) }' VERSION > VERSION.incr
35+
mv VERSION.incr VERSION
36+
git add VERSION
37+
git commit -m "Update VERSION"
38+
git tag `cat VERSION`
39+
git push
40+
git push --tags
41+
python setup.py register -r pypi || (echo "Was unable to register to pypi, aborting publish." && false)
42+
python setup.py sdist upload -r pypi || (echo "Was unable to upload to pypi, publish failed." && false)
43+
@echo
44+
@echo "\033[92mSUCCESS: published v`cat VERSION` \033[0m"
45+
@echo
46+

README.rst

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Please see the examples directory. Overall, basic usage requires that a tracer g
2121
import sqlalchemy_opentracing
2222
2323
sqlalchemy_opentracing.init_tracing(tracer) # A OpenTracing compatible tracer.
24-
sqlalchemy_opentracing.register_connectable(engine) # A valid SQLAlchemy Engine object.
24+
sqlalchemy_opentracing.register_engine(engine) # A valid SQLAlchemy Engine object.
2525
2626
with engine.begin() as conn:
2727
sel = select([users])
@@ -40,6 +40,95 @@ By default, only statements marked to be traced are taken into account (explicit
4040
sel = select([users])
4141
conn.execute(sel)
4242
43+
The resulting spans will have an operation name related to the sql statement (such as `create-table` or `insert`), and will include exception information (if any), the dialect/backend (such as sqlite), and a few other hints.
44+
45+
Tracing under a Connection
46+
===========================
47+
48+
It is possible to trace all statements being executed under a connection's transaction lifetime. For this, instead of marking a statement as traced, the connection is passed to set_traced() or set_parent_span():
49+
50+
.. code-block:: python
51+
52+
parent_span = tracer.start_span('ParentSpan')
53+
conn = engine.connect()
54+
55+
with conn.begin() as trans:
56+
sqlalchemy_opentracing.set_parent_span(conn, parent_span)
57+
58+
# these three statements will be traced as children of
59+
# parent_span
60+
conn.execute(users.insert().values(name='John'))
61+
conn.execute(users.insert().values(name='Jason'))
62+
conn.execute(users.insert().values(name='Jackie'))
63+
64+
Either a commit or a rollback on a connection's transaction will finish its tracing. If the same Connection object is used afterwards, no tracing will be done for it (unless registered for tracing again). When using (emulated) nested transactions, the tracing needs to be marked at top-level transaction time, and tracing will happen for all statements under the nested transactions:
65+
66+
.. code-block:: python
67+
68+
with conn.begin() as trans:
69+
sqlalchemy_opentracing.set_parent_span(conn, parent_span)
70+
conn.execute(users.insert().values(name='John'))
71+
72+
with conn.begin() as nested_trans:
73+
# This statement will also be traced as
74+
# child of parent_span
75+
conn.execute(users.insert().values(name='Jason'))
76+
77+
78+
Tracing under a Session (ORM)
79+
=============================
80+
81+
It is also possible to trace all actual SQL statements happening during a Session's execution life time - that is, from being fresh to have its statements executed and committed (or rollbacked). For this, the Session object is passed to set_traced or set_parent_span():
82+
83+
.. code-block:: python
84+
85+
parent_span = tracer.start_span('ParentSpan')
86+
session = Session()
87+
88+
sqlalchemy_opentracing.set_parent_span(session, parent_span)
89+
try:
90+
session.add(User(name='Jackie'))
91+
session.commit()
92+
except IntegrityError:
93+
session.rollback()
94+
95+
Similar to what happens for Connection, either a commit or a rollback will finish its tracing, and further work on it will not be reported.
96+
97+
Tracing raw SQL statements
98+
==========================
99+
100+
Executing raw SQL statements can be done through either a Connection or a Session, through their execute() method. Since there's no way to mark each statement individually, tracing them can be done through either tracing all statements, or through tracing a Connection's transaction or Session:
101+
102+
.. code-block:: python
103+
104+
sqlalchemy_opentracing.set_parent_span(session, parent_span)
105+
106+
# this statement will be traced as part of the session's execution
107+
session.execute('INSERT INTO users VALUES (?, ?)', 1, 'John')
108+
109+
110+
Raw SQL statements will be traced having its operation name as `textclause`, to indicate their explicit text nature.
111+
112+
Manually cancel tracing
113+
=======================
114+
115+
Sometimes no commit nor rollback may happen for a Connection or Session (for example, when doing bulk insertion/update). In this case, manually canceling tracing for an object can be done through clear_traced():
116+
117+
.. code-block:: python
118+
119+
parent_span = tracer.start_span('ParentSpan')
120+
session = Session()
121+
122+
sqlalchemy_opentracing.set_parent_span(session, parent_span)
123+
124+
# this will generate tracing of a single INSERT statement.
125+
users = [User(name = 'User-%s' % i) for i in xrange(100)]
126+
session.bulk_save_objects(users)
127+
128+
sqlalchemy_opentracing.clear_traced(session)
129+
130+
Manually canceling tracing will not clear any tracing already done - it will simply stop any further tracing for the current statement, Connection or Session object.
131+
43132
Further information
44133
===================
45134

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.0
1+
0.1.1

examples/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## Examples
2+
3+
This directory contains examples of tracing applications using the sqlalchemy package. To run the examples, make sure you've installed the packages `opentracing` and `lightstep`. If you have a lightstep token and would like to view the created spans, then uncomment to proper lines under the given examples. If you would like to use a different OpenTracing implementation, you may also replace the lightstep tracer with the tracer of your choice.
4+
5+
Then simply:
6+
7+
```
8+
> python example-file.py
9+
```
10+

examples/core-childspans.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
conn = engine.connect()
2222

2323
sqlalchemy_opentracing.init_tracing(tracer)
24-
sqlalchemy_opentracing.register_connectable(engine)
24+
sqlalchemy_opentracing.register_engine(engine)
2525

2626
span = tracer.start_span('create sample')
2727

examples/core-connection.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from sqlalchemy import MetaData, Table, Integer, String, Column, create_engine
2+
from sqlalchemy.schema import CreateTable
3+
4+
import lightstep
5+
import sqlalchemy_opentracing
6+
7+
tracer = lightstep.Tracer(
8+
component_name='sqlalchemy-conn',
9+
access_token='{your_lightstep_token}'
10+
)
11+
12+
if __name__ == '__main__':
13+
engine = create_engine('sqlite:///:memory:')
14+
15+
sqlalchemy_opentracing.init_tracing(tracer)
16+
sqlalchemy_opentracing.register_engine(engine)
17+
18+
metadata = MetaData()
19+
users = Table('users', metadata,
20+
Column('id', Integer, primary_key=True),
21+
Column('name', String),
22+
)
23+
creat = CreateTable(users)
24+
ins = users.insert().values(name='John Doe')
25+
26+
# All statements during this transaction will be traced.
27+
with engine.begin() as conn:
28+
sqlalchemy_opentracing.set_traced(conn)
29+
conn.execute(creat)
30+
conn.execute(ins)
31+
32+
tracer.flush()
33+

examples/core-simple.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
engine = create_engine('sqlite:///:memory:')
1414

1515
sqlalchemy_opentracing.init_tracing(tracer)
16-
sqlalchemy_opentracing.register_connectable(engine)
16+
sqlalchemy_opentracing.register_engine(engine)
1717

1818
metadata = MetaData()
1919
users = Table('users', metadata,

examples/orm-bulk.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
from sqlalchemy import MetaData, Table, Integer, String, Column, create_engine
3+
from sqlalchemy.ext.declarative import declarative_base
4+
from sqlalchemy.orm import sessionmaker
5+
6+
import lightstep
7+
import sqlalchemy_opentracing
8+
9+
DB_LOCATION = '/tmp/simple.db'
10+
11+
tracer = lightstep.Tracer(
12+
component_name='sqlalchemy-orm-bulk',
13+
access_token='{your_lightstep_token}'
14+
)
15+
16+
Base = declarative_base()
17+
18+
class User(Base):
19+
__tablename__ = 'users'
20+
21+
id = Column(Integer, primary_key=True)
22+
name = Column(String)
23+
24+
if __name__ == '__main__':
25+
if os.path.exists(DB_LOCATION):
26+
os.remove(DB_LOCATION) # cleanup
27+
28+
engine = create_engine('sqlite:///%s' % DB_LOCATION)
29+
session = sessionmaker(bind=engine)()
30+
31+
sqlalchemy_opentracing.init_tracing(tracer)
32+
sqlalchemy_opentracing.register_engine(engine)
33+
34+
User.metadata.create_all(engine)
35+
36+
# Register the session for the current transaction.
37+
sqlalchemy_opentracing.set_traced(session)
38+
39+
# Insert a set of rows.
40+
users = [User(name = 'User-%s' % i) for i in xrange(100)]
41+
session.bulk_save_objects(users)
42+
43+
# Bulk saves objects without intermmediate steps,
44+
# so explicitly stop tracing the session.
45+
sqlalchemy_opentracing.clear_traced(session)
46+

examples/orm-childspan.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class User(Base):
2929
session = sessionmaker(bind=engine)()
3030

3131
sqlalchemy_opentracing.init_tracing(tracer)
32-
sqlalchemy_opentracing.register_connectable(engine)
32+
sqlalchemy_opentracing.register_engine(engine)
3333

3434
User.metadata.create_all(engine)
3535

examples/orm-simple.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class User(Base):
2929
session = sessionmaker(bind=engine)()
3030

3131
sqlalchemy_opentracing.init_tracing(tracer)
32-
sqlalchemy_opentracing.register_connectable(engine)
32+
sqlalchemy_opentracing.register_engine(engine)
3333

3434
User.metadata.create_all(engine)
3535

0 commit comments

Comments
 (0)