def __init__(self, argv): args = self._get_base_parser().parse_args(argv) opts.set_defaults(cfg.CONF) if not (args.os_auth_token and args.ceilometer_url): if not args.os_username: raise exc.CommandError( "You must provide a username via either --os-username or " "via env[OS_USERNAME]") if not args.os_password: raise exc.CommandError( "You must provide a password via either --os-password or " "via env[OS_PASSWORD]") if self._no_project_and_domain_set(args): # steer users towards Keystone V3 API raise exc.CommandError( "You must provide a project_id via either --os-project-id " "or via env[OS_PROJECT_ID] and a domain_name via either " "--os-user-domain-name or via env[OS_USER_DOMAIN_NAME] or " "a domain_id via either --os-user-domain-id or via " "env[OS_USER_DOMAIN_ID]") if not args.os_auth_url: raise exc.CommandError( "You must provide an auth url via either --os-auth-url or " "via env[OS_AUTH_URL]") args.func(args)
def list(self, args): """List all traces""" if not args.conn_str: raise exc.CommandError( "You must provide connection string via" " either --connection-string or " "via env[OSPROFILER_CONNECTION_STRING]") try: engine = base.get_driver(args.conn_str, **args.__dict__) except Exception as e: raise exc.CommandError(e.message) fields = ("base_id", "timestamp") pretty_table = prettytable.PrettyTable(fields) pretty_table.align = "l" timeformat = '%Y-%m-%dT%H:%M:%S.%f' if args.since: since = datetime.datetime.strptime( args.since, timeformat) else: since = datetime.datetime.fromtimestamp(0) if not args.error_trace: traces = engine.list_traces(fields) else: traces = engine.list_error_traces() for trace in traces: if since > datetime.datetime.strptime( trace['timestamp'], timeformat): continue row = [trace[field] for field in fields] pretty_table.add_row(row) if six.PY3: print(encodeutils.safe_encode(pretty_table.get_string()).decode()) else: print(encodeutils.safe_encode(pretty_table.get_string()))
def show(self, args): """Display trace results in HTML, JSON or DOT format.""" trace = None if not uuidutils.is_uuid_like(args.trace): trace = json.load(open(args.trace)) else: try: engine = base.get_driver(args.conn_str, **args.__dict__) except Exception as e: raise exc.CommandError(e.message) trace = engine.get_report(args.trace) if not trace or not trace.get("children"): msg = ("Trace with UUID %s not found. Please check the HMAC key " "used in the command." % args.trace) raise exc.CommandError(msg) # NOTE(ayelistratov): Ceilometer translates datetime objects to # strings, other drivers store this data in ISO Date format. # Since datetime.datetime is not JSON serializable by default, # this method will handle that. def datetime_json_serialize(obj): if hasattr(obj, "isoformat"): return obj.isoformat() else: return obj if args.use_json: output = json.dumps(trace, default=datetime_json_serialize, separators=(",", ": "), indent=2) elif args.use_html: with open(os.path.join(os.path.dirname(__file__), "template.html")) as html_template: output = html_template.read().replace( "$DATA", json.dumps(trace, indent=4, separators=(",", ": "), default=datetime_json_serialize)) if args.local_libs: output = output.replace("$LOCAL", "true") else: output = output.replace("$LOCAL", "false") elif args.use_dot: dot_graph = self._create_dot_graph(trace) output = dot_graph.source if args.render_dot_filename: dot_graph.render(args.render_dot_filename, cleanup=True) else: raise exc.CommandError("You should choose one of the following " "output formats: json, html or dot.") if args.file_name: with open(args.file_name, "w+") as output_file: output_file.write(output) else: print(output)
def __init__(self, connection_str, db=0, project=None, service=None, host=None, conf=cfg.CONF, **kwargs): """Redis driver for OSProfiler.""" super(Redis, self).__init__(connection_str, project=project, service=service, host=host, conf=conf, **kwargs) 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'.") # only connection over network is supported with schema # redis://[:password]@host[:port][/db] self.db = StrictRedis.from_url(self.connection_str) self.namespace = "osprofiler:" self.namespace_error = "osprofiler_error:"
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, conf=conf, **kwargs) 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))], password=parsed_url.password, socket_timeout=socket_timeout) self.db = sentinel.master_for(self.conf.profiler.sentinel_service_name, socket_timeout=socket_timeout)
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:"
def __init__(self, connection_str, index_name="osprofiler-notifications", project=None, service=None, host=None, conf=cfg.CONF, **kwargs): """Elasticsearch driver for OSProfiler.""" super(ElasticsearchDriver, self).__init__(connection_str, project=project, service=service, host=host, conf=conf, **kwargs) try: from elasticsearch import Elasticsearch except ImportError: raise exc.CommandError( "To use this command, you should install " "'elasticsearch' manually. Use command:\n " "'pip install elasticsearch'.") client_url = parser.urlunparse(parser.urlparse(self.connection_str) ._replace(scheme="http")) self.conf = conf self.client = Elasticsearch(client_url) self.index_name = index_name self.index_name_error = "osprofiler-notifications-error"
def __init__(self, connection_str, db=0, project=None, service=None, host=None, conf=cfg.CONF, **kwargs): """Redis driver for OSProfiler.""" super(Redis, self).__init__(connection_str, project=project, service=service, host=host, conf=conf, **kwargs) try: from redis import StrictRedis except ImportError: raise exc.CommandError( "To use OSProfiler with Redis driver, " "please install `redis` library. " "To install with pip:\n `pip install redis`.") # only connection over network is supported with schema # redis://[:password]@host[:port][/db] self.db = StrictRedis.from_url(self.connection_str) self.namespace_opt = "osprofiler_opt:" self.namespace = "osprofiler:" # legacy self.namespace_error = "osprofiler_error:"
def __init__(self, connection_str, project=None, service=None, host=None, conf=cfg.CONF, **kwargs): """Jaeger driver for OSProfiler.""" super(Jaeger, self).__init__(connection_str, project=project, service=service, host=host, conf=conf, **kwargs) try: import jaeger_client self.jaeger_client = jaeger_client except ImportError: raise exc.CommandError( "To use OSProfiler with Uber Jaeger tracer, " "you have to install `jaeger-client` manually. " "Install with pip:\n `pip install jaeger-client`." ) parsed_url = parser.urlparse(connection_str) cfg = { "local_agent": { "reporting_host": parsed_url.hostname, "reporting_port": parsed_url.port, } } # Initialize tracer for each profiler service_name = "{}-{}".format(project, service) config = jaeger_client.Config(cfg, service_name=service_name) self.tracer = config.initialize_tracer() self.spans = collections.deque()
def __init__(self, connection_str, index_name="osprofiler-notifications", project=None, service=None, host=None, conf=cfg.CONF, **kwargs): """Elasticsearch driver for OSProfiler.""" super(ElasticsearchDriver, self).__init__(connection_str, project=project, service=service, host=host, conf=conf, **kwargs) try: from elasticsearch import Elasticsearch except ImportError: raise exc.CommandError( "To use OSProfiler with ElasticSearch driver, " "please install `elasticsearch` library. " "To install with pip:\n `pip install elasticsearch`.") client_url = parser.urlunparse( parser.urlparse(self.connection_str)._replace(scheme="http")) self.conf = conf self.client = Elasticsearch(client_url) self.index_name = index_name self.index_name_error = "osprofiler-notifications-error"
def db_conn(self): try: from pymongo import MongoClient except ImportError: raise exc.CommandError("To use this command, you should install " "'pymongo' manually. Use command:\n " "'pip install pymongo'.") client = MongoClient(self.connection_str, connect=False) self.db = client['osprofiler']
def __init__(self, connection_str, **kwargs): """Driver receiving profiled information from ceilometer.""" super(Ceilometer, self).__init__(connection_str) try: import ceilometerclient.client except ImportError: raise exc.CommandError( "To use this command, you should install " "'ceilometerclient' manually. Use command:\n " "'pip install python-ceilometerclient'.") try: self.client = ceilometerclient.client.get_client( kwargs["ceilometer_api_version"], **kwargs) except Exception as e: if hasattr(e, "http_status") and e.http_status == 401: msg = "Invalid OpenStack Identity credentials." else: msg = "Error occurred while connecting to Ceilometer: %s." % e raise exc.CommandError(msg)
def list(self, args): """List all traces""" if not args.conn_str: raise exc.CommandError( "You must provide connection string via" " either --connection-string or " "via env[OSPROFILER_CONNECTION_STRING]") try: engine = base.get_driver(args.conn_str, **args.__dict__) except Exception as e: raise exc.CommandError(e.message) fields = ("base_id", "timestamp") pretty_table = prettytable.PrettyTable(fields) pretty_table.align = "l" if not args.error_trace: traces = engine.list_traces(fields) else: traces = engine.list_error_traces() for trace in traces: row = [trace[field] for field in fields] pretty_table.add_row(row) print(encodeutils.safe_encode(pretty_table.get_string()).decode())
def __init__(self, connection_str, db_name="osprofiler", project=None, service=None, host=None, **kwargs): """MongoDB driver for OSProfiler.""" super(MongoDB, self).__init__(connection_str, project=project, service=service, host=host, **kwargs) try: from pymongo import MongoClient except ImportError: raise exc.CommandError( "To use this command, you should install " "'pymongo' manually. Use command:\n " "'pip install pymongo'.") client = MongoClient(self.connection_str, connect=False) self.db = client[db_name]
def list_traces(self, fields=None): try: from sqlalchemy.sql import select except ImportError: raise exc.CommandError( "To use this command, you should install 'SQLAlchemy'") stmt = select([self._data_table]) seen_ids = set() result = [] traces = self._conn.execute(stmt).fetchall() for trace in traces: if trace["base_id"] not in seen_ids: seen_ids.add(trace["base_id"]) result.append({ key: value for key, value in trace.items() if key in fields }) return result
def list(self, args): """List all traces""" try: engine = base.get_driver(args.conn_str, **args.__dict__) except Exception as e: raise exc.CommandError(e.message) fields = ("base_id", "timestamp") pretty_table = prettytable.PrettyTable(fields) pretty_table.align = "l" if not args.error_trace: traces = engine.list_traces(fields) else: traces = engine.list_error_traces() for trace in traces: row = [trace[field] for field in fields] pretty_table.add_row(row) if six.PY3: print(encodeutils.safe_encode(pretty_table.get_string()).decode()) else: print(encodeutils.safe_encode(pretty_table.get_string()))
def get_report(self, base_id): try: from sqlalchemy.sql import select except ImportError: raise exc.CommandError( "To use this command, you should install 'SQLAlchemy'") stmt = select([self._data_table ]).where(self._data_table.c.base_id == base_id) results = self._conn.execute(stmt).fetchall() for n in results: timestamp = n["timestamp"] trace_id = n["trace_id"] parent_id = n["parent_id"] name = n["name"] project = n["project"] service = n["service"] host = n["host"] data = jsonutils.loads(n["data"]) self._append_results(trace_id, parent_id, name, project, service, host, timestamp, data) return self._parse_results()
def _create_dot_graph(self, trace): try: import graphviz except ImportError: raise exc.CommandError( "graphviz library is required to use this option.") dot = graphviz.Digraph(format="pdf") next_id = [0] def _create_node(info): time_taken = info["finished"] - info["started"] service = info["service"] + ":" if "service" in info else "" name = info["name"] label = "%s%s - %d ms" % (service, name, time_taken) if name == "wsgi": req = info["meta.raw_payload.wsgi-start"]["info"]["request"] label = "%s\\n%s %s.." % (label, req["method"], req["path"][:30]) elif name == "rpc" or name == "driver": raw = info["meta.raw_payload.%s-start" % name] fn_name = raw["info"]["function"]["name"] label = "%s\\n%s" % (label, fn_name.split(".")[-1]) node_id = str(next_id[0]) next_id[0] += 1 dot.node(node_id, label) return node_id def _create_sub_graph(root): rid = _create_node(root["info"]) for child in root["children"]: cid = _create_sub_graph(child) dot.edge(rid, cid) return rid _create_sub_graph(trace) return dot
def __init__(self, connection_str, db_name="osprofiler", project=None, service=None, host=None, **kwargs): """MongoDB driver for OSProfiler.""" super(MongoDB, self).__init__(connection_str, project=project, service=service, host=host, **kwargs) try: from pymongo import MongoClient except ImportError: raise exc.CommandError( "To use OSProfiler with MongoDB driver, " "please install `pymongo` library. " "To install with pip:\n `pip install pymongo`.") client = MongoClient(self.connection_str, connect=False) self.db = client[db_name]
def show(self, args): """Display trace results in HTML, JSON or DOT format.""" trace = None if not uuidutils.is_uuid_like(args.trace): trace = json.load(open(args.trace)) else: try: engine = base.get_driver(args.conn_str, **args.__dict__) except Exception as e: raise exc.CommandError(e.message) trace = engine.get_report(args.trace) if not trace or not trace.get("children"): msg = ("Trace with UUID %s not found. " "There are 3 possible reasons: \n" " 1) You are using not admin credentials\n" " 2) You specified wrong trace id\n" " 3) You specified wrong HMAC Key in original calling\n" " 4) Ceilometer didn't enable profiler notification topic" % args.trace) raise exc.CommandError(msg) # NOTE(ayelistratov): Ceilometer translates datetime objects to # strings, other drivers store this data in ISO Date format. # Since datetime.datetime is not JSON serializable by default, # this method will handle that. def datetime_json_serialize(obj): if hasattr(obj, "isoformat"): return obj.isoformat() else: return obj if args.use_json: output = json.dumps(trace, default=datetime_json_serialize, indent=2) elif args.use_html: with open(os.path.join(os.path.dirname(__file__), "template.html")) as html_template: output = html_template.read().replace( "$DATA", json.dumps(trace, indent=4, default=datetime_json_serialize)) elif args.use_dot: dot_graph = self._create_dot_graph(trace) output = dot_graph.source if args.render_dot_filename: dot_graph.render(args.render_dot_filename, cleanup=True) else: raise exc.CommandError("You should choose one of the following " "output formats: json, html or dot.") if args.file_name: with open(args.file_name, "w+") as output_file: output_file.write(output) else: print(output)
def test_shell_main(self, mock_shell): mock_shell.side_effect = exc.CommandError("some_message") shell.main() self.assertEqual("some_message\n", sys.stdout.getvalue())