diff options
Diffstat (limited to 'osprofiler/drivers/redis_driver.py')
-rw-r--r-- | osprofiler/drivers/redis_driver.py | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/osprofiler/drivers/redis_driver.py b/osprofiler/drivers/redis_driver.py new file mode 100644 index 0000000..f3f5812 --- /dev/null +++ b/osprofiler/drivers/redis_driver.py @@ -0,0 +1,137 @@ +# Copyright 2016 Mirantis Inc. +# Copyright 2016 IBM Corporation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_config import cfg +from oslo_serialization import jsonutils +import six.moves.urllib.parse as parser + +from osprofiler.drivers import base +from osprofiler import exc + + +class Redis(base.Driver): + def __init__(self, connection_str, db=0, project=None, + service=None, host=None, **kwargs): + """Redis driver for OSProfiler.""" + + super(Redis, self).__init__(connection_str, project=project, + service=service, host=host) + try: + from redis import StrictRedis + except ImportError: + raise exc.CommandError( + "To use this command, you should install " + "'redis' manually. Use command:\n " + "'pip install redis'.") + + parsed_url = parser.urlparse(self.connection_str) + self.db = StrictRedis(host=parsed_url.hostname, + port=parsed_url.port, + db=db) + self.namespace = "osprofiler:" + + @classmethod + def get_name(cls): + return "redis" + + def notify(self, info): + """Send notifications to Redis. + + :param info: Contains information about trace element. + In payload dict there are always 3 ids: + "base_id" - uuid that is common for all notifications + related to one trace. Used to simplify + retrieving of all trace elements from + Redis. + "parent_id" - uuid of parent element in trace + "trace_id" - uuid of current element in trace + + With parent_id and trace_id it's quite simple to build + tree of trace elements, which simplify analyze of trace. + + """ + data = info.copy() + data["project"] = self.project + data["service"] = self.service + key = self.namespace + data["base_id"] + "_" + data["trace_id"] + "_" + \ + data["timestamp"] + self.db.set(key, jsonutils.dumps(data)) + + def list_traces(self, query="*", fields=[]): + """Returns array of all base_id fields that match the given criteria + + :param query: string that specifies the query criteria + :param fields: iterable of strings that specifies the output fields + """ + for base_field in ["base_id", "timestamp"]: + if base_field not in fields: + fields.append(base_field) + ids = self.db.scan_iter(match=self.namespace + query) + traces = [jsonutils.loads(self.db.get(i)) for i in ids] + result = [] + for trace in traces: + result.append({key: value for key, value in trace.iteritems() + if key in fields}) + return result + + def get_report(self, base_id): + """Retrieves and parses notification from Redis. + + :param base_id: Base id of trace elements. + """ + for key in self.db.scan_iter(match=self.namespace + base_id + "*"): + data = self.db.get(key) + n = jsonutils.loads(data) + trace_id = n["trace_id"] + parent_id = n["parent_id"] + name = n["name"] + project = n["project"] + service = n["service"] + host = n["info"]["host"] + timestamp = n["timestamp"] + + self._append_results(trace_id, parent_id, name, project, service, + host, timestamp, n) + + return self._parse_results() + + +class RedisSentinel(Redis, base.Driver): + def __init__(self, connection_str, db=0, project=None, + service=None, host=None, conf=cfg.CONF, **kwargs): + """Redis driver for OSProfiler.""" + + super(RedisSentinel, self).__init__(connection_str, project=project, + service=service, host=host) + try: + from redis.sentinel import Sentinel + except ImportError: + raise exc.CommandError( + "To use this command, you should install " + "'redis' manually. Use command:\n " + "'pip install redis'.") + + self.conf = conf + socket_timeout = self.conf.profiler.socket_timeout + parsed_url = parser.urlparse(self.connection_str) + sentinel = Sentinel([(parsed_url.hostname, int(parsed_url.port))], + socket_timeout=socket_timeout) + self.db = sentinel.master_for(self.conf.profiler.sentinel_service_name, + socket_timeout=socket_timeout) + + @classmethod + def get_name(cls): + return "redissentinel" |