diff --git a/docs/core/logger.md b/docs/core/logger.md index 0a0ea34bcc..330cab073a 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -634,7 +634,7 @@ Once a child logger is created, the logger and its parent will act as separate i ### Sampling debug logs -Use sampling when you want to dynamically change your log level to **DEBUG** based on a **percentage of your concurrent/cold start invocations**. +Use sampling when you want to dynamically change your log level to **DEBUG** based on a **percentage of your invocations**. You can use values ranging from `0` to `1` (100%) when setting the `sampleRateValue` constructor option or `POWERTOOLS_LOGGER_SAMPLE_RATE` env var. @@ -643,10 +643,9 @@ You can use values ranging from `0` to `1` (100%) when setting the `sampleRateVa This feature takes into account transient issues where additional debugging information can be useful. -Sampling decision happens at the Logger initialization. This means sampling may happen significantly more or less than depending on your traffic patterns, for example a steady low number of invocations and thus few cold starts. +Sampling decision happens at the Logger initialization. When using the `injectLambdaContext` method either as a decorator or middleware, the sampling decision is refreshed at the beginning of each Lambda invocation for you. -!!! note - Open a [feature request](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=type%2Ffeature-request%2Ctriage&projects=aws-powertools%2F7&template=feature_request.yml&title=Feature+request%3A+TITLE) if you want Logger to calculate sampling for every invocation +If you're not using either of these, you'll need to manually call the `refreshSamplingRate()` function at the start of your handler to refresh the sampling decision for each invocation. === "handler.ts" diff --git a/examples/snippets/logger/logSampling.ts b/examples/snippets/logger/logSampling.ts index ea808f18ca..0067afb73f 100644 --- a/examples/snippets/logger/logSampling.ts +++ b/examples/snippets/logger/logSampling.ts @@ -10,6 +10,8 @@ export const handler = async ( _event: unknown, _context: unknown ): Promise => { + // Refresh sample rate calculation on runtime, only when not using injectLambdaContext + logger.refreshSampleRateCalculation(); // This log item (equal to log level 'ERROR') will be printed to standard output // in all Lambda invocations logger.error('This is an ERROR log'); diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index 2f342f6ff7..0695e8d8b4 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -413,6 +413,7 @@ class Logger extends Utility implements LoggerInterface { context, callback ) { + loggerRef.refreshSampleRateCalculation(); Logger.injectLambdaContextBefore(loggerRef, event, context, options); let result: unknown; diff --git a/packages/logger/src/middleware/middy.ts b/packages/logger/src/middleware/middy.ts index e399c1bae8..804444c4b4 100644 --- a/packages/logger/src/middleware/middy.ts +++ b/packages/logger/src/middleware/middy.ts @@ -87,6 +87,9 @@ const injectLambdaContext = ( if (isResetStateEnabled) { setCleanupFunction(request); } + + logger.refreshSampleRateCalculation(); + Logger.injectLambdaContextBefore( logger, request.event, diff --git a/packages/logger/tests/unit/injectLambdaContext.test.ts b/packages/logger/tests/unit/injectLambdaContext.test.ts index e7107ad94a..e51a163a65 100644 --- a/packages/logger/tests/unit/injectLambdaContext.test.ts +++ b/packages/logger/tests/unit/injectLambdaContext.test.ts @@ -184,4 +184,40 @@ describe('Inject Lambda Context', () => { }) ); }); + + it('refreshes sample rate calculation before each invocation using decorator', async () => { + // Prepare + const logger = new Logger({ sampleRateValue: 0.5 }); + const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation'); + + class Lambda { + @logger.injectLambdaContext() + public async handler(_event: unknown, _context: Context): Promise { + logger.info('test'); + } + } + const lambda = new Lambda(); + + // Act + await lambda.handler({}, {} as Context); + + // Assess + expect(refreshSpy).toHaveBeenCalledTimes(1); + }); + + it('refreshes sample rate calculation before each invocation using middleware', async () => { + // Prepare + const logger = new Logger({ sampleRateValue: 0.5 }); + const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation'); + + const handler = middy(async () => { + logger.info('Hello, world!'); + }).use(injectLambdaContext(logger)); + + // Act + await handler(event, context); + + // Assess + expect(refreshSpy).toHaveBeenCalledTimes(1); + }); });