From 94b0770491ee6c6b11a5c8275d0a0221ce30a392 Mon Sep 17 00:00:00 2001 From: Kyle Verhoog Date: Thu, 30 Jun 2022 16:21:54 -0400 Subject: [PATCH] fix(flask-caching): support v2.0 (#3882) ## Description flask-caching released version 2.0 which moves the cache client to a new library called [`cachelib`](https://github.com/pallets-eco/cachelib). Diff here: https://github.com/pallets-eco/flask-caching/compare/v1.10.0...v2.0.0 This breaks our logic which collects tags for the redis client. ## Fix It was noticed that both `_write_client` and `_read_client` use the same connection information so we don't need to dynamically check for each. Also [`_read_clients`](https://github.com/pallets-eco/flask-caching/blob/ac13e01baa11d65c68dcba64f99ccaafd9b5419c/src/flask_caching/backends/rediscache.py#L62) was moved to [`_read_client`](https://github.com/pallets-eco/cachelib/blob/13c8bf8db156dd06154f5e08e23bdd9e73480a5b/src/cachelib/redis.py#L29) when the logic was moved to `cachelib`. --- ddtrace/contrib/flask_cache/tracers.py | 22 ++++++++++++------- ddtrace/contrib/flask_cache/utils.py | 9 ++++++-- .../notes/flask_caching-dc23b94171041b4f.yaml | 4 ++++ 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 releasenotes/notes/flask_caching-dc23b94171041b4f.yaml diff --git a/ddtrace/contrib/flask_cache/tracers.py b/ddtrace/contrib/flask_cache/tracers.py index d1c623cfb78..9a7ed1ec3a2 100644 --- a/ddtrace/contrib/flask_cache/tracers.py +++ b/ddtrace/contrib/flask_cache/tracers.py @@ -3,6 +3,7 @@ """ import logging +import typing from ddtrace import config @@ -14,6 +15,10 @@ from .utils import _resource_from_cache_prefix +if typing.TYPE_CHECKING: + from ddtrace import Span + + log = logging.Logger(__name__) DEFAULT_SERVICE = config.service or "flask-cache" @@ -55,7 +60,8 @@ class TracedCache(cache_cls): _datadog_service = service _datadog_meta = meta - def __trace(self, cmd, write=False): + def __trace(self, cmd): + # type: (str, bool) -> Span """ Start a tracing with default attributes and tags """ @@ -68,7 +74,7 @@ def __trace(self, cmd, write=False): # set analytics sample rate s.set_tag(ANALYTICS_SAMPLE_RATE_KEY, config.flask_cache.get_analytics_sample_rate()) # add connection meta if there is one - client = _extract_client(self.cache, write=write) + client = _extract_client(self.cache) if client is not None: try: s.set_tags(_extract_conn_tags(client)) @@ -91,7 +97,7 @@ def set(self, *args, **kwargs): """ Track ``set`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("SET", self.config) if len(args) > 0: span.set_tag(COMMAND_KEY, args[0]) @@ -101,7 +107,7 @@ def add(self, *args, **kwargs): """ Track ``add`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("ADD", self.config) if len(args) > 0: span.set_tag(COMMAND_KEY, args[0]) @@ -111,7 +117,7 @@ def delete(self, *args, **kwargs): """ Track ``delete`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("DELETE", self.config) if len(args) > 0: span.set_tag(COMMAND_KEY, args[0]) @@ -121,7 +127,7 @@ def delete_many(self, *args, **kwargs): """ Track ``delete_many`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("DELETE_MANY", self.config) span.set_tag(COMMAND_KEY, list(args)) return super(TracedCache, self).delete_many(*args, **kwargs) @@ -130,7 +136,7 @@ def clear(self, *args, **kwargs): """ Track ``clear`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("CLEAR", self.config) return super(TracedCache, self).clear(*args, **kwargs) @@ -147,7 +153,7 @@ def set_many(self, *args, **kwargs): """ Track ``set_many`` operation """ - with self.__trace("flask_cache.cmd", write=True) as span: + with self.__trace("flask_cache.cmd") as span: span.resource = _resource_from_cache_prefix("SET_MANY", self.config) if len(args) > 0: span.set_tag(COMMAND_KEY, list(args[0].keys())) diff --git a/ddtrace/contrib/flask_cache/utils.py b/ddtrace/contrib/flask_cache/utils.py index 27a8f221522..b121b0c793f 100644 --- a/ddtrace/contrib/flask_cache/utils.py +++ b/ddtrace/contrib/flask_cache/utils.py @@ -17,14 +17,19 @@ def _resource_from_cache_prefix(resource, cache): return name.lower() -def _extract_client(cache, write=False): +def _extract_client(cache): """ Get the client from the cache instance according to the current operation """ client = getattr(cache, "_client", None) if client is None: # flask-caching has _read_clients & _write_client for the redis backend - client = getattr(cache, "_write_client" if write else "_read_clients", None) + # These use the same connection so just try to get a reference to one of them. + # flask-caching < 2.0.0 uses _read_clients so look for that one too. + for attr in ("_write_client", "_read_client", "_read_clients"): + client = getattr(cache, attr, None) + if client is not None: + break return client diff --git a/releasenotes/notes/flask_caching-dc23b94171041b4f.yaml b/releasenotes/notes/flask_caching-dc23b94171041b4f.yaml new file mode 100644 index 00000000000..ccc09f251bb --- /dev/null +++ b/releasenotes/notes/flask_caching-dc23b94171041b4f.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + flask_caching: fix redis tagging after the v2.0 release.