Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions sentry_sdk/integrations/aws_lambda/_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
ORIGIN,
)
from sentry_sdk.scope import Scope
from sentry_sdk.traces import SegmentNameSource
from sentry_sdk.traces import SENTRY_TRACE_HEADER_NAME, SegmentNameSource
from sentry_sdk.utils import (
TimeoutThread,
capture_internal_exceptions,
Expand Down Expand Up @@ -187,7 +187,18 @@ def sentry_handler(
}
)

sentry_sdk.continue_trace(headers)
# a synchronous `Invoke` passes the invoking span in `ClientContext`; it wins over
# event headers, which a forwarded HTTP event keeps from further upstream.
# https://docs.aws.amazon.com/lambda/latest/dg/python-context.html
client_context = aws_context.client_context
if (
client_context is not None
and client_context.custom
and SENTRY_TRACE_HEADER_NAME in client_context.custom
):
sentry_sdk.continue_trace(client_context.custom)
else:
sentry_sdk.continue_trace(headers)
Scope.set_custom_sampling_context(sampling_context)
with sentry_sdk.start_span(
name=function_name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Need to add some ignore rules in this directory, because the unit tests will add the Sentry SDK and its dependencies
# into this directory to create a Lambda function package that contains everything needed to instrument a Lambda function using Sentry.

# Ignore everything
*

# But not index.py
!index.py

# And not .gitignore itself
!.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import json
import os

import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration
from sentry_sdk.integrations.aws_lambda._runtime import get_lambda_bootstrap

sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN"),
traces_sample_rate=1.0,
integrations=[AwsLambdaIntegration()],
)

# `sam local` drops `ClientContext`; pass the event's `client_context` to the runtime
# instead, like lambda does for a synchronous `Invoke`.
bootstrap = get_lambda_bootstrap()
handle_event_request = bootstrap.handle_event_request


def handle_event_request_with_client_context(
lambda_runtime_client,
request_handler,
invoke_id,
event_body,
content_type,
client_context_json,
*args,
):
client_context_json = json.dumps(json.loads(event_body)["client_context"])
return handle_event_request(
lambda_runtime_client,
request_handler,
invoke_id,
event_body,
content_type,
client_context_json,
*args,
)


bootstrap.handle_event_request = handle_event_request_with_client_context


def handler(event, context):
return {"event": event}
33 changes: 33 additions & 0 deletions tests/integrations/aws_lambda/test_aws_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,39 @@ def test_trace_continuation(lambda_client, test_environment):
assert SPANDATA.FAAS_INVOCATION_ID in attrs


@pytest.mark.parametrize(
"headers",
[
pytest.param({}, id="client-context"),
# `ClientContext` wins over event headers.
pytest.param(
{"sentry-trace": "0f4c2a5b8d9e4f1a2b3c4d5e6f7a8b9c-1a2b3c4d5e6f7a8b-1"},
id="client-context-and-event-headers",
),
],
)
def test_trace_continuation_from_client_context(
lambda_client, test_environment, headers
):
payload = {
"headers": headers,
# `ClientContextTrace` passes it to the runtime as the invocation's `ClientContext`.
"client_context": {
"custom": {
"sentry-trace": "471a43a4192642f0b136d5159a501701-6e8f22c393e68f19-1"
}
},
}

lambda_client.invoke(FunctionName="ClientContextTrace", Payload=json.dumps(payload))

(segment_span,) = [
s for s in test_environment["server"].span_items if s["is_segment"]
]
assert segment_span["trace_id"] == "471a43a4192642f0b136d5159a501701"
assert segment_span["parent_span_id"] == "6e8f22c393e68f19"


def test_request_attributes(lambda_client, test_environment):
payload = {
"headers": {
Expand Down
Loading