def _default_event_context_extractor(lambda_event: Any) -> Context: """Default way of extracting the context from the Lambda Event. Assumes the Lambda Event is a map with the headers under the 'headers' key. This is the mapping to use when the Lambda is invoked by an API Gateway REST API where API Gateway is acting as a pure proxy for the request. Protects headers from being something other than dictionary, as this is what downstream propagators expect. See more: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format Args: lambda_event: user-defined, so it could be anything, but this method counts on it being a map with a 'headers' key Returns: A Context with configuration found in the event. """ headers = None try: headers = lambda_event["headers"] except (TypeError, KeyError): logger.debug( "Extracting context from Lambda Event failed: either enable X-Ray active tracing or configure API Gateway to trigger this Lambda function as a pure proxy. Otherwise, generated spans will have an invalid (empty) parent context." ) if not isinstance(headers, dict): headers = {} return get_global_textmap().extract(headers)
def test_invoke(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) function_name = "testFunction" self._create_lambda_function( function_name, return_headers_lambda_str() ) # 2 spans for create IAM + create lambda self.assertEqual(2, len(self.memory_exporter.get_finished_spans())) self.memory_exporter.clear() response = self.client.invoke( Payload=json.dumps({}), FunctionName=function_name, InvocationType="RequestResponse", ) span = self.assert_invoke_span(function_name) span_context = span.get_span_context() # # assert injected span headers = json.loads(response["Payload"].read().decode("utf-8")) self.assertEqual( str(span_context.trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertEqual( str(span_context.span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def extract(self, format: object, carrier: object): """Returns an ``opentracing.SpanContext`` instance extracted from a ``carrier``. See base class for more details. Args: format: a Python object instance that represents a given carrier format. ``format`` may be of any type, and ``format`` equality is defined by python ``==`` operator. carrier: the format-specific carrier object to extract from Returns: An ``opentracing.SpanContext`` extracted from ``carrier`` or ``None`` if no such ``SpanContext`` could be found. """ # pylint: disable=redefined-builtin # This implementation does not perform the extracing by itself but # uses the configured propagators in opentelemetry.propagators. # TODO: Support Format.BINARY once it is supported in # opentelemetry-python. if format not in self._supported_formats: raise UnsupportedFormatException propagator = get_global_textmap() ctx = propagator.extract(self._carrier_getter, carrier) span = get_current_span(ctx) if span is not None: otel_context = span.get_span_context() else: otel_context = INVALID_SPAN_CONTEXT return SpanContextShim(otel_context)
def test_client_interceptor_trace_context_propagation(self, ): # pylint: disable=no-self-use """ensure that client interceptor correctly inject trace context into all outgoing requests.""" previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) interceptor = OpenTelemetryClientInterceptor( trace._DefaultTracer()) carrier = tuple() def invoker(request, metadata): nonlocal carrier carrier = metadata return {} request = Request(client_id=1, request_data="data") interceptor.intercept_unary( request, {}, _UnaryClientInfo(full_method="/GRPCTestServer/SimpleMethod", timeout=None), invoker=invoker, ) assert len(carrier) == 2 assert carrier[0][0] == "mock-traceid" assert carrier[0][1] == "0" assert carrier[1][0] == "mock-spanid" assert carrier[1][1] == "0" finally: set_global_textmap(previous_propagator)
def test_propagator_injects_into_request(self): headers = {} previous_propagator = get_global_textmap() def check_headers(**kwargs): nonlocal headers headers = kwargs["request"].headers try: set_global_textmap(MockTextMapPropagator()) ec2 = self._make_client("ec2") ec2.meta.events.register_first( "before-send.ec2.DescribeInstances", check_headers ) ec2.describe_instances() request_id = "fdcdcab1-ae5c-489e-9c33-4637c5dda355" span = self.assert_span( "EC2", "DescribeInstances", request_id=request_id ) self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( str(span.get_span_context().trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( str(span.get_span_context().span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def test_distributed_context(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) result = self.perform_request(self.URL) self.assertEqual(result.read(), b"Hello!") span = self.assert_span() headers_ = dict(httpretty.last_request().headers) headers = {} for k, v in headers_.items(): headers[k.lower()] = v self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( str(span.get_span_context().trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( str(span.get_span_context().span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def inject(self, span_context, format: object, carrier: object): """Injects ``span_context`` into ``carrier``. See base class for more details. Args: span_context: The ``opentracing.SpanContext`` to inject. format: a Python object instance that represents a given carrier format. `format` may be of any type, and `format` equality is defined by Python ``==`` operator. carrier: the format-specific carrier object to inject into """ # pylint: disable=redefined-builtin # This implementation does not perform the injecting by itself but # uses the configured propagators in opentelemetry.propagators. # TODO: Support Format.BINARY once it is supported in # opentelemetry-python. if format not in self._supported_formats: raise UnsupportedFormatException propagator = get_global_textmap() ctx = set_span_in_context(NonRecordingSpan(span_context.unwrap())) propagator.inject(type(carrier).__setitem__, carrier, context=ctx)
def test_set_custom_propagator(self): reload(propagate) _configure_tracing(_Options()) propagator = get_global_textmap() self.assertIsInstance(propagator, CompositePropagator) propagators = propagator._propagators # pylint: disable=protected-access self.assertEqual(len(propagators), 1) self.assertIsInstance(propagators[0], W3CBaggagePropagator)
def test_sets_tracecontext_and_baggage_are_default_propagator(self): reload(propagate) _configure_tracing(_Options()) propagator = get_global_textmap() self.assertIsInstance(propagator, CompositePropagator) propagators = propagator._propagators # pylint: disable=protected-access self.assertEqual(len(propagators), 2) self.assertIsInstance(propagators[0], TraceContextTextMapPropagator) self.assertIsInstance(propagators[1], W3CBaggagePropagator)
def test_extract_empty_context_returns_invalid_context(self): """In the case where the propagator cannot extract a SpanContext, extract should return and invalid span context. """ _old_propagator = get_global_textmap() set_global_textmap(NOOPTextMapPropagator()) try: carrier = {} ctx = self.shim.extract(opentracing.Format.HTTP_HEADERS, carrier) self.assertEqual(ctx.unwrap(), trace.INVALID_SPAN_CONTEXT) finally: set_global_textmap(_old_propagator)
def test_lambda_invoke_propagation(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) lamb = self._make_client("lambda") lamb.create_function( FunctionName="testFunction", Runtime="python3.8", Role=self.get_role_name(), Handler="lambda_function.lambda_handler", Code={ "ZipFile": get_as_zip_file("lambda_function.py", return_headers_lambda_str()) }, Description="test lambda function", Timeout=3, MemorySize=128, Publish=True, ) # 2 spans for create IAM + create lambda self.assertEqual(2, len(self.memory_exporter.get_finished_spans())) self.memory_exporter.clear() response = lamb.invoke( Payload=json.dumps({}), FunctionName="testFunction", InvocationType="RequestResponse", ) span = self.assert_span("Lambda", "Invoke", request_id=_REQUEST_ID_REGEX_MATCH) span_context = span.get_span_context() # assert injected span results = response["Payload"].read().decode("utf-8") headers = json.loads(results) self.assertEqual( str(span_context.trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertEqual( str(span_context.span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def test_lambda_invoke_propagation(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) lamb = self.session.create_client("lambda", region_name="us-east-1") lamb.create_function( FunctionName="testFunction", Runtime="python2.7", Role=self.get_role_name(), Handler="lambda_function.lambda_handler", Code={ "ZipFile": get_as_zip_file("lambda_function.py", return_headers_lambda_str()) }, Description="test lambda function", Timeout=3, MemorySize=128, Publish=True, ) response = lamb.invoke( Payload=json.dumps({}), FunctionName="testFunction", InvocationType="RequestResponse", ) spans = self.memory_exporter.get_finished_spans() assert spans self.assertEqual(len(spans), 3) results = response["Payload"].read().decode("utf-8") headers = json.loads(results) self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( "0", headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( "0", headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def test_propagator_injects_into_request(self): headers = {} previous_propagator = get_global_textmap() def check_headers(**kwargs): nonlocal headers headers = kwargs["request"].headers try: set_global_textmap(MockTextMapPropagator()) ec2 = self.session.create_client("ec2", region_name="us-west-2") ec2.meta.events.register_first( "before-send.ec2.DescribeInstances", check_headers ) ec2.describe_instances() spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) span = spans[0] describe_instances_attributes = spans[0].attributes self.assertEqual( describe_instances_attributes, { "aws.operation": "DescribeInstances", "aws.region": "us-west-2", "aws.request_id": "fdcdcab1-ae5c-489e-9c33-4637c5dda355", "aws.service": "ec2", "retry_attempts": 0, "http.status_code": 200, }, ) self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( str(span.get_span_context().trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( str(span.get_span_context().span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def test_uninstrument_does_not_inject_headers(self): headers = {} previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) def intercept_headers(**kwargs): headers.update(kwargs["request"].headers) ec2 = self._make_client("ec2") BotocoreInstrumentor().uninstrument() ec2.meta.events.register_first("before-send.ec2.DescribeInstances", intercept_headers) with self.tracer_provider.get_tracer("test").start_span("parent"): ec2.describe_instances() self.assertNotIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertNotIn(MockTextMapPropagator.SPAN_ID_KEY, headers) finally: set_global_textmap(previous_propagator)
def test_context_propagation(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) response = self.perform_request(self.HTTP_URL) self.assertEqual(b"Hello!", response.data) span = self.assert_span() headers = dict(httpretty.last_request().headers) self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( headers[MockTextMapPropagator.TRACE_ID_KEY], str(span.get_span_context().trace_id), ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( headers[MockTextMapPropagator.SPAN_ID_KEY], str(span.get_span_context().span_id), ) finally: set_global_textmap(previous_propagator)
def test_distributed_context(self): previous_propagator = get_global_textmap() try: set_global_textmap(MockTextMapPropagator()) result = self.perform_request(self.URL) self.assertEqual(result.text, "Hello!") span = self.assert_span() headers = dict(respx.calls.last.request.headers) self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( str(span.get_span_context().trace_id), headers[MockTextMapPropagator.TRACE_ID_KEY], ) self.assertIn(MockTextMapPropagator.SPAN_ID_KEY, headers) self.assertEqual( str(span.get_span_context().span_id), headers[MockTextMapPropagator.SPAN_ID_KEY], ) finally: set_global_textmap(previous_propagator)
def receive_message_wrapper(wrapped, instance, args, kwargs): queue_url = kwargs.get("QueueUrl") message_attribute_names = kwargs.pop("MessageAttributeNames", []) message_attribute_names.extend( propagate.get_global_textmap().fields) queue_name = Boto3SQSInstrumentor._extract_queue_name_from_url( queue_url) with self._tracer.start_as_current_span( name=f"{queue_name} receive", end_on_exit=True, kind=SpanKind.CONSUMER, ) as span: Boto3SQSInstrumentor._enrich_span( span, queue_name, queue_url, operation=MessagingOperationValues.RECEIVE, ) retval = wrapped( *args, MessageAttributeNames=message_attribute_names, **kwargs, ) messages = retval.get("Messages", []) if not messages: return retval for message in messages: receipt_handle = message.get("ReceiptHandle") if not receipt_handle: continue Boto3SQSInstrumentor._safe_end_processing_span( receipt_handle) self._create_processing_span(queue_name, queue_url, receipt_handle, message) retval["Messages"] = Boto3SQSInstrumentor.ContextableList( messages) return retval
def custom_event_context_extractor(lambda_event): return get_global_textmap().extract(lambda_event["foo"]["headers"])
def setUpClass(cls): # Save current propagator to be restored on teardown. cls._previous_propagator = get_global_textmap() # Set mock propagator for testing. set_global_textmap(MockTextMapPropagator())
def test_sets_b3_is_global_propagator(self): _configure_tracing(Options()) propagtor = get_global_textmap() self.assertIsInstance(propagtor, B3Format)
from opentelemetry.sdk.trace import TracerProvider app = Flask(__name__) trace.set_tracer_provider(TracerProvider()) trace.get_tracer_provider().add_span_processor( DatadogExportSpanProcessor( DatadogSpanExporter( agent_url="http://*****:*****@app.route("/server_request") def server_request(): param = request.args.get("param")