Skip to content

Commit 1d66a2a

Browse files
authored
feat(logger): refresh sample rate calculation per invocation (#3644)
1 parent f471552 commit 1d66a2a

File tree

5 files changed

+45
-4
lines changed

5 files changed

+45
-4
lines changed

Diff for: docs/core/logger.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ Once a child logger is created, the logger and its parent will act as separate i
634634

635635
### Sampling debug logs
636636

637-
Use sampling when you want to dynamically change your log level to **DEBUG** based on a **percentage of your concurrent/cold start invocations**.
637+
Use sampling when you want to dynamically change your log level to **DEBUG** based on a **percentage of your invocations**.
638638

639639
You can use values ranging from `0` to `1` (100%) when setting the `sampleRateValue` constructor option or `POWERTOOLS_LOGGER_SAMPLE_RATE` env var.
640640

@@ -643,10 +643,9 @@ You can use values ranging from `0` to `1` (100%) when setting the `sampleRateVa
643643

644644
This feature takes into account transient issues where additional debugging information can be useful.
645645

646-
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.
646+
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.
647647

648-
!!! note
649-
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
648+
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.
650649

651650
=== "handler.ts"
652651

Diff for: examples/snippets/logger/logSampling.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export const handler = async (
1010
_event: unknown,
1111
_context: unknown
1212
): Promise<void> => {
13+
// Refresh sample rate calculation on runtime, only when not using injectLambdaContext
14+
logger.refreshSampleRateCalculation();
1315
// This log item (equal to log level 'ERROR') will be printed to standard output
1416
// in all Lambda invocations
1517
logger.error('This is an ERROR log');

Diff for: packages/logger/src/Logger.ts

+1
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ class Logger extends Utility implements LoggerInterface {
413413
context,
414414
callback
415415
) {
416+
loggerRef.refreshSampleRateCalculation();
416417
Logger.injectLambdaContextBefore(loggerRef, event, context, options);
417418

418419
let result: unknown;

Diff for: packages/logger/src/middleware/middy.ts

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ const injectLambdaContext = (
8787
if (isResetStateEnabled) {
8888
setCleanupFunction(request);
8989
}
90+
91+
logger.refreshSampleRateCalculation();
92+
9093
Logger.injectLambdaContextBefore(
9194
logger,
9295
request.event,

Diff for: packages/logger/tests/unit/injectLambdaContext.test.ts

+36
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,40 @@ describe('Inject Lambda Context', () => {
184184
})
185185
);
186186
});
187+
188+
it('refreshes sample rate calculation before each invocation using decorator', async () => {
189+
// Prepare
190+
const logger = new Logger({ sampleRateValue: 0.5 });
191+
const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation');
192+
193+
class Lambda {
194+
@logger.injectLambdaContext()
195+
public async handler(_event: unknown, _context: Context): Promise<void> {
196+
logger.info('test');
197+
}
198+
}
199+
const lambda = new Lambda();
200+
201+
// Act
202+
await lambda.handler({}, {} as Context);
203+
204+
// Assess
205+
expect(refreshSpy).toHaveBeenCalledTimes(1);
206+
});
207+
208+
it('refreshes sample rate calculation before each invocation using middleware', async () => {
209+
// Prepare
210+
const logger = new Logger({ sampleRateValue: 0.5 });
211+
const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation');
212+
213+
const handler = middy(async () => {
214+
logger.info('Hello, world!');
215+
}).use(injectLambdaContext(logger));
216+
217+
// Act
218+
await handler(event, context);
219+
220+
// Assess
221+
expect(refreshSpy).toHaveBeenCalledTimes(1);
222+
});
187223
});

0 commit comments

Comments
 (0)