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
|
"""
This is an example of a library written to work with opentracing-python. It
provides a simple caching decorator backed by Redis, and uses the OpenTracing
Redis integration to automatically generate spans for each call to Redis.
"""
import pickle
from functools import wraps
# FIXME The pylint disablings are needed here because the code of this
# example is being executed against the tox.ini of the main
# opentelemetry-python project. Find a way to separate the two.
import redis # pylint: disable=import-error
import redis_opentracing # pylint: disable=import-error
class RedisCache:
"""Redis-backed caching decorator, using OpenTracing!
Args:
tracer: an opentracing.tracer.Tracer
"""
def __init__(self, tracer):
redis_opentracing.init_tracing(tracer)
self.tracer = tracer
self.client = redis.StrictRedis()
def __call__(self, func):
@wraps(func)
def inner(*args, **kwargs):
with self.tracer.start_active_span("Caching decorator") as scope1:
# Pickle the call args to get a canonical key. Don't do this in
# prod!
key = pickle.dumps((func.__qualname__, args, kwargs))
pval = self.client.get(key)
if pval is not None:
val = pickle.loads(pval)
scope1.span.log_kv(
{"msg": "Found cached value", "val": val}
)
return val
scope1.span.log_kv({"msg": "Cache miss, calling function"})
with self.tracer.start_active_span(
f'Call "{func.__name__}"'
) as scope2:
scope2.span.set_tag("func", func.__name__)
scope2.span.set_tag("args", str(args))
scope2.span.set_tag("kwargs", str(kwargs))
val = func(*args, **kwargs)
scope2.span.set_tag("val", str(val))
# Let keys expire after 10 seconds
self.client.setex(key, 10, pickle.dumps(val))
return val
return inner
|