예제 #1
0
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)
예제 #2
0
    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)
예제 #3
0
    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)
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
 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)
예제 #9
0
 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)
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #14
0
    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)
예제 #15
0
    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)
예제 #16
0
        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"])
예제 #19
0
    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)
예제 #21
0
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")