Repository navigation
feat(aws-lambda): Detect Lambda triggers - #8222
Conversation
A synchronous boto3 Invoke now carries sentry-trace and baggage in ClientContext.custom (added with the Lambda service extension). The Lambda integration continues the trace from there. ClientContext wins over event headers, because a forwarded HTTP event can keep headers from further upstream. The ClientContextTrace test function works around sam local, which drops ClientContext, by handing the event's client_context to the runtime. Co-Authored-By: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
Classify the delivered event into faas.trigger: http (API Gateway, function URLs, ALB, CloudFront, AppSync), pubsub (SQS, SNS, Kinesis, Kafka, MQ, SES, EventBridge), datasource (S3, DynamoDB Streams, DocumentDB), timer (EventBridge schedules) or other. The trigger is read from the event envelope, never from its payload. messaging.batch.message_count is now only set for messaging deliveries, with the number of delivered messages. Co-Authored-By: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
Coverage Results 📊✅ 58565 passed | ❌ 1 failed | ⏭️ 3071 skipped | Total: 61637 | Pass Rate: 95.02% | Execution Time: 157m 1s 📊 Comparison with Base Branch
➕ New Tests (1)View new tests
➖ Removed Tests (1)View removed tests
❌ Failed Tests
|
| File | Patch coverage | Changed executable lines |
|---|---|---|
| sentry_sdk/integrations/aws_lambda/_trigger.py | 17.86% | 5/28 covered; missed: 42, 51, 53, 54, 55, 57, 58, 62, 63, 66, 68, 69, 71, 72, 74, 75, 77, 78, 80, 81, 85, 86, 88 |
| sentry_sdk/integrations/aws_lambda/_handler.py | 33.33% | 1/3 covered; missed: 235, 236 |
| sentry_sdk/consts.py | 100.00% | 2/2 covered |
Coverage diff
@@ Coverage Diff @@
## master #8222 +/-##
==========================================
Coverage 90.21% 90.21% —%
==========================================
Files 203 200 -3
Tracked lines 27335 21857 -5478
Branches 10246 7622 -2624
==========================================
- Hits 24660 19717 -4943
+ Misses 2675 2140 -535
+ Partials 1559 1254 -305Generated by Coverage Action
…a span Keep the count on messaging spans only (boto3 receive and batch-send spans, and queue.process for SQS/SNS triggers), as in the OTel messaging conventions and the JS SDK. This drops the batch counting for Kafka, MQ and RabbitMQ deliveries, and matches #8219 so both PRs change these lines the same way. Co-Authored-By: johdax <114897+dingsdax@users.noreply.github.com>
Read client_context and its custom dict with getattr, so a context object without them falls back to the event headers. Co-Authored-By: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
…r/aws-lambda-trigger Co-Authored-By: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
Each case is a SAM invoke. The removed cases only checked other keys of the same lookup table. Co-Authored-By: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
…a-invoke-trace-continuation # Conflicts: # sentry_sdk/integrations/boto3/_client.py # sentry_sdk/integrations/boto3/_instrumentation.py # sentry_sdk/integrations/boto3/_services/base.py # sentry_sdk/integrations/boto3/_services/lambda_.py # sentry_sdk/integrations/boto3/_services/registry.py
…a-invoke-trace-continuation
…r/aws-lambda-trigger
### Description With #8117 (merged), a synchronous boto3 `Invoke` carries `sentry-trace` and `baggage` in `ClientContext.custom`. This PR adds the receiving side: the Lambda integration continues the trace from `context.client_context.custom`. `ClientContext` wins over event headers, because a forwarded HTTP event can still carry headers from further upstream. `sam local` drops `ClientContext`, so the new `ClientContextTrace` test function hands the event's `client_context` to the runtime. That way the container tests can cover it. This is Pablo's code from `pablo/aws-lambda-client-context-trace`. The one change: `client_context` and `custom` are read with `getattr`, so a context object without them falls back to event headers instead of failing. It's the first of three stacked PRs for the stretch Lambda work: this PR → trigger detection (#8222) → `queue.process` spans (#8223). #### Issues * resolves: PY-3009 (receiving side; #8117 does the injection) * Part of #8071 <!-- junior-request-attribution:start --> via @dingsdax. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:slack%3AC0C9X9V5NMT%3A1793904671.980379 --> -- [View Session](https://junior-prod.sentry.dev/conversations/slack%3AC0C9X9V5NMT%3A1793904671.980379) [[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC0C9X9V5NMT%3A1793904671.980379/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: Pablo Deputter <pablo.deputter@sentry.io> Co-authored-by: Pablo Deputter <71842639+pabloDeputter@users.noreply.github.com> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Johannes Daxböck <114897+dingsdax@users.noreply.github.com>
) ### Description Since #8137, #8142, and #8145, boto3 puts `sentry-trace` in SQS and SNS message attributes, but nothing reads it on the Lambda side. This PR is the smallest change that closes the loop for SQS- and SNS-triggered functions. The Lambda integration now reads `sentry-trace` from each record and adds a `message_origin` link from the invocation span to each distinct producer span. This matches what the boto3 `ReceiveMessage` span already does. Messages never become the invocation's parent. It reads: - SQS records: `messageAttributes["sentry-trace"].stringValue` - SNS records: `Sns.MessageAttributes["sentry-trace"].Value` - SNS → SQS without raw message delivery: the SNS envelope in the SQS `body`, the same as boto3 does Links are deduplicated, because a batch send gives many messages the same producer span, and capped at 128, OTel's default, because Lambda can deliver up to 10,000 SQS messages at once. **Scope.** This is intentionally kept separate from the stretch stack. It doesn't add `faas.trigger` (#8222) or `queue.process` spans (#8223), and it doesn't touch `messaging.batch.message_count` (#8229). The invocation span is otherwise unchanged. Synchronous `Invoke` propagation through `ClientContext` is #8221. That PR changes the `continue_trace` call and this one only adds `links=`, so the two are independent. The link-building code repeats boto3's `_message_link` in a Lambda-event shape: Lambda records use `messageAttributes` / `stringValue` / `body`, while the boto3 response uses `MessageAttributes` / `StringValue` / `Body`. Importing from the boto3 integration would make `aws_lambda` depend on botocore. **Testing.** `test_producer_links` sends SQS, SNS, and SNS-to-SQS events to `BasicOkSpanStreaming`. It asserts the segment span's `links` and that the segment span has no parent. It passes in CI's Cloud (Lambda) jobs, and `ruff` and `mypy sentry_sdk` pass. `codecov/patch` is red because the Lambda tests run in `sam local` containers, so their coverage isn't counted. #### Issues * Part of #8081 <!-- junior-request-attribution:start --> via **webb**, @sentrivana. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:slack%3AC09M26BC6A1%3A1794211222.463239 --> -- [View Session](https://junior-prod.sentry.dev/conversations/slack%3AC09M26BC6A1%3A1794211222.463239) [[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC09M26BC6A1%3A1794211222.463239/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Alexander Webb <alexander.webb@sentry.io> Co-authored-by: Ivana Kellyer <131587164+sentrivana@users.noreply.github.com>
|
Take the messaging.batch.message_count stuff out of this PR. As I understand, #8229 is a separate PR for exactly that. |
Restores the batch count on the invocation span, as on major/3.0, so this PR only adds faas.trigger.
…a-trigger # Conflicts: # tests/integrations/aws_lambda/test_aws_lambda.py
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 151b3a4. Configure here.

Description
Sets
faas.triggeron the Lambda span based on the shape of the delivered event:http: API Gateway REST/HTTP, function URLs, ALB, CloudFront, AppSyncpubsub: SQS, SNS, Kinesis, Kafka, MQ, SES, EventBridgedatasource: S3, DynamoDB Streams, DocumentDBtimer: EventBridge schedulesother: anything elseThe trigger is read from the event envelope, never from its payload.
test_triggerhas one case per code path. Other event sources use the same lookup table, so they have no extra cases.This PR doesn't touch
messaging.batch.message_count. That change is in #8229.This is Pablo's code from
pablo/aws-lambda-trigger, without his batch counting for the invocation span. It's the second of three stacked PRs (#8221 → this → #8223).Issues
faas.triggerpart; the per-source attributes in the issue aren't in this PR)via @dingsdax.
--
View Session [Sentry]