Skip to content

fix(console): Re-patch console in AWS Lambda runtimes - #20337

Merged
s1gr1d merged 16 commits into
developfrom
sig/console-aws-lambda-fix
Apr 22, 2026
Merged

fix(console): Re-patch console in AWS Lambda runtimes#20337
s1gr1d merged 16 commits into
developfrom
sig/console-aws-lambda-fix

Conversation

@s1gr1d

@s1gr1ds1gr1d commented Apr 15, 2026

Copy link
Copy Markdown
Member

On AWS Lambda, the Node.js runtime replaces console.* methods with its own loggers. This means Sentry's console instrumentation gets silently overwritten, and integrations like consoleLoggingIntegration stop capturing console output entirely.

This PR fixes that by introducing a defineProperty-based patching strategy for Lambda environments. Instead of simply assigning a wrapper to console.log (which Lambda can overwrite), we define a getter/setter on the console property. When the Lambda runtime assigns its logger, the setter intercepts it, stores the new function as the underlying delegate, and keeps Sentry's wrapper in place. The handler continues to fire, and the Lambda logger still gets called underneath (I checked that manually - the log is still shown in the CloudWatch logs).

This behavior is guarded behind process.env.LAMBDA_TASK_ROOT, so non-Lambda environments continue to use the existing fill()-based patching with zero behavioral change. If defineProperty fails for any reason, it falls back to fill().

The setter also handles consoleSandbox correctly (recognizes when it restores the original method and allows it through), and defers to other Sentry wrappers by checking for __sentry_original__.

Closes#18238

@github-actions

github-actionsBot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser25.88 kB--
@sentry/browser - with treeshaking flags24.35 kB--
@sentry/browser (incl. Tracing)43.81 kB--
@sentry/browser (incl. Tracing + Span Streaming)45.5 kB--
@sentry/browser (incl. Tracing, Profiling)48.73 kB--
@sentry/browser (incl. Tracing, Replay)82.98 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags72.5 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)87.67 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)99.93 kB--
@sentry/browser (incl. Feedback)42.7 kB--
@sentry/browser (incl. sendFeedback)30.55 kB--
@sentry/browser (incl. FeedbackAsync)35.55 kB--
@sentry/browser (incl. Metrics)27.16 kB--
@sentry/browser (incl. Logs)27.29 kB--
@sentry/browser (incl. Metrics & Logs)27.98 kB--
@sentry/react27.62 kB--
@sentry/react (incl. Tracing)46.05 kB--
@sentry/vue30.71 kB--
@sentry/vue (incl. Tracing)45.62 kB--
@sentry/svelte25.89 kB--
CDN Bundle28.55 kB--
CDN Bundle (incl. Tracing)44.94 kB--
CDN Bundle (incl. Logs, Metrics)29.93 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)46.03 kB--
CDN Bundle (incl. Replay, Logs, Metrics)68.89 kB--
CDN Bundle (incl. Tracing, Replay)81.96 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)83.03 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)87.46 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)88.55 kB--
CDN Bundle - uncompressed83.4 kB--
CDN Bundle (incl. Tracing) - uncompressed134.3 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed87.55 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed137.72 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed211.12 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed251.75 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed255.14 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed264.66 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed268.05 kB--
@sentry/nextjs (client)48.58 kB--
@sentry/sveltekit (client)44.22 kB--
@sentry/node-core58.3 kB+0.48%+278 B 🔺
@sentry/node175.17 kB+0.17%+282 B 🔺
@sentry/node - without tracing98.24 kB+0.29%+279 B 🔺
@sentry/aws-serverless115.48 kB+0.26%+290 B 🔺

View base workflow run

Comment threadpackages/core/src/instrument/console.ts Outdated
Comment thread.size-limit.js Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 249d85d. Configure here.

Comment threadpackages/core/src/instrument/console.ts Outdated

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just some questions and edge cases to consider, but this is a very straightforward way around AWS's instrumentation thwarting ours.

Out of scope for this PR, but it does make me wonder if there's a way to abstract this into core/src/utils/object.ts wrapMethod or something. If we find ourselves in this position again, we can consider doing that. Probably premature otherwise, since just wrapping as a plain old method assignment is usually fine.

Tests look good (rubber-stamp LGTM, I did not run the tests.)

Comment threadpackages/node-core/src/integrations/console.ts
Comment threadpackages/node-core/src/integrations/console.ts
triggerHandlers('console', { args, level } as HandlerDataConsole);

const log = originalConsoleMethods[level];
log?.apply(GLOBAL_OBJ.console, args);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
log?.apply(GLOBAL_OBJ.console,args);
returnlog?.apply(this,args);

typeof newValue === 'function' &&
newValue !== wrapper &&
newValue !== originalConsoleMethods[level] &&
!(newValue as WrappedFunction).__sentry_original__

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clobbering the wrapper if it's a sentry wrapped function makes sense (since that's likely ourselves doing it), but I'm unclear why you're allowing it to be set back to the originalConsoleMethods[level].

That would mean:

constoriginal=console.log// Sentry setup happensconsole.log=someAwsThing;// later...console.log=original;// lose the Sentry instrumentation!

It seems like setting it to the original should just set the consoleDelegate, no?

@s1gr1ds1gr1dApr 20, 2026

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, that's probably a bug. I'm gonna look into that. Currently, it makes sure that the consoleSandbox still works.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated and added a test for that - consoleSandbox also still works.

@s1gr1d
s1gr1d requested a review from isaacsApril 21, 2026 08:56

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@s1gr1d
s1gr1d merged commit 4d8baea into developApr 22, 2026
244 checks passed
@s1gr1d
s1gr1d deleted the sig/console-aws-lambda-fix branch April 22, 2026 08:53
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry Console Logging Integration not working in AWS Lambda

4 participants

@s1gr1d@isaacs@Lms24@JPeer264