Skip to content

Commit ae484cb

Browse files
c24tocelotlOberon00mauriciovasquezbernal
authored
Add OpenTracing shim example (open-telemetry#282)
Co-authored-by: Diego Hurtado <ocelotl@users.noreply.github.com> Co-authored-by: Christian Neumüller <christian+github@neumueller.me> Co-authored-by: Mauricio Vásquez <mauricio@kinvolk.io>
1 parent 9ec1f1f commit ae484cb

File tree

8 files changed

+203
-1
lines changed

8 files changed

+203
-1
lines changed

examples/opentracing/README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Overview
2+
3+
This example shows how to use the [`opentelemetry-ext-opentracing-shim`
4+
package](https://github.com/open-telemetry/opentelemetry-python/tree/master/ext/opentelemetry-ext-opentracing-shim)
5+
to interact with libraries instrumented with
6+
[`opentracing-python`](https://github.com/opentracing/opentracing-python).
7+
8+
The included `rediscache` library creates spans via the OpenTracing Redis
9+
integration,
10+
[`redis_opentracing`](https://github.com/opentracing-contrib/python-redis).
11+
Spans are exported via the Jaeger exporter, which is attached to the
12+
OpenTelemetry tracer.
13+
14+
## Installation
15+
16+
### Jaeger
17+
18+
Install and run
19+
[Jaeger](https://www.jaegertracing.io/docs/latest/getting-started/#all-in-one).
20+
See the [basic tracer
21+
example](https://github.com/open-telemetry/opentelemetry-python/tree/master/examples/basic-tracer)
22+
for more detail.
23+
24+
### Redis
25+
26+
Install Redis following the [instructions](https://redis.io/topics/quickstart).
27+
28+
Make sure that the Redis server is running by executing this:
29+
30+
```sh
31+
$ redis-server
32+
```
33+
34+
### Python Dependencies
35+
36+
Install the Python dependencies in [`requirements.txt`](requirements.txt):
37+
38+
```sh
39+
$ pip install -r requirements.txt
40+
```
41+
42+
Alternatively, you can install the Python dependencies separately:
43+
44+
```sh
45+
$ pip install \
46+
opentelemetry-api \
47+
opentelemetry-sdk \
48+
opentelemetry-ext-jaeger \
49+
opentelemetry-opentracing-shim \
50+
redis \
51+
redis_opentracing
52+
```
53+
54+
## Run the Application
55+
56+
The example script calculates a few Fibonacci numbers and stores the results in
57+
Redis. The script, the `rediscache` library, and the OpenTracing Redis
58+
integration all contribute spans to the trace.
59+
60+
To run the script:
61+
62+
```sh
63+
$ python main.py
64+
```
65+
66+
After running, you can view the generated trace in the Jaeger UI.
67+
68+
#### Jaeger UI
69+
70+
Open the Jaeger UI in your browser at
71+
<http://localhost:16686> and view traces for the
72+
"OpenTracing Shim Example" service.
73+
74+
Each `main.py` run should generate a trace, and each trace should include
75+
multiple spans that represent calls to Redis.
76+
77+
<p align="center"><img src="./images/jaeger-trace-full.png?raw=true"/></p>
78+
79+
Note that tags and logs (OpenTracing) and attributes and events (OpenTelemetry)
80+
from both tracing systems appear in the exported trace.
81+
82+
<p align="center"><img src="./images/jaeger-span-expanded.png?raw=true"/></p>
83+
84+
## Useful links
85+
- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
86+
- For more information on tracing in Python, visit: <https://github.com/open-telemetry/opentelemetry-python>
87+
88+
## LICENSE
89+
90+
Apache License 2.0

examples/opentracing/__init__.py

Whitespace-only changes.
Loading
Loading

examples/opentracing/main.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python
2+
3+
from opentelemetry import trace
4+
from opentelemetry.ext import opentracing_shim
5+
from opentelemetry.ext.jaeger import JaegerSpanExporter
6+
from opentelemetry.sdk.trace import TracerSource
7+
from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor
8+
from rediscache import RedisCache
9+
10+
# Configure the tracer using the default implementation
11+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
12+
tracer_source = trace.tracer_source()
13+
14+
# Configure the tracer to export traces to Jaeger
15+
jaeger_exporter = JaegerSpanExporter(
16+
service_name="OpenTracing Shim Example",
17+
agent_host_name="localhost",
18+
agent_port=6831,
19+
)
20+
span_processor = SimpleExportSpanProcessor(jaeger_exporter)
21+
tracer_source.add_span_processor(span_processor)
22+
23+
# Create an OpenTracing shim. This implements the OpenTracing tracer API, but
24+
# forwards calls to the underlying OpenTelemetry tracer.
25+
opentracing_tracer = opentracing_shim.create_tracer(tracer_source)
26+
27+
# Our example caching library expects an OpenTracing-compliant tracer.
28+
redis_cache = RedisCache(opentracing_tracer)
29+
30+
# Appication code uses an OpenTelemetry Tracer as usual.
31+
tracer = trace.tracer_source().get_tracer(__name__)
32+
33+
34+
@redis_cache
35+
def fib(number):
36+
"""Get the Nth Fibonacci number, cache intermediate results in Redis."""
37+
if number < 0:
38+
raise ValueError
39+
if number in (0, 1):
40+
return number
41+
return fib(number - 1) + fib(number - 2)
42+
43+
44+
with tracer.start_as_current_span("Fibonacci") as span:
45+
span.set_attribute("is_example", "yes :)")
46+
fib(4)

examples/opentracing/rediscache.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
This is an example of a library written to work with opentracing-python. It
3+
provides a simple caching decorator backed by Redis, and uses the OpenTracing
4+
Redis integration to automatically generate spans for each call to Redis.
5+
"""
6+
7+
import pickle
8+
from functools import wraps
9+
10+
# FIXME The pylint disablings are needed here because the code of this
11+
# example is being executed against the tox.ini of the main
12+
# opentelemetry-python project. Find a way to separate the two.
13+
import redis # pylint: disable=import-error
14+
import redis_opentracing # pylint: disable=import-error
15+
16+
17+
class RedisCache:
18+
"""Redis-backed caching decorator, using OpenTracing!
19+
20+
Args:
21+
tracer: an opentracing.tracer.Tracer
22+
"""
23+
24+
def __init__(self, tracer):
25+
redis_opentracing.init_tracing(tracer)
26+
self.tracer = tracer
27+
self.client = redis.StrictRedis()
28+
29+
def __call__(self, func):
30+
@wraps(func)
31+
def inner(*args, **kwargs):
32+
with self.tracer.start_active_span("Caching decorator") as scope1:
33+
34+
# Pickle the call args to get a canonical key. Don't do this in
35+
# prod!
36+
key = pickle.dumps((func.__qualname__, args, kwargs))
37+
38+
pval = self.client.get(key)
39+
if pval is not None:
40+
val = pickle.loads(pval)
41+
scope1.span.log_kv(
42+
{"msg": "Found cached value", "val": val}
43+
)
44+
return val
45+
46+
scope1.span.log_kv({"msg": "Cache miss, calling function"})
47+
with self.tracer.start_active_span(
48+
'Call "{}"'.format(func.__name__)
49+
) as scope2:
50+
scope2.span.set_tag("func", func.__name__)
51+
scope2.span.set_tag("args", str(args))
52+
scope2.span.set_tag("kwargs", str(kwargs))
53+
54+
val = func(*args, **kwargs)
55+
scope2.span.set_tag("val", str(val))
56+
57+
# Let keys expire after 10 seconds
58+
self.client.setex(key, 10, pickle.dumps(val))
59+
return val
60+
61+
return inner

examples/opentracing/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
opentelemetry-api
2+
opentelemetry-sdk
3+
opentelemetry-ext-jaeger
4+
opentelemetry-opentracing-shim
5+
redis
6+
redis_opentracing

ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,6 @@ def test_inject_text_map(self):
489489

490490
# Verify Format.TEXT_MAP
491491
text_map = {}
492-
493492
self.shim.inject(context, opentracing.Format.TEXT_MAP, text_map)
494493
self.assertEqual(text_map[MockHTTPTextFormat.TRACE_ID_KEY], str(1220))
495494
self.assertEqual(text_map[MockHTTPTextFormat.SPAN_ID_KEY], str(7478))

0 commit comments

Comments
 (0)