def _append_ceilometer_args(self, parent_parser): parser = parent_parser.add_argument_group("ceilometer") parser.add_argument( "--ceilometer-url", default=cliutils.env("CEILOMETER_URL"), help="Defaults to env[CEILOMETER_URL].") parser.add_argument( "--ceilometer-api-version", default=cliutils.env("CEILOMETER_API_VERSION", default="2"), help="Defaults to env[CEILOMETER_API_VERSION] or 2.")
def _append_ceilometer_args(self, parent_parser): parser = parent_parser.add_argument_group('ceilometer') parser.add_argument( '--ceilometer-url', default=cliutils.env('CEILOMETER_URL'), help='Defaults to env[CEILOMETER_URL].') parser.add_argument( '--ceilometer-api-version', default=cliutils.env('CEILOMETER_API_VERSION', default='2'), help='Defaults to env[CEILOMETER_API_VERSION] or 2.')
def _append_identity_args(self, parent_parser): # FIXME(fabgia): identity related parameters should be passed by the # Keystone client itself to avoid constant update in all the services # clients. When this fix is merged this method can be made obsolete. # Bug: https://bugs.launchpad.net/python-keystoneclient/+bug/1332337 parser = parent_parser.add_argument_group("identity") parser.add_argument("-k", "--insecure", default=False, action="store_true", help="Explicitly allow osprofiler to " "perform \"insecure\" SSL (https) requests. " "The server's certificate will " "not be verified against any certificate " "authorities. This option should be used with " "caution.") # User related options parser.add_argument("--os-username", default=cliutils.env("OS_USERNAME"), help="Defaults to env[OS_USERNAME].") parser.add_argument("--os-user-id", default=cliutils.env("OS_USER_ID"), help="Defaults to env[OS_USER_ID].") parser.add_argument("--os-password", default=cliutils.env("OS_PASSWORD"), help="Defaults to env[OS_PASSWORD].") # Domain related options parser.add_argument("--os-user-domain-id", default=cliutils.env("OS_USER_DOMAIN_ID"), help="Defaults to env[OS_USER_DOMAIN_ID].") parser.add_argument("--os-user-domain-name", default=cliutils.env("OS_USER_DOMAIN_NAME"), help="Defaults to env[OS_USER_DOMAIN_NAME].") parser.add_argument("--os-project-domain-id", default=cliutils.env("OS_PROJECT_DOMAIN_ID"), help="Defaults to env[OS_PROJECT_DOMAIN_ID].") parser.add_argument("--os-project-domain-name", default=cliutils.env("OS_PROJECT_DOMAIN_NAME"), help="Defaults to env[OS_PROJECT_DOMAIN_NAME].") # Project V3 or Tenant V2 related options parser.add_argument("--os-project-id", default=cliutils.env("OS_PROJECT_ID"), help="Another way to specify tenant ID. " "This option is mutually exclusive with " " --os-tenant-id. " "Defaults to env[OS_PROJECT_ID].") parser.add_argument("--os-project-name", default=cliutils.env("OS_PROJECT_NAME"), help="Another way to specify tenant name. " "This option is mutually exclusive with " " --os-tenant-name. " "Defaults to env[OS_PROJECT_NAME].") parser.add_argument("--os-tenant-id", default=cliutils.env("OS_TENANT_ID"), help="This option is mutually exclusive with " " --os-project-id. " "Defaults to env[OS_PROJECT_ID].") parser.add_argument("--os-tenant-name", default=cliutils.env("OS_TENANT_NAME"), help="Defaults to env[OS_TENANT_NAME].") # Auth related options parser.add_argument("--os-auth-url", default=cliutils.env("OS_AUTH_URL"), help="Defaults to env[OS_AUTH_URL].") parser.add_argument("--os-auth-token", default=cliutils.env("OS_AUTH_TOKEN"), help="Defaults to env[OS_AUTH_TOKEN].") parser.add_argument("--os-cacert", metavar="<ca-certificate-file>", dest="os_cacert", default=cliutils.env("OS_CACERT"), help="Path of CA TLS certificate(s) used to verify" " the remote server\"s certificate. Without this " "option ceilometer looks for the default system CA" " certificates.") parser.add_argument("--os-cert", help="Path of certificate file to use in SSL " "connection. This file can optionally be " "prepended with the private key.") parser.add_argument("--os-key", help="Path of client key to use in SSL " "connection. This option is not necessary " "if your key is prepended to your cert file.") # Service Catalog related options parser.add_argument("--os-service-type", default=cliutils.env("OS_SERVICE_TYPE"), help="Defaults to env[OS_SERVICE_TYPE].") parser.add_argument("--os-endpoint-type", default=cliutils.env("OS_ENDPOINT_TYPE"), help="Defaults to env[OS_ENDPOINT_TYPE].") parser.add_argument("--os-region-name", default=cliutils.env("OS_REGION_NAME"), help="Defaults to env[OS_REGION_NAME].")
class TraceCommands(BaseCommand): group_name = "trace" @cliutils.arg("trace", help="File with trace or trace id") @cliutils.arg("--connection-string", dest="conn_str", default=(cliutils.env("OSPROFILER_CONNECTION_STRING")), help="Storage driver's connection string. Defaults to " "env[OSPROFILER_CONNECTION_STRING] if set") @cliutils.arg("--transport-url", dest="transport_url", help="Oslo.messaging transport URL (for messaging:// driver " "only), e.g. rabbit://user:password@host:5672/") @cliutils.arg("--idle-timeout", dest="idle_timeout", type=int, default=1, help="How long to wait for the trace to finish, in seconds " "(for messaging:// driver only)") @cliutils.arg("--json", dest="use_json", action="store_true", help="show trace in JSON") @cliutils.arg("--html", dest="use_html", action="store_true", help="show trace in HTML") @cliutils.arg("--local-libs", dest="local_libs", action="store_true", help="use local static files of html in /libs/") @cliutils.arg("--dot", dest="use_dot", action="store_true", help="show trace in DOT language") @cliutils.arg("--render-dot", dest="render_dot_filename", help="filename for rendering the dot graph in pdf format") @cliutils.arg("--out", dest="file_name", help="save output in file") def show(self, args): """Display trace results in HTML, JSON or DOT format.""" if not args.conn_str: raise exc.CommandError( "You must provide connection string via" " either --connection-string or " "via env[OSPROFILER_CONNECTION_STRING]") 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) # 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 _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 @cliutils.arg("--connection-string", dest="conn_str", default=cliutils.env("OSPROFILER_CONNECTION_STRING"), help="Storage driver's connection string. Defaults to " "env[OSPROFILER_CONNECTION_STRING] if set") @cliutils.arg("--error-trace", dest="error_trace", type=bool, default=False, help="List all traces that contain error.") 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())
class TraceCommands(BaseCommand): group_name = "trace" @cliutils.arg("trace", help="File with trace or trace id") @cliutils.arg("--connection-string", dest="conn_str", default=(cliutils.env("OSPROFILER_CONNECTION_STRING") or "ceilometer://"), help="Storage driver's connection string. Defaults to " "env[OSPROFILER_CONNECTION_STRING] if set, else " "ceilometer://") @cliutils.arg("--json", dest="use_json", action="store_true", help="show trace in JSON") @cliutils.arg("--html", dest="use_html", action="store_true", help="show trace in HTML") @cliutils.arg("--dot", dest="use_dot", action="store_true", help="show trace in DOT language") @cliutils.arg("--render-dot", dest="render_dot_filename", help="filename for rendering the dot graph in pdf format") @cliutils.arg("--out", dest="file_name", help="save output in file") 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 _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