diff --git a/README.md b/README.md index a2d58489..6bc64dcd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Datadog Lambda Layer for Python (2.7, 3.6, 3.7 and 3.8) enables custom metric su ## IMPORTANT NOTE -AWS Lambda is expected to recieve a [breaking change](https://aws.amazon.com/blogs/compute/upcoming-changes-to-the-python-sdk-in-aws-lambda/) on **January 30, 2021**. If you are using Datadog Python Lambda layer version 7 or below, please upgrade to version 11. +AWS Lambda is expected to recieve a [breaking change](https://aws.amazon.com/blogs/compute/upcoming-changes-to-the-python-sdk-in-aws-lambda/) on **January 30, 2021**. If you are using Datadog Python Lambda layer version 7 or below, please upgrade to version 11. ## Installation @@ -21,6 +21,7 @@ arn:aws:lambda::464622532012:layer:Datadog-:` with the AWS region where your Lambda function is published to. Replace `` with one of the following that matches your Lambda's Python runtime: + - `Datadog-Python27` - `Datadog-Python36` - `Datadog-Python37` @@ -81,7 +82,7 @@ If `DD_FLUSH_TO_LOG` is set to false (not recommended), the Datadog API Key must - DD_KMS_API_KEY - the KMS-encrypted API Key, requires the `kms:Decrypt` permission - DD_API_KEY_SECRET_ARN - the Secret ARN to fetch API Key from the Secrets Manager, requires the `secretsmanager:GetSecretValue` permission (and `kms:Decrypt` if using a customer managed CMK) -You can also supply or override the API key at runtime (not recommended): +You can also supply or override the API key at runtime (not recommended): ```python # Override DD API Key after importing datadog_lambda packages @@ -243,6 +244,7 @@ If your Lambda function is triggered by API Gateway via [the non-proxy integrati If your Lambda function is deployed by the Serverless Framework, such a mapping template gets created by default. ## Log and Trace Correlations + By default, the Datadog trace id gets automatically injected into the logs for correlation, if using the standard python `logging` library. If you use a custom logger handler to log in json, you can inject the ids using the helper function `get_correlation_ids` [manually](https://docs.datadoghq.com/tracing/connect_logs_and_traces/?tab=python#manual-trace-id-injection). @@ -265,6 +267,36 @@ def lambda_handler(event, context): }) ``` +## Datadog Tracer (**Experimental**) + +You can now trace Lambda functions using Datadog APM's tracing libraries ([dd-trace-py](https://github.com/DataDog/dd-trace-py)). + +1. If you are using the Lambda layer, upgrade it to at least version 15. +1. If you are using the pip package `datadog-lambda-python`, upgrade it to at least version `v2.15.0`. +1. Install (or update to) the latest version of [Datadog forwarder Lambda function](https://docs.datadoghq.com/integrations/amazon_web_services/?tab=allpermissions#set-up-the-datadog-lambda-function). Ensure the trace forwarding layer is attached to the forwarder, e.g., ARN for Python 2.7 `arn:aws:lambda::464622532012:layer:Datadog-Trace-Forwarder-Python27:4`. +1. Set the environment variable `DD_TRACE_ENABLED` to true on your function. +1. Instrument your function using `dd-trace`. + +```py +from datadog_lambda.metric import lambda_metric +from datadog_lambda.wrapper import datadog_lambda_wrapper + +from ddtrace import tracer + +@datadog_lambda_wrapper +def hello(event, context): + return { + "statusCode": 200, + "body": get_message() + } + +@tracer.wrap() +def get_message(): + return "hello world" +``` + +You can also use `dd-trace` and the X-Ray tracer together and merge the traces into one, using the environment variable `DD_MERGE_XRAY_TRACES` to true on your function. + ## Opening Issues If you encounter a bug with this package, we want to hear about it. Before opening a new issue, search the existing issues to avoid duplicates. diff --git a/datadog_lambda/__init__.py b/datadog_lambda/__init__.py index 49d69f5e..a6aff66f 100644 --- a/datadog_lambda/__init__.py +++ b/datadog_lambda/__init__.py @@ -1,6 +1,6 @@ # The minor version corresponds to the Lambda layer version. # E.g.,, version 0.5.0 gets packaged into layer version 5. -__version__ = "2.14.0" +__version__ = "2.15.0" import os diff --git a/datadog_lambda/constants.py b/datadog_lambda/constants.py index d2a9332e..5e0b1d9b 100644 --- a/datadog_lambda/constants.py +++ b/datadog_lambda/constants.py @@ -24,3 +24,12 @@ class XraySubsegment(object): NAME = "datadog-metadata" KEY = "trace" NAMESPACE = "datadog" + + +# TraceContextSource of datadog context. The DD_MERGE_XRAY_TRACES +# feature uses this to determine when to use X-Ray as the parent +# trace. +class TraceContextSource(object): + XRAY = "xray" + EVENT = "event" + DDTRACE = "ddtrace" diff --git a/datadog_lambda/tracing.py b/datadog_lambda/tracing.py index 45c5b5ff..132b3884 100644 --- a/datadog_lambda/tracing.py +++ b/datadog_lambda/tracing.py @@ -4,16 +4,26 @@ # Copyright 2019 Datadog, Inc. import logging +import os from aws_xray_sdk.core import xray_recorder from aws_xray_sdk.core.lambda_launcher import LambdaContext -from ddtrace import patch, tracer -from datadog_lambda.constants import SamplingPriority, TraceHeader, XraySubsegment +from datadog_lambda.constants import ( + SamplingPriority, + TraceHeader, + XraySubsegment, + TraceContextSource, +) +from ddtrace import tracer, patch +from ddtrace.propagation.http import HTTPPropagator logger = logging.getLogger(__name__) dd_trace_context = {} +dd_tracing_enabled = os.environ.get("DD_TRACE_ENABLED", "false").lower() == "true" + +propagator = HTTPPropagator() def _convert_xray_trace_id(xray_trace_id): @@ -41,6 +51,43 @@ def _convert_xray_sampling(xray_sampled): ) +def _get_xray_trace_context(): + if not is_lambda_context(): + return None + + xray_trace_entity = xray_recorder.get_trace_entity() # xray (sub)segment + return { + "trace-id": _convert_xray_trace_id(xray_trace_entity.trace_id), + "parent-id": _convert_xray_entity_id(xray_trace_entity.id), + "sampling-priority": _convert_xray_sampling(xray_trace_entity.sampled), + "source": TraceContextSource.XRAY, + } + + +def _get_dd_trace_py_context(): + span = tracer.current_span() + if not span: + return None + + parent_id = span.context.span_id + trace_id = span.context.trace_id + sampling_priority = span.context.sampling_priority + return { + "parent-id": str(parent_id), + "trace-id": str(trace_id), + "sampling-priority": str(sampling_priority), + "source": TraceContextSource.DDTRACE, + } + + +def _context_obj_to_headers(obj): + return { + TraceHeader.TRACE_ID: str(obj.get("trace-id")), + TraceHeader.PARENT_ID: str(obj.get("parent-id")), + TraceHeader.SAMPLING_PRIORITY: str(obj.get("sampling-priority")), + } + + def extract_dd_trace_context(event): """ Extract Datadog trace context from the Lambda `event` object. @@ -61,23 +108,24 @@ def extract_dd_trace_context(event): sampling_priority = lowercase_headers.get(TraceHeader.SAMPLING_PRIORITY) if trace_id and parent_id and sampling_priority: logger.debug("Extracted Datadog trace context from headers") - dd_trace_context = { + metadata = { "trace-id": trace_id, "parent-id": parent_id, "sampling-priority": sampling_priority, } xray_recorder.begin_subsegment(XraySubsegment.NAME) subsegment = xray_recorder.current_subsegment() - subsegment.put_metadata( - XraySubsegment.KEY, dd_trace_context, XraySubsegment.NAMESPACE - ) + + subsegment.put_metadata(XraySubsegment.KEY, metadata, XraySubsegment.NAMESPACE) + dd_trace_context = metadata.copy() + dd_trace_context["source"] = TraceContextSource.EVENT xray_recorder.end_subsegment() else: # AWS Lambda runtime caches global variables between invocations, # reset to avoid using the context from the last invocation. - dd_trace_context = {} - + dd_trace_context = _get_xray_trace_context() logger.debug("extracted dd trace context %s", dd_trace_context) + return dd_trace_context def get_dd_trace_context(): @@ -86,32 +134,38 @@ def get_dd_trace_context(): If the Lambda function is invoked by a Datadog-traced service, a Datadog trace context may already exist, and it should be used. Otherwise, use the - current X-Ray trace entity. + current X-Ray trace entity, or the dd-trace-py context if DD_TRACE_ENABLED is true. Most of widely-used HTTP clients are patched to inject the context automatically, but this function can be used to manually inject the trace context to an outgoing request. """ - if not is_lambda_context(): - logger.debug("get_dd_trace_context is only supported in LambdaContext") - return {} - global dd_trace_context - xray_trace_entity = xray_recorder.get_trace_entity() # xray (sub)segment - if dd_trace_context: - return { - TraceHeader.TRACE_ID: dd_trace_context["trace-id"], - TraceHeader.PARENT_ID: _convert_xray_entity_id(xray_trace_entity.id), - TraceHeader.SAMPLING_PRIORITY: dd_trace_context["sampling-priority"], - } - else: - return { - TraceHeader.TRACE_ID: _convert_xray_trace_id(xray_trace_entity.trace_id), - TraceHeader.PARENT_ID: _convert_xray_entity_id(xray_trace_entity.id), - TraceHeader.SAMPLING_PRIORITY: _convert_xray_sampling( - xray_trace_entity.sampled - ), - } + + context = None + xray_context = None + + try: + xray_context = _get_xray_trace_context() # xray (sub)segment + except Exception as e: + logger.debug( + "get_dd_trace_context couldn't read from segment from x-ray, with error %s" + % e + ) + + if xray_context and not dd_trace_context: + context = xray_context + elif xray_context and dd_trace_context: + context = dd_trace_context.copy() + context["parent-id"] = xray_context["parent-id"] + + if dd_tracing_enabled: + dd_trace_py_context = _get_dd_trace_py_context() + if dd_trace_py_context is not None: + logger.debug("get_dd_trace_context using dd-trace context") + context = dd_trace_py_context + + return _context_obj_to_headers(context) if context is not None else {} def set_correlation_ids(): @@ -125,6 +179,9 @@ def set_correlation_ids(): if not is_lambda_context(): logger.debug("set_correlation_ids is only supported in LambdaContext") return + if dd_tracing_enabled: + logger.debug("using ddtrace implementation for spans") + return context = get_dd_trace_context() @@ -167,3 +224,37 @@ def is_lambda_context(): regular `Context` (e.g., when testing lambda functions locally). """ return type(xray_recorder.context) == LambdaContext + + +def set_dd_trace_py_root(trace_context, merge_xray_traces): + if trace_context["source"] == TraceContextSource.EVENT or merge_xray_traces: + headers = get_dd_trace_context() + span_context = propagator.extract(headers) + tracer.context_provider.activate(span_context) + + +def create_function_execution_span( + context, function_name, is_cold_start, trace_context +): + tags = {} + if context: + tags = { + "cold_start": str(is_cold_start).lower(), + "function_arn": context.invoked_function_arn, + "request_id": context.aws_request_id, + "resource_names": context.function_name, + } + source = trace_context["source"] + if source != TraceContextSource.DDTRACE: + tags["_dd.parent_source"] = source + + args = { + "service": "aws.lambda", + "resource": function_name, + "span_type": "serverless", + } + tracer.set_tags({"_dd.origin": "lambda"}) + span = tracer.trace("aws.lambda", **args) + if span: + span.set_tags(tags) + return span diff --git a/datadog_lambda/wrapper.py b/datadog_lambda/wrapper.py index 161e1fca..db30e0c3 100644 --- a/datadog_lambda/wrapper.py +++ b/datadog_lambda/wrapper.py @@ -7,7 +7,7 @@ import logging import traceback -from datadog_lambda.cold_start import set_cold_start +from datadog_lambda.cold_start import set_cold_start, is_cold_start from datadog_lambda.metric import ( lambda_stats, submit_invocations_metric, @@ -16,10 +16,13 @@ from datadog_lambda.patch import patch_all from datadog_lambda.tracing import ( extract_dd_trace_context, - set_correlation_ids, inject_correlation_ids, + dd_tracing_enabled, + set_correlation_ids, + set_dd_trace_py_root, + create_function_execution_span, ) - +from ddtrace import patch_all as patch_all_dd logger = logging.getLogger(__name__) @@ -81,13 +84,21 @@ def __init__(self, func): self.logs_injection = ( os.environ.get("DD_LOGS_INJECTION", "true").lower() == "true" ) + self.merge_xray_traces = ( + os.environ.get("DD_MERGE_XRAY_TRACES", "false").lower() == "true" + ) + self.function_name = os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "function") # Inject trace correlation ids to logs if self.logs_injection: inject_correlation_ids() - # Patch HTTP clients to propagate Datadog trace context - patch_all() + if not dd_tracing_enabled: + # When using dd_trace_py it will patch all the http clients for us, + # Patch HTTP clients to propagate Datadog trace context + patch_all() + else: + patch_all_dd() logger.debug("datadog_lambda_wrapper initialized") except Exception: traceback.print_exc() @@ -105,19 +116,29 @@ def __call__(self, event, context, **kwargs): def _before(self, event, context): try: + set_cold_start() submit_invocations_metric(context) # Extract Datadog trace context from incoming requests - extract_dd_trace_context(event) + dd_context = extract_dd_trace_context(event) + + self.span = None + if dd_tracing_enabled: + set_dd_trace_py_root(dd_context, self.merge_xray_traces) + self.span = create_function_execution_span( + context, self.function_name, is_cold_start(), dd_context + ) + else: + set_correlation_ids() - # Set log correlation ids using extracted trace context - set_correlation_ids() logger.debug("datadog_lambda_wrapper _before() done") except Exception: traceback.print_exc() def _after(self, event, context): try: + if self.span: + self.span.finish() if not self.flush_to_log: lambda_stats.flush(float("inf")) logger.debug("datadog_lambda_wrapper _after() done") diff --git a/scripts/publish_staging.sh b/scripts/publish_staging.sh new file mode 100755 index 00000000..4d4787ed --- /dev/null +++ b/scripts/publish_staging.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e + +./scripts/build_layers.sh +./scripts/publish_layers.sh us-east-1 \ No newline at end of file diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh index c9f7df55..6619210d 100755 --- a/scripts/run_integration_tests.sh +++ b/scripts/run_integration_tests.sh @@ -116,7 +116,15 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do # Strip API key from logged requests sed -E "s/(api_key=|'api_key': ')[a-z0-9\.\-]+/\1XXXX/g" | # Normalize minor package version so that these snapshots aren't broken on version bumps - sed -E "s/(dd_lambda_layer:datadog-python[0-9]+_2\.)[0-9]+\.0/\1XX\.0/g" + sed -E "s/(dd_lambda_layer:datadog-python[0-9]+_2\.)[0-9]+\.0/\1XX\.0/g" | + # Strip out trace/span/parent/timestamps + sed -E "s/(\"trace_id\"\: \")[A-Z0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"span_id\"\: \")[A-Z0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"parent_id\"\: \")[A-Z0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"request_id\"\: \")[a-z0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"duration\"\: )[0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"start\"\: )[0-9\.\-]+/\1XXXX/g" | + sed -E "s/(\"system\.pid\"\: )[0-9\.\-]+/\1XXXX/g" ) if [ ! -f $function_snapshot_path ]; then diff --git a/setup.py b/setup.py index 707e1c04..745558ec 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ install_requires=[ "aws-xray-sdk==2.4.3", "datadog==0.32.0", - "ddtrace==0.31.0", + "ddtrace==0.36.0", "wrapt==1.11.2", "setuptools==42.0.2", ], diff --git a/tests/integration/http_requests.py b/tests/integration/http_requests.py index 4a48e0a3..a79eaecc 100644 --- a/tests/integration/http_requests.py +++ b/tests/integration/http_requests.py @@ -2,6 +2,10 @@ from datadog_lambda.metric import lambda_metric from datadog_lambda.wrapper import datadog_lambda_wrapper +from ddtrace import tracer +from ddtrace.internal.writer import LogWriter + +tracer.writer = LogWriter() @datadog_lambda_wrapper diff --git a/tests/integration/serverless.yml b/tests/integration/serverless.yml index b4422c50..6ec3b956 100644 --- a/tests/integration/serverless.yml +++ b/tests/integration/serverless.yml @@ -86,23 +86,31 @@ functions: http-requests_python27: handler: http_requests.handle runtime: python2.7 + environment: + DD_TRACE_ENABLED: true layers: - { Ref: Python27LambdaLayer } http-requests_python36: handler: http_requests.handle runtime: python3.6 + environment: + DD_TRACE_ENABLED: true layers: - { Ref: Python36LambdaLayer } http-requests_python37: handler: http_requests.handle runtime: python3.7 + environment: + DD_TRACE_ENABLED: true layers: - { Ref: Python37LambdaLayer } http-requests_python38: handler: http_requests.handle runtime: python3.8 + environment: + DD_TRACE_ENABLED: true layers: - { Ref: Python38LambdaLayer } diff --git a/tests/integration/snapshots/logs/http-requests_python27.log b/tests/integration/snapshots/logs/http-requests_python27.log index 26003f91..14b9dc0c 100644 --- a/tests/integration/snapshots/logs/http-requests_python27.log +++ b/tests/integration/snapshots/logs/http-requests_python27.log @@ -2,6 +2,7 @@ START RequestId: XXXX Version: $LATEST {"e": XXXX, "m": "aws.lambda.enhanced.invocations", "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python27", "cold_start:true", "memorysize:1024", "runtime:python2.7", "dd_lambda_layer:datadog-python27_2.XX.0"], "v": 1} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"resource": "http_requests.handle", "name": "aws.lambda", "service": "integration-tester-dev-http-requests_python27", "start": XXXX, "trace_id": "XXXX", "metrics": {"_sampling_priority_v1": 1, "system.pid": XXXX, "_dd.agent_psr": 1.0}, "parent_id": "XXXX", "meta": {"function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python27", "request_id": "XXXX", "cold_start": "True", "resource_names": "integration-tester-dev-http-requests_python27"}, "error": 0, "duration": XXXX, "type": "serverless", "span_id": "XXXX"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "hello.dog", "interval": 10, "host": null, "points": [[XXXX, [1.0]]], "device": null, "type": "distribution"}, {"tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "tests.integration.count", "interval": 10, "host": null, "points": [[XXXX, [21.0]]], "device": null, "type": "distribution"}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms @@ -10,6 +11,7 @@ START RequestId: XXXX Version: $LATEST {"e": XXXX, "m": "aws.lambda.enhanced.invocations", "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python27", "cold_start:false", "memorysize:1024", "runtime:python2.7", "dd_lambda_layer:datadog-python27_2.XX.0"], "v": 1} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"resource": "http_requests.handle", "name": "aws.lambda", "service": "integration-tester-dev-http-requests_python27", "start": XXXX, "trace_id": "XXXX", "metrics": {"_sampling_priority_v1": 1, "system.pid": XXXX, "_dd.agent_psr": 1.0}, "parent_id": "XXXX", "meta": {"function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python27", "request_id": "XXXX", "cold_start": "False", "resource_names": "integration-tester-dev-http-requests_python27"}, "error": 0, "duration": XXXX, "type": "serverless", "span_id": "XXXX"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "hello.dog", "interval": 10, "host": null, "points": [[XXXX, [1.0]]], "device": null, "type": "distribution"}, {"tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "tests.integration.count", "interval": 10, "host": null, "points": [[XXXX, [21.0]]], "device": null, "type": "distribution"}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB @@ -18,6 +20,7 @@ START RequestId: XXXX Version: $LATEST {"e": XXXX, "m": "aws.lambda.enhanced.invocations", "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python27", "cold_start:false", "memorysize:1024", "runtime:python2.7", "dd_lambda_layer:datadog-python27_2.XX.0"], "v": 1} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"resource": "http_requests.handle", "name": "aws.lambda", "service": "integration-tester-dev-http-requests_python27", "start": XXXX, "trace_id": "XXXX", "metrics": {"_sampling_priority_v1": 1, "system.pid": XXXX, "_dd.agent_psr": 1.0}, "parent_id": "XXXX", "meta": {"function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python27", "request_id": "XXXX", "cold_start": "False", "resource_names": "integration-tester-dev-http-requests_python27"}, "error": 0, "duration": XXXX, "type": "serverless", "span_id": "XXXX"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "hello.dog", "interval": 10, "host": null, "points": [[XXXX, [1.0]]], "device": null, "type": "distribution"}, {"tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python27_2.XX.0"], "metric": "tests.integration.count", "interval": 10, "host": null, "points": [[XXXX, [21.0]]], "device": null, "type": "distribution"}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/http-requests_python36.log b/tests/integration/snapshots/logs/http-requests_python36.log index c1c839d8..67c00196 100644 --- a/tests/integration/snapshots/logs/http-requests_python36.log +++ b/tests/integration/snapshots/logs/http-requests_python36.log @@ -2,6 +2,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python36", "cold_start:true", "memorysize:1024", "runtime:python3.6", "dd_lambda_layer:datadog-python36_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python36", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "True", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python36", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python36"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms @@ -10,6 +11,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python36", "cold_start:false", "memorysize:1024", "runtime:python3.6", "dd_lambda_layer:datadog-python36_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python36", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python36", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python36"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB @@ -18,6 +20,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python36", "cold_start:false", "memorysize:1024", "runtime:python3.6", "dd_lambda_layer:datadog-python36_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python36", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python36", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python36"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python36_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/http-requests_python37.log b/tests/integration/snapshots/logs/http-requests_python37.log index 2c037c43..0f93de6d 100644 --- a/tests/integration/snapshots/logs/http-requests_python37.log +++ b/tests/integration/snapshots/logs/http-requests_python37.log @@ -2,6 +2,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python37", "cold_start:true", "memorysize:1024", "runtime:python3.7", "dd_lambda_layer:datadog-python37_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python37", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "True", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python37", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python37"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms @@ -10,6 +11,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python37", "cold_start:false", "memorysize:1024", "runtime:python3.7", "dd_lambda_layer:datadog-python37_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python37", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python37", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python37"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB @@ -18,6 +20,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python37", "cold_start:false", "memorysize:1024", "runtime:python3.7", "dd_lambda_layer:datadog-python37_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python37", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python37", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python37"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/http-requests_python38.log b/tests/integration/snapshots/logs/http-requests_python38.log index a67728d3..30e214d5 100644 --- a/tests/integration/snapshots/logs/http-requests_python38.log +++ b/tests/integration/snapshots/logs/http-requests_python38.log @@ -2,6 +2,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python38", "cold_start:true", "memorysize:1024", "runtime:python3.8", "dd_lambda_layer:datadog-python38_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python38", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "True", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python38", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python38"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms @@ -10,6 +11,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python38", "cold_start:false", "memorysize:1024", "runtime:python3.8", "dd_lambda_layer:datadog-python38_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python38", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python38", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python38"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB @@ -18,6 +20,7 @@ START RequestId: XXXX Version: $LATEST {"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:XXXX", "functionname:integration-tester-dev-http-requests_python38", "cold_start:false", "memorysize:1024", "runtime:python3.8", "dd_lambda_layer:datadog-python38_2.XX.0"]} HTTP GET https://ip-ranges.datadoghq.com/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} HTTP GET https://ip-ranges.datadoghq.eu/ Headers: ["x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {} +{"traces": [[{"trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", "service": "integration-tester-dev-http-requests_python38", "resource": "http_requests.handle", "name": "aws.lambda", "error": 0, "start": XXXX, "duration": XXXX, "meta": {"cold_start": "False", "function_arn": "arn:aws:lambda:us-east-1:601427279990:function:integration-tester-dev-http-requests_python38", "request_id": "XXXX", "resource_names": "integration-tester-dev-http-requests_python38"}, "metrics": {"_dd.agent_psr": 1.0, "system.pid": XXXX, "_sampling_priority_v1": 1}, "type": "serverless"}]]} HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Content-Type:application/json", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:2", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_2.XX.0"], "interval": 10}]} END RequestId: XXXX REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB diff --git a/tests/test_tracing.py b/tests/test_tracing.py index bf2f03f9..4f4a6ab1 100644 --- a/tests/test_tracing.py +++ b/tests/test_tracing.py @@ -6,6 +6,7 @@ from mock import MagicMock, patch from ddtrace.helpers import get_correlation_ids + from datadog_lambda.constants import SamplingPriority, TraceHeader, XraySubsegment from datadog_lambda.tracing import ( extract_dd_trace_context, @@ -19,6 +20,8 @@ class TestExtractAndGetDDTraceContext(unittest.TestCase): def setUp(self): + global dd_tracing_enabled + dd_tracing_enabled = False patcher = patch("datadog_lambda.tracing.xray_recorder") self.mock_xray_recorder = patcher.start() self.mock_xray_recorder.get_trace_entity.return_value = MagicMock( @@ -35,8 +38,21 @@ def setUp(self): self.mock_is_lambda_context.return_value = True self.addCleanup(patcher.stop) + def tearDown(self): + global dd_tracing_enabled + dd_tracing_enabled = False + def test_without_datadog_trace_headers(self): - extract_dd_trace_context({}) + ctx = extract_dd_trace_context({}) + self.assertDictEqual( + ctx, + { + "trace-id": "4369", + "parent-id": "65535", + "sampling-priority": "2", + "source": "xray", + }, + ) self.assertDictEqual( get_dd_trace_context(), { @@ -47,9 +63,18 @@ def test_without_datadog_trace_headers(self): ) def test_with_incomplete_datadog_trace_headers(self): - extract_dd_trace_context( + ctx = extract_dd_trace_context( {"headers": {TraceHeader.TRACE_ID: "123", TraceHeader.PARENT_ID: "321"}} ) + self.assertDictEqual( + ctx, + { + "trace-id": "4369", + "parent-id": "65535", + "sampling-priority": "2", + "source": "xray", + }, + ) self.assertDictEqual( get_dd_trace_context(), { @@ -60,7 +85,7 @@ def test_with_incomplete_datadog_trace_headers(self): ) def test_with_complete_datadog_trace_headers(self): - extract_dd_trace_context( + ctx = extract_dd_trace_context( { "headers": { TraceHeader.TRACE_ID: "123", @@ -69,6 +94,15 @@ def test_with_complete_datadog_trace_headers(self): } } ) + self.assertDictEqual( + ctx, + { + "trace-id": "123", + "parent-id": "321", + "sampling-priority": "1", + "source": "event", + }, + ) self.assertDictEqual( get_dd_trace_context(), {