Skip to content

Commit 3638237

Browse files
authored
Respect trace context from Lambda environment variable _X_AMZ_TRACE_ID (#250)
*Description of changes:* The PR includes 3 changes: 1. Respect trace context from Lambda environment variable; 2. Remove Architecture incompatible dependencies; 3. Enable botocore and lambda instrumentations only By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent 4b36553 commit 3638237

File tree

4 files changed

+40
-6
lines changed

4 files changed

+40
-6
lines changed

lambda-layer/src/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ ADD . /workspace
66

77
WORKDIR /workspace
88

9+
RUN sed -i "/opentelemetry-exporter-otlp-proto-grpc/d" ./aws-opentelemetry-distro/pyproject.toml
10+
11+
RUN sed -i "/opentelemetry-instrumentation-system-metrics/d" ./aws-opentelemetry-distro/pyproject.toml
12+
913
RUN mkdir -p /build && \
1014
python3 -m pip install aws-opentelemetry-distro/ -t /build/python && \
1115
mv otel_wrapper.py /build/python && \

lambda-layer/src/otel-instrument

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ fi
126126
# - Enable botocore instrumentation by default
127127

128128
if [ -z ${OTEL_PYTHON_DISABLED_INSTRUMENTATIONS} ]; then
129-
export OTEL_PYTHON_DISABLED_INSTRUMENTATIONS="aio-pika,aiohttp-client,aiopg,asgi,asyncpg,boto3sqs,boto,cassandra,celery,confluent-kafka,dbapi,django,elasticsearch,fastapi,falcon,flask,grpc,httpx,jinja2,kafka-python,logging,mysql,mysqlclient,pika,psycopg2,pymemcache,pymongo,pymysql,pyramid,redis,remoulade,requests,sklearn,sqlalchemy,sqlite3,starlette,system-metrics,tornado,tortoiseorm,urllib,urllib3,wsgi"
129+
export OTEL_PYTHON_DISABLED_INSTRUMENTATIONS="aio-pika,aiohttp-client,aiohttp-server,aiopg,asgi,asyncio,asyncpg,boto,boto3,cassandra,celery,confluent_kafka,dbapi,django,elasticsearch,falcon,fastapi,flask,grpc_client,grpc_server,grpc_aio_client,grpc_aio_server,httpx,jinja2,kafka,logging,mysql,mysqlclient,pika,psycopg,psycopg2,pymemcache,pymongo,pymysql,pyramid,redis,remoulade,requests,sklearn,sqlalchemy,sqlite3,starlette,system_metrics,threading,tornado,tortoiseorm,urllib,urllib3,wsgi"
130130
fi
131131

132132
# - Use a wrapper because AWS Lambda's `python3 /var/runtime/bootstrap.py` will

lambda-layer/src/otel_wrapper.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,14 @@
3636

3737
import os
3838
from importlib import import_module
39+
from typing import Any
3940

40-
from opentelemetry.instrumentation.aws_lambda import AwsLambdaInstrumentor
41+
from opentelemetry.context import Context
42+
from opentelemetry.instrumentation.aws_lambda import _X_AMZN_TRACE_ID, AwsLambdaInstrumentor
43+
from opentelemetry.propagate import get_global_textmap
44+
from opentelemetry.propagators.aws import AwsXRayPropagator
45+
from opentelemetry.propagators.aws.aws_xray_propagator import TRACE_HEADER_KEY
46+
from opentelemetry.trace import get_current_span
4147

4248

4349
def modify_module_name(module_name):
@@ -49,7 +55,26 @@ class HandlerError(Exception):
4955
pass
5056

5157

52-
AwsLambdaInstrumentor().instrument()
58+
def custom_event_context_extractor(lambda_event: Any) -> Context:
59+
xray_env_var = os.environ.get(_X_AMZN_TRACE_ID)
60+
lambda_trace_context = AwsXRayPropagator().extract({TRACE_HEADER_KEY: xray_env_var})
61+
parent_span_context = get_current_span(lambda_trace_context).get_span_context()
62+
63+
if parent_span_context is None or not parent_span_context.is_valid:
64+
headers = None
65+
try:
66+
headers = lambda_event["headers"]
67+
except (TypeError, KeyError):
68+
pass
69+
if not isinstance(headers, dict):
70+
headers = {}
71+
72+
return get_global_textmap().extract(headers)
73+
74+
return lambda_trace_context
75+
76+
77+
AwsLambdaInstrumentor().instrument(event_context_extractor=custom_event_context_extractor)
5378

5479
path = os.environ.get("ORIG_HANDLER")
5580

lambda-layer/src/tests/test_lambda_instrumentation.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,17 @@ def __init__(self, aws_request_id, invoked_function_arn):
5353
MOCK_XRAY_TRACE_ID = 0x5FB7331105E8BB83207FA31D4D9CDB4C
5454
MOCK_XRAY_TRACE_ID_STR = f"{MOCK_XRAY_TRACE_ID:x}"
5555
MOCK_XRAY_PARENT_SPAN_ID = 0x3328B8445A6DBAD2
56+
MOCK_XRAY_LAMBDA_LINEAGE = "Lineage=01cfa446:0"
5657
MOCK_XRAY_TRACE_CONTEXT_COMMON = (
5758
f"Root={TRACE_ID_VERSION}-{MOCK_XRAY_TRACE_ID_STR[:TRACE_ID_FIRST_PART_LENGTH]}"
5859
f"-{MOCK_XRAY_TRACE_ID_STR[TRACE_ID_FIRST_PART_LENGTH:]};Parent={MOCK_XRAY_PARENT_SPAN_ID:x}"
5960
)
60-
MOCK_XRAY_TRACE_CONTEXT_SAMPLED = f"{MOCK_XRAY_TRACE_CONTEXT_COMMON};Sampled=1"
61-
MOCK_XRAY_TRACE_CONTEXT_NOT_SAMPLED = f"{MOCK_XRAY_TRACE_CONTEXT_COMMON};Sampled=0"
61+
MOCK_XRAY_TRACE_CONTEXT_SAMPLED = f"{MOCK_XRAY_TRACE_CONTEXT_COMMON};Sampled=1;{MOCK_XRAY_LAMBDA_LINEAGE}"
62+
MOCK_XRAY_TRACE_CONTEXT_NOT_SAMPLED = f"{MOCK_XRAY_TRACE_CONTEXT_COMMON};Sampled=0;{MOCK_XRAY_LAMBDA_LINEAGE}"
63+
MOCK_XRAY_TRACE_CONTEXT_PASSTHROUGH = (
64+
f"Root={TRACE_ID_VERSION}-{MOCK_XRAY_TRACE_ID_STR[:TRACE_ID_FIRST_PART_LENGTH]}"
65+
f"-{MOCK_XRAY_TRACE_ID_STR[TRACE_ID_FIRST_PART_LENGTH:]};{MOCK_XRAY_LAMBDA_LINEAGE}"
66+
)
6267

6368
# See more:
6469
# https://www.w3.org/TR/trace-context/#examples-of-http-traceparent-headers
@@ -232,7 +237,7 @@ def test_parent_context_from_lambda_event(self):
232237
{
233238
**os.environ,
234239
# NOT Active Tracing
235-
_X_AMZN_TRACE_ID: MOCK_XRAY_TRACE_CONTEXT_NOT_SAMPLED,
240+
_X_AMZN_TRACE_ID: MOCK_XRAY_TRACE_CONTEXT_PASSTHROUGH,
236241
# NOT using the X-Ray Propagator
237242
OTEL_PROPAGATORS: "tracecontext",
238243
},

0 commit comments

Comments
 (0)