File: rediscache.py

package info (click to toggle)
python-opentelemetry 1.39.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,952 kB
  • sloc: python: 53,083; sh: 398; makefile: 142; sql: 39
file content (60 lines) | stat: -rw-r--r-- 2,155 bytes parent folder | download
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