def _trace_before_publish(self, *args, **kwargs): task = utils.retrieve_task_from_sender(kwargs) task_id = utils.retrieve_task_id_from_message(kwargs) if task is None or task_id is None: return operation_name = "{0}/{1}".format(_TASK_APPLY_ASYNC, task.name) span = self._tracer.start_span( operation_name, kind=trace.SpanKind.PRODUCER ) # apply some attributes here because most of the data is not available if span.is_recording(): span.set_attribute(_TASK_TAG_KEY, _TASK_APPLY_ASYNC) span.set_attribute(_MESSAGE_ID_ATTRIBUTE_NAME, task_id) span.set_attribute(_TASK_NAME_KEY, task.name) utils.set_attributes_from_context(span, kwargs) activation = self._tracer.use_span(span, end_on_exit=True) activation.__enter__() utils.attach_span(task, task_id, (span, activation), is_publish=True) headers = kwargs.get("headers") if headers: propagators.inject(type(headers).__setitem__, headers)
async def on_request_start( unused_session: aiohttp.ClientSession, trace_config_ctx: types.SimpleNamespace, params: aiohttp.TraceRequestStartParams, ): http_method = params.method.upper() if trace_config_ctx.span_name is None: request_span_name = http_method elif callable(trace_config_ctx.span_name): request_span_name = str(trace_config_ctx.span_name(params)) else: request_span_name = str(trace_config_ctx.span_name) trace_config_ctx.span = trace_config_ctx.tracer.start_span( request_span_name, kind=SpanKind.CLIENT, attributes={ "component": "http", "http.method": http_method, "http.url": trace_config_ctx.url_filter(params.url) if callable(trace_config_ctx.url_filter) else str(params.url), }, ) trace_config_ctx.token = context_api.attach( trace.propagation.set_span_in_context(trace_config_ctx.span) ) propagators.inject( tracer, type(params.headers).__setitem__, params.headers )
def fetch_async(tracer, func, _, args, kwargs): start_time = time_ns() # Return immediately if no args were provided (error) # or original_request is set (meaning we are in a redirect step). if len(args) == 0 or hasattr(args[0], "original_request"): return func(*args, **kwargs) # Force the creation of a HTTPRequest object if needed, # so we can inject the context into the headers. args, kwargs = _normalize_request(args, kwargs) request = args[0] span = tracer.start_span( request.method, kind=trace.SpanKind.CLIENT, start_time=start_time, ) if span.is_recording(): attributes = { "component": "tornado", "http.url": request.url, "http.method": request.method, } for key, value in attributes.items(): span.set_attribute(key, value) with tracer.use_span(span): propagators.inject(type(request.headers).__setitem__, request.headers) future = func(*args, **kwargs) future.add_done_callback( functools.partial(_finish_tracing_callback, span=span) ) return future
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/data-semantic-conventions.md#http-client try: parsed_url = urlparse(url) except ValueError as exc: # Invalid URL path = "<Unparsable URL: {}>".format(exc) else: if parsed_url is None: path = "<URL parses to None>" path = parsed_url.path with tracer.start_as_current_span(path, kind=SpanKind.CLIENT) as span: span.set_attribute("component", "http") span.set_attribute("http.method", method.upper()) span.set_attribute("http.url", url) # TODO: Propagate the trace context via headers once we have a way # to access propagators. headers = kwargs.setdefault("headers", {}) propagators.inject(tracer, type(headers).__setitem__, headers) result = wrapped(self, method, url, *args, **kwargs) # *** PROCEED span.set_attribute("http.status_code", result.status_code) span.set_attribute("http.status_text", result.reason) return result
def test_propagation(self): traceparent_value = "00-{trace_id}-{span_id}-00".format( trace_id=format(self.TRACE_ID, "032x"), span_id=format(self.SPAN_ID, "016x"), ) tracestate_value = "foo=1,bar=2,baz=3" headers = { "otcorrelationcontext": ["key1=val1,key2=val2"], "traceparent": [traceparent_value], "tracestate": [tracestate_value], } ctx = extract(get_as_list, headers) correlations = correlationcontext.get_correlations(context=ctx) expected = {"key1": "val1", "key2": "val2"} self.assertEqual(correlations, expected) span_context = get_span_from_context(context=ctx).get_context() self.assertEqual(span_context.trace_id, self.TRACE_ID) self.assertEqual(span_context.span_id, self.SPAN_ID) span = trace.DefaultSpan(span_context) ctx = correlationcontext.set_correlation("key3", "val3") ctx = correlationcontext.set_correlation("key4", "val4", context=ctx) ctx = set_span_in_context(span, context=ctx) output = {} inject(dict.__setitem__, output, context=ctx) self.assertEqual(traceparent_value, output["traceparent"]) self.assertIn("key3=val3", output["otcorrelationcontext"]) self.assertIn("key4=val4", output["otcorrelationcontext"]) self.assertIn("foo=1", output["tracestate"]) self.assertIn("bar=2", output["tracestate"]) self.assertIn("baz=3", output["tracestate"])
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/main/specification/trace/semantic_conventions/http.md#http-client method = method.upper() span_name = "" if name_callback is not None: span_name = name_callback(method, url) if not span_name or not isinstance(span_name, str): span_name = get_default_span_name(method) labels = {} labels["http.method"] = method labels["http.url"] = url with get_tracer(__name__, __version__, tracer_provider).start_as_current_span( span_name, kind=SpanKind.CLIENT) as span: exception = None if span.is_recording(): span.set_attribute("http.method", method) 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 isinstance(result, Response): if span.is_recording(): span.set_attribute("http.status_code", result.status_code) span.set_attribute("http.status_text", result.reason) span.set_status( Status(http_status_to_status_code(result.status_code))) labels["http.status_code"] = str(result.status_code) if result.raw and result.raw.version: labels["http.flavor"] = (str(result.raw.version)[:1] + "." + str(result.raw.version)[:-1]) if span_callback is not None: span_callback(span, result) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result
def _inject_span_context(metadata: MutableMapping[str, str]) -> None: # pylint:disable=unused-argument def append_metadata(carrier: MutableMapping[str, str], key: str, value: str): metadata[key] = value # Inject current active span from the context propagators.inject(append_metadata, metadata)
def to_header(self): # pylint: disable=no-self-use # type: () -> Dict[str, str] """ Returns a dictionary with the header labels and values. :return: A key value pair dictionary """ temp_headers = {} # type: Dict[str, str] inject(_set_headers_from_http_request_headers, temp_headers) return temp_headers
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 to_header(self): # type: () -> Dict[str, str] """ Returns a dictionary with the header labels and values. :return: A key value pair dictionary """ temp_headers = {} # type: Dict[str, str] inject(self.get_current_tracer(), _set_headers_from_http_request_headers, temp_headers) return temp_headers
def deploy_to_orch(): with tracer.start_as_current_span('deploy-to-orch') as span: headers = {} inject(dict.__setitem__, headers) print(span) print(headers) requested = get( "http://localhost:8081/deploy", headers=headers, ) span.set_attribute("http.route", "/orch/deploy")
async def _send_request(event: SendRequest) -> None: tracer = get_tracer(__name__) span = tracer.start_span( event.method_name, kind=SpanKind.CLIENT, attributes={ "component": "grpc", "grpc.method": event.method_name }, ) _client_span.set(span) inject(type(event.metadata).__setitem__, event.metadata)
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 inject(self, url): if self.type == "open_telemetry": headers = {} propagators.inject(type(headers).__setitem__, headers) return headers elif self.type == "jaeger": # https://github.com/yurishkuro/opentracing-tutorial/blob/7ae271badb867635f6697d9dbe5510c798883ff8/python/lesson03/solution/hello.py#L26 headers = {} span = self.tracer.active_span span.set_tag(tags.HTTP_METHOD, "POST") span.set_tag(tags.HTTP_URL, url) span.set_tag(tags.SPAN_KIND, tags.SPAN_KIND_RPC_CLIENT) self.tracer.inject(span, Format.HTTP_HEADERS, headers) # span_header = self.tracer.inject(span, Format.HTTP_HEADERS, headers) # tracer.inject(child_span.context, 'zipkin-span-format', text_carrier) return headers
async def on_request_start( unused_session: aiohttp.ClientSession, trace_config_ctx: types.SimpleNamespace, params: aiohttp.TraceRequestStartParams, ): if context_api.get_value("suppress_instrumentation"): trace_config_ctx.span = None return http_method = params.method.upper() if trace_config_ctx.span_name is None: request_span_name = "HTTP {}".format(http_method) elif callable(trace_config_ctx.span_name): request_span_name = str(trace_config_ctx.span_name(params)) else: request_span_name = str(trace_config_ctx.span_name) trace_config_ctx.span = trace_config_ctx.tracer.start_span( request_span_name, kind=SpanKind.CLIENT, ) if trace_config_ctx.span.is_recording(): attributes = { "component": "http", "http.method": http_method, "http.url": trace_config_ctx.url_filter(params.url) if callable(trace_config_ctx.url_filter) else str(params.url), } for key, value in attributes.items(): trace_config_ctx.span.set_attribute(key, value) trace_config_ctx.token = context_api.attach( trace.set_span_in_context(trace_config_ctx.span)) propagators.inject(type(params.headers).__setitem__, params.headers)
def produce(self, *args, **kwargs): tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( "confluent_kafka.produce", kind=trace.SpanKind.PRODUCER) as span: a = list(args) k = kwargs.copy() argmap = dict(topic=0, value=1, key=2, partition=3, timestamp=5) for name, pos in argmap.items(): if name in kwargs: span.set_attribute("kafka.%s" % name, kwargs[name]) elif len(args) > pos: span.set_attribute("kafka.%s" % name, args[pos]) if "headers" in kwargs: headers = k["headers"] = kwargs["headers"].copy() elif len(args) > 7: headers = a[7] = args[7].copy() else: headers = k["headers"] = {} propagators.inject(type(headers).__setitem__, headers) return self._self_instance.produce(*a, **k)
def _patched_endpoint_prepare_request(wrapped, instance, args, kwargs): request = args[0] headers = request.headers propagators.inject(type(headers).__setitem__, headers) return wrapped(*args, **kwargs)
def inject_current_context() -> Dict[Any, Any]: """Inject trace context into otel propagator.""" context_dict: Dict[Any, Any] = {} propagators.inject(dict.__setitem__, context_dict) return context_dict
def _instrumented_open_call(_, request, call_wrapped, get_or_create_headers): # pylint: disable=too-many-locals if context.get_value("suppress_instrumentation") or context.get_value( _SUPPRESS_URLLIB_INSTRUMENTATION_KEY): return call_wrapped() method = request.get_method().upper() url = request.full_url span_name = "" if name_callback is not None: span_name = name_callback(method, url) if not span_name or not isinstance(span_name, str): span_name = get_default_span_name(method) recorder = URLLibInstrumentor().metric_recorder labels = { "http.method": method, "http.url": url, } with get_tracer(__name__, __version__, tracer_provider).start_as_current_span( span_name, kind=SpanKind.CLIENT) as span: exception = None with recorder.record_client_duration(labels): if span.is_recording(): span.set_attribute("http.method", method) span.set_attribute("http.url", url) headers = get_or_create_headers() propagators.inject(type(headers).__setitem__, headers) token = context.attach( context.set_value(_SUPPRESS_URLLIB_INSTRUMENTATION_KEY, True)) try: result = call_wrapped() # *** PROCEED except Exception as exc: # pylint: disable=W0703 exception = exc result = getattr(exc, "file", None) finally: context.detach(token) if result is not None: code_ = result.getcode() labels["http.status_code"] = str(code_) if span.is_recording(): span.set_attribute("http.status_code", code_) span.set_attribute("http.status_text", result.reason) span.set_status( Status(http_status_to_status_code(code_))) ver_ = str(getattr(result, "version", "")) if ver_: labels["http.flavor"] = "{}.{}".format( ver_[:1], ver_[:-1]) if span_callback is not None: span_callback(span, result) if exception is not None: raise exception.with_traceback(exception.__traceback__) return result
from requests import get from opentelemetry import propagators, trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, SimpleSpanProcessor, ) trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer_provider().get_tracer(__name__) trace.get_tracer_provider().add_span_processor( SimpleSpanProcessor(ConsoleSpanExporter())) assert len(argv) == 2 with tracer.start_as_current_span("client"): with tracer.start_as_current_span("client-server"): headers = {} propagators.inject(headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, headers=headers, ) assert requested.status_code == 200
def request( # type:ignore self, method, url, query_params=None, headers=None, post_params=None, body=None, _preload_content=True, _request_timeout=None, ): headers = {} if headers is None else headers span_attributes = { "http.method": method, "http.url": url, } with get_tracer(__name__, __version__).start_as_current_span( f"External Api Call {self.__class__.__name__}", kind=SpanKind.CLIENT, attributes=span_attributes) as span: try: self.add_client_creds_token_header(headers) if self._tracing_enabled and not _is_instrumentation_suppressed( ): inject(type(headers).__setitem__, headers) with _suppress_further_instrumentation(): response = super().request( # type:ignore method, url, query_params, headers, post_params, body, _preload_content, _request_timeout) _apply_response(span, response) return response except Exception as ex: if is_api_exception(ex) and ex.status in ( HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): # type:ignore logger.warning("Access Denied. Token expired? Retrying.", api_exception=str(ex)) loop = new_event_loop() loop.run_until_complete( self.refresh_client_creds_token(force=True)) self.add_client_creds_token_header(headers) if self._tracing_enabled and not _is_instrumentation_suppressed( ): inject(type(headers).__setitem__, headers) with _suppress_further_instrumentation(): response = super().request( # type:ignore method, url, query_params, headers, post_params, body, _preload_content, _request_timeout) _apply_response(span, response) return response else: logger.exception("Could not call API.", client=self.__class__.__name__) _apply_response(span, ex) raise
from opentelemetry.ext.datadog import ( DatadogExportSpanProcessor, DatadogSpanExporter, ) from opentelemetry.sdk.trace import TracerProvider trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor( DatadogExportSpanProcessor( DatadogSpanExporter(agent_url="http://localhost:8126", service="example-client"))) tracer = trace.get_tracer(__name__) assert len(argv) == 2 with tracer.start_as_current_span("client"): with tracer.start_as_current_span("client-server"): headers = {} propagators.inject(dict.__setitem__, headers) requested = get( "http://localhost:8082/server_request", params={"param": argv[1]}, headers=headers, ) assert requested.status_code == 200 print(requested.text)