def update_span_data(self, task_data, host_data, span): """ update the span with the given TaskData and HostData """ name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name) message = 'success' status = Status(status_code=StatusCode.OK) if host_data.status == 'included': rc = 0 else: res = host_data.result._result rc = res.get('rc', 0) if host_data.status == 'failed': message = self.get_error_message(res) status = Status(status_code=StatusCode.ERROR, description=message) # Record an exception with the task message span.record_exception(BaseException(self.enrich_error_message(res))) elif host_data.status == 'skipped': if 'skip_reason' in res: message = res['skip_reason'] else: message = 'skipped' status = Status(status_code=StatusCode.UNSET) span.set_status(status) self.set_span_attribute(span, "ansible.task.args", task_data.args) self.set_span_attribute(span, "ansible.task.module", task_data.action) self.set_span_attribute(span, "ansible.task.message", message) self.set_span_attribute(span, "ansible.task.name", name) self.set_span_attribute(span, "ansible.task.result", rc) self.set_span_attribute(span, "ansible.task.host.name", host_data.name) self.set_span_attribute(span, "ansible.task.host.status", host_data.status) span.end(end_time=host_data.finish)
def convertOutcome(outcome): if outcome == 'passed': return Status(status_code=StatusCode.OK) elif outcome == 'failed': return Status(status_code=StatusCode.ERROR) else: return Status(status_code=StatusCode.UNSET)
def traced_execution(self, query_method: typing.Callable[..., typing.Any], *args: typing.Tuple[typing.Any, typing.Any], **kwargs: typing.Dict[typing.Any, typing.Any]): statement = args[0] if args else "" with self._db_api_integration.tracer.start_as_current_span( self._db_api_integration.name, kind=SpanKind.CLIENT) as span: span.set_attribute("component", self._db_api_integration.database_component) span.set_attribute("db.type", self._db_api_integration.database_type) span.set_attribute("db.instance", self._db_api_integration.database) span.set_attribute("db.statement", statement) for ( attribute_key, attribute_value, ) in self._db_api_integration.span_attributes.items(): span.set_attribute(attribute_key, attribute_value) if len(args) > 1: span.set_attribute("db.statement.parameters", str(args[1])) try: result = query_method(*args, **kwargs) span.set_status(Status(StatusCanonicalCode.OK)) return result except Exception as ex: # pylint: disable=broad-except span.set_status(Status(StatusCanonicalCode.UNKNOWN, str(ex))) raise ex
async def _do_execute(func, instance, args, kwargs): span_attributes = _hydrate_span_from_args(instance, args[0], args[1:]) tracer = getattr(asyncpg, _APPLIED) exception = None with tracer.start_as_current_span("postgresql", kind=SpanKind.CLIENT) as span: for attribute, value in span_attributes.items(): span.set_attribute(attribute, value) try: result = await func(*args, **kwargs) except Exception as exc: # pylint: disable=W0703 exception = exc raise finally: if exception is not None: span.set_status(Status( _exception_to_canonical_code(exception))) else: span.set_status(Status(StatusCanonicalCode.OK)) return result
async def _opentracing_middleware( request: Request, handler: Callable[[Request], Awaitable[StreamResponse]], ) -> StreamResponse: tracer = get_tracer(__name__) attach(extract(_headers_getter, request)) with tracer.start_as_current_span( request.path, kind=SpanKind.SERVER, attributes={ "component": "http", "http.method": request.method, "http.scheme": request.scheme, "http.host": request.host, }, ) as span: try: response = await handler(request) except HTTPException as e: code = _utils.status_to_canonical_code(e.status) span.set_status(Status(code)) span.set_attribute("http.status_text", e.reason) raise else: code = _utils.status_to_canonical_code(response.status) span.set_status(Status(code)) span.set_attribute("http.status_text", response.reason) return response
def test_description_and_non_error_status(self): with self.assertLogs(level=WARNING) as warning: status = Status(status_code=StatusCode.OK, description="status description") self.assertIs(status.status_code, StatusCode.OK) self.assertEqual(status.description, None) self.assertIn( "description should only be set when status_code is set to StatusCode.ERROR", warning.output[0], ) with self.assertLogs(level=WARNING) as warning: status = Status(status_code=StatusCode.UNSET, description="status description") self.assertIs(status.status_code, StatusCode.UNSET) self.assertEqual(status.description, None) self.assertIn( "description should only be set when status_code is set to StatusCode.ERROR", warning.output[0], ) status = Status(status_code=StatusCode.ERROR, description="status description") self.assertIs(status.status_code, StatusCode.ERROR) self.assertEqual(status.description, "status description")
def trace_call(name, session, extra_attributes=None): if not HAS_OPENTELEMETRY_INSTALLED or not session: # Empty context manager. Users will have to check if the generated value is None or a span yield None return tracer = trace.get_tracer(__name__) # Set base attributes that we know for every trace created attributes = { "db.type": "spanner", "db.url": SpannerClient.DEFAULT_ENDPOINT, "db.instance": session._database.name, "net.host.name": SpannerClient.DEFAULT_ENDPOINT, } if extra_attributes: attributes.update(extra_attributes) with tracer.start_as_current_span(name, kind=trace.SpanKind.CLIENT, attributes=attributes) as span: try: yield span except GoogleAPICallError as error: if error.code is not None: span.set_status( Status(http_status_to_canonical_code(error.code))) elif error.grpc_status_code is not None: span.set_status( # OpenTelemetry's StatusCanonicalCode maps 1-1 with grpc status codes Status(StatusCanonicalCode(error.grpc_status_code.value[0]) )) raise
def trace_call(name, session, extra_attributes=None): if not HAS_OPENTELEMETRY_INSTALLED or not session: # Empty context manager. Users will have to check if the generated value is None or a span yield None return tracer = trace.get_tracer(__name__) # Set base attributes that we know for every trace created attributes = { "db.type": "spanner", "db.url": SpannerClient.DEFAULT_ENDPOINT, "db.instance": session._database.name, "net.host.name": SpannerClient.DEFAULT_ENDPOINT, } if extra_attributes: attributes.update(extra_attributes) with tracer.start_as_current_span( name, kind=trace.SpanKind.CLIENT, attributes=attributes ) as span: try: span.set_status(Status(StatusCode.OK)) yield span except GoogleAPICallError as error: span.set_status(Status(StatusCode.ERROR)) span.record_exception(error) raise
def trace_call(name, connection, extra_attributes=None): if not HAS_OPENTELEMETRY_INSTALLED or not connection: # Empty context manager. Users will have to check if the generated value # is None or a span. yield None return tracer = trace.get_tracer(__name__) # Set base attributes that we know for every trace created attributes = { "db.type": "spanner", "db.engine": "django_spanner", "db.project": connection.settings_dict["PROJECT"], "db.instance": connection.settings_dict["INSTANCE"], "db.name": connection.settings_dict["NAME"], } if extra_attributes: attributes.update(extra_attributes) with tracer.start_as_current_span( name, kind=trace.SpanKind.CLIENT, attributes=attributes ) as span: try: span.set_status(Status(StatusCode.OK)) yield span except GoogleAPICallError as error: span.set_status(Status(StatusCode.ERROR)) span.record_exception(error) raise
def test_constructor(self): status = Status() self.assertIs(status.status_code, StatusCode.UNSET) self.assertIsNone(status.description) status = Status(StatusCode.ERROR, "unavailable") self.assertIs(status.status_code, StatusCode.ERROR) self.assertEqual(status.description, "unavailable")
def test_constructor(self): status = Status() self.assertIs(status.canonical_code, StatusCanonicalCode.OK) self.assertIsNone(status.description) status = Status(StatusCanonicalCode.UNAVAILABLE, "unavailable") self.assertIs(status.canonical_code, StatusCanonicalCode.UNAVAILABLE) self.assertEqual(status.description, "unavailable")
def v2_playbook_on_stats(self, stats): if self.errors == 0: status = Status(status_code=StatusCode.OK) else: status = Status(status_code=StatusCode.ERROR) self.opentelemetry.generate_distributed_traces(self.otel_service_name, self.ansible_playbook, self.tasks_data, status, self.traceparent)
def update_span_data(self, task_data, host_data, span): """ update the span with the given TaskData and HostData """ name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name) message = 'success' res = {} rc = 0 status = Status(status_code=StatusCode.OK) if host_data.status != 'included': # Support loops if 'results' in host_data.result._result: if host_data.status == 'failed': message = self.get_error_message_from_results( host_data.result._result['results'], task_data.action) enriched_error_message = self.enrich_error_message_from_results( host_data.result._result['results'], task_data.action) else: res = host_data.result._result rc = res.get('rc', 0) if host_data.status == 'failed': message = self.get_error_message(res) enriched_error_message = self.enrich_error_message(res) if host_data.status == 'failed': status = Status(status_code=StatusCode.ERROR, description=message) # Record an exception with the task message span.record_exception(BaseException(enriched_error_message)) elif host_data.status == 'skipped': message = res[ 'skip_reason'] if 'skip_reason' in res else 'skipped' status = Status(status_code=StatusCode.UNSET) elif host_data.status == 'ignored': status = Status(status_code=StatusCode.UNSET) span.set_status(status) if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action: names = tuple( self.transform_ansible_unicode_to_str(k) for k in task_data.args.keys()) values = tuple( self.transform_ansible_unicode_to_str(k) for k in task_data.args.values()) self.set_span_attribute(span, ("ansible.task.args.name"), names) self.set_span_attribute(span, ("ansible.task.args.value"), values) self.set_span_attribute(span, "ansible.task.module", task_data.action) self.set_span_attribute(span, "ansible.task.message", message) self.set_span_attribute(span, "ansible.task.name", name) self.set_span_attribute(span, "ansible.task.result", rc) self.set_span_attribute(span, "ansible.task.host.name", host_data.name) self.set_span_attribute(span, "ansible.task.host.status", host_data.status) # This will allow to enrich the service map self.add_attributes_for_service_map_if_possible(span, task_data) span.end(end_time=host_data.finish)
def _instrumented_requests_call( method: str, url: str, call_wrapped, get_or_create_headers ): if context.get_value("suppress_instrumentation") or context.get_value( _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY ): return call_wrapped() # See # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client method = method.upper() span_name = "HTTP {}".format(method) exception = None with get_tracer( __name__, __version__, tracer_provider ).start_as_current_span(span_name, kind=SpanKind.CLIENT) as span: span.set_attribute("component", "http") span.set_attribute("http.method", method.upper()) span.set_attribute("http.url", url) headers = get_or_create_headers() propagators.inject(type(headers).__setitem__, headers) token = context.attach( context.set_value(_SUPPRESS_REQUESTS_INSTRUMENTATION_KEY, True) ) try: result = call_wrapped() # *** PROCEED except Exception as exc: # pylint: disable=W0703 exception = exc result = getattr(exc, "response", None) finally: context.detach(token) if exception is not None: span.set_status( Status(_exception_to_canonical_code(exception)) ) span.record_exception(exception) if result is not None: span.set_attribute("http.status_code", result.status_code) span.set_attribute("http.status_text", result.reason) span.set_status( Status(http_status_to_canonical_code(result.status_code)) ) if span_callback is not None: span_callback(span, result) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result
def convertOutcome(outcome): """Convert from pytest outcome to OpenTelemetry status code""" if outcome == "passed": return Status(status_code=StatusCode.OK) elif (outcome == "failed" or outcome == "interrupted" or outcome == "internal_error" or outcome == "usage_error" or outcome == "no_tests_collected"): return Status(status_code=StatusCode.ERROR) else: return Status(status_code=StatusCode.UNSET)
def instrumented_request(self, method, url, *args, **kwargs): if context.get_value("suppress_instrumentation"): return wrapped(self, method, url, *args, **kwargs) # See # https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-client try: parsed_url = urlparse(url) span_name = parsed_url.path except ValueError as exc: # Invalid URL span_name = "<Unparsable URL: {}>".format(exc) exception = None with get_tracer( __name__, __version__, tracer_provider ).start_as_current_span(span_name, kind=SpanKind.CLIENT) as span: span.set_attribute("component", "http") span.set_attribute("http.method", method.upper()) span.set_attribute("http.url", url) headers = kwargs.get("headers", {}) or {} propagators.inject(type(headers).__setitem__, headers) kwargs["headers"] = headers try: result = wrapped( self, method, url, *args, **kwargs ) # *** PROCEED except Exception as exc: # pylint: disable=W0703 exception = exc result = getattr(exc, "response", None) if exception is not None: span.set_status( Status(_exception_to_canonical_code(exception)) ) if result is not None: span.set_attribute("http.status_code", result.status_code) span.set_attribute("http.status_text", result.reason) span.set_status( Status(http_status_to_canonical_code(result.status_code)) ) if span_callback is not None: span_callback(span, result) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result
def set_status_code(span, status_code): """Adds HTTP response attributes to span using the status_code argument.""" try: status_code = int(status_code) except ValueError: span.set_status( Status( StatusCanonicalCode.UNKNOWN, "Non-integer HTTP status: " + repr(status_code), )) else: span.set_attribute("http.status_code", status_code) span.set_status(Status(http_status_to_canonical_code(status_code)))
def traced_execution(self, query_method: typing.Callable[..., typing.Any], *args: typing.Tuple[typing.Any, typing.Any], **kwargs: typing.Dict[typing.Any, typing.Any]): with self._db_api_integration.get_tracer().start_as_current_span( self._db_api_integration.name, kind=SpanKind.CLIENT) as span: self._populate_span(span, *args) try: result = query_method(*args, **kwargs) span.set_status(Status(StatusCanonicalCode.OK)) return result except Exception as ex: # pylint: disable=broad-except span.set_status(Status(StatusCanonicalCode.UNKNOWN, str(ex))) raise ex
def set_status_code(span, status_code): """Adds HTTP response attributes to span using the status_code argument.""" if not span.is_recording(): return try: status_code = int(status_code) except ValueError: span.set_status( Status( StatusCode.ERROR, "Non-integer HTTP status: " + repr(status_code), )) else: span.set_attribute("http.status_code", status_code) span.set_status(Status(http_status_to_status_code(status_code)))
def started(self, event: monitoring.CommandStartedEvent): """ Method to handle a pymongo CommandStartedEvent """ command = event.command.get(event.command_name, "") name = DATABASE_TYPE + "." + event.command_name statement = event.command_name if command: name += "." + command statement += " " + command try: span = self._tracer.start_span(name, kind=SpanKind.CLIENT) span.set_attribute("component", DATABASE_TYPE) span.set_attribute("db.type", DATABASE_TYPE) span.set_attribute("db.instance", event.database_name) span.set_attribute("db.statement", statement) if event.connection_id is not None: span.set_attribute("peer.hostname", event.connection_id[0]) span.set_attribute("peer.port", event.connection_id[1]) # pymongo specific, not specified by spec span.set_attribute("db.mongo.operation_id", event.operation_id) span.set_attribute("db.mongo.request_id", event.request_id) for attr in COMMAND_ATTRIBUTES: _attr = event.command.get(attr) if _attr is not None: span.set_attribute("db.mongo." + attr, str(_attr)) # Add Span to dictionary self._span_dict[_get_span_dict_key(event)] = span except Exception as ex: # noqa pylint: disable=broad-except if span is not None: span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex))) span.end() self._remove_span(event)
def use_span(self, span: trace_api.Span, end_on_exit: bool = False) -> Iterator[trace_api.Span]: try: token = context_api.attach(context_api.set_value(SPAN_KEY, span)) try: yield span finally: context_api.detach(token) except Exception as error: # pylint: disable=broad-except if (isinstance(span, Span) and span.status is None and span._set_status_on_exception # pylint:disable=protected-access # noqa ): span.set_status( Status( canonical_code=StatusCanonicalCode.UNKNOWN, description="{}: {}".format( type(error).__name__, error), )) raise finally: if end_on_exit: span.end()
def __call__(self, environ, start_response): """The WSGI application Args: environ: A WSGI environment. start_response: The WSGI start_response callable. """ token = context.attach( propagators.extract(get_header_from_environ, environ)) span_name = self.name_callback(environ) span = self.tracer.start_span( span_name, kind=trace.SpanKind.SERVER, attributes=collect_request_attributes(environ), ) try: with self.tracer.use_span(span): start_response = self._create_start_response( span, start_response) iterable = self.wsgi(environ, start_response) return _end_span_after_iterating(iterable, span, self.tracer, token) except Exception as ex: span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex))) span.end() context.detach(token) raise
def _trace_failure(*args, **kwargs): task = utils.retrieve_task_from_sender(kwargs) task_id = utils.retrieve_task_id(kwargs) if task is None or task_id is None: return # retrieve and pass exception info to activation span, _ = utils.retrieve_span(task, task_id) if span is None or not span.is_recording(): return status_kwargs = {"status_code": StatusCode.ERROR} ex = kwargs.get("einfo") if ( hasattr(task, "throws") and ex is not None and isinstance(ex.exception, task.throws) ): return if ex is not None: status_kwargs["description"] = str(ex) span.set_status(Status(**status_kwargs))
def _intercept_server_stream(self, request_or_iterator, metadata, client_info, invoker): if not metadata: mutable_metadata = OrderedDict() else: mutable_metadata = OrderedDict(metadata) with self._start_span(client_info.full_method) as span: inject(mutable_metadata, setter=_carrier_setter) metadata = tuple(mutable_metadata.items()) rpc_info = RpcInfo( full_method=client_info.full_method, metadata=metadata, timeout=client_info.timeout, ) if client_info.is_client_stream: rpc_info.request = request_or_iterator try: yield from invoker(request_or_iterator, metadata) except grpc.RpcError as err: span.set_status(Status(StatusCode.ERROR)) span.set_attribute(SpanAttributes.RPC_GRPC_STATUS_CODE, err.code().value[0]) raise err
def __init__( self, name: str = None, context: trace_api.SpanContext = None, parent: Optional[trace_api.SpanContext] = None, resource: Resource = Resource.create({}), attributes: types.Attributes = None, events: Sequence[Event] = (), links: Sequence[trace_api.Link] = (), kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL, instrumentation_info: InstrumentationInfo = None, status: Status = Status(StatusCode.UNSET), start_time: Optional[int] = None, end_time: Optional[int] = None, ) -> None: self._name = name self._context = context self._kind = kind self._instrumentation_info = instrumentation_info self._parent = parent self._start_time = start_time self._end_time = end_time self._attributes = attributes self._events = events self._links = links self._resource = resource self._status = status
def test_span_to_envelope_properties(self): exporter = self._exporter start_time = 1575494316027613500 end_time = start_time + 1001000000 # Properties span = trace._Span( name="test", context=SpanContext( trace_id=36873507687745823477771305566750195431, span_id=12030755672171557337, is_remote=False, ), attributes={ "test": "asd", "http.method": "GET", "http.url": "https://www.wikipedia.org/wiki/Rabbit", "http.status_code": 200, }, kind=SpanKind.CLIENT, ) span._status = Status(status_code=StatusCode.OK) span.start(start_time=start_time) span.end(end_time=end_time) envelope = exporter._span_to_envelope(span) self.assertEqual(len(envelope.data.base_data.properties), 1) self.assertEqual(envelope.data.base_data.properties["test"], "asd")
def test_span_envelope_server_messaging(self): exporter = self._exporter start_time = 1575494316027613500 end_time = start_time + 1001000000 # SpanKind.SERVER messaging span = trace._Span( name="test", context=SpanContext( trace_id=36873507687745823477771305566750195431, span_id=12030755672171557337, is_remote=False, ), attributes={ "messaging.system": "messaging", "net.peer.name": "test name", "net.peer.ip": "127.0.0.1", "messaging.destination": "celery", }, kind=SpanKind.SERVER, ) span._status = Status(status_code=StatusCode.OK) span.start(start_time=start_time) span.end(end_time=end_time) envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_type, "RequestData") self.assertEqual(envelope.data.base_data.name, "test") self.assertEqual(envelope.data.base_data.id, "a6f5d48acb4d31d9") self.assertEqual(envelope.data.base_data.duration, "0.00:00:01.001") self.assertTrue(envelope.data.base_data.success)
async def _do_execute(self, func, instance, args, kwargs): exception = None params = getattr(instance, "_params", {}) name = args[0] if args[0] else params.get("database", "postgresql") with self._tracer.start_as_current_span( name, kind=SpanKind.CLIENT ) as span: if span.is_recording(): span_attributes = _hydrate_span_from_args( instance, args[0], args[1:] if self.capture_parameters else None, ) for attribute, value in span_attributes.items(): span.set_attribute(attribute, value) try: result = await func(*args, **kwargs) except Exception as exc: # pylint: disable=W0703 exception = exc raise finally: if span.is_recording() and exception is not None: span.set_status(Status(StatusCode.ERROR)) return result
def use_span( self, span: trace_api.Span, end_on_exit: bool = False, ) -> Iterator[trace_api.Span]: try: token = context_api.attach(context_api.set_value(SPAN_KEY, span)) try: yield span finally: context_api.detach(token) except Exception as exc: # pylint: disable=broad-except # Record the exception as an event if isinstance(span, Span) and span.is_recording(): # pylint:disable=protected-access if span._record_exception: span.record_exception(exc) # Records status if use_span is used # i.e. with tracer.start_as_current_span() as span: if (span.status.status_code is StatusCode.UNSET and span._set_status_on_exception): span.set_status( Status( status_code=StatusCode.ERROR, description="{}: {}".format( type(exc).__name__, exc), )) raise finally: if end_on_exit: span.end()
def started(self, event: monitoring.CommandStartedEvent): """ Method to handle a pymongo CommandStartedEvent """ if not self.is_enabled: return command = event.command.get(event.command_name, "") name = event.command_name statement = event.command_name if command: name += "." + str(command) statement += " " + str(command) try: span = self._tracer.start_span(name, kind=SpanKind.CLIENT) if span.is_recording(): span.set_attribute("db.system", DATABASE_SYSTEM) span.set_attribute("db.name", event.database_name) span.set_attribute("db.statement", statement) if event.connection_id is not None: span.set_attribute("net.peer.name", event.connection_id[0]) span.set_attribute("net.peer.port", event.connection_id[1]) # Add Span to dictionary self._span_dict[_get_span_dict_key(event)] = span except Exception as ex: # noqa pylint: disable=broad-except if span is not None and span.is_recording(): span.set_status(Status(StatusCode.ERROR, str(ex))) span.end() self._pop_span(event)