11import context from '@aws-lambda-powertools/testing-utils/context' ;
22import type { Context } from 'aws-lambda' ;
3+ import middy from 'middy5' ;
34import { type Mock , beforeEach , describe , expect , it , vi } from 'vitest' ;
45import { Logger } from '../../src/Logger.js' ;
56import { LogLevel , UncaughtErrorLogMessage } from '../../src/constants.js' ;
7+ import { injectLambdaContext } from '../../src/middleware/middy.js' ;
68import type { ConstructorOptions } from '../../src/types/Logger.js' ;
79
810describe ( 'Buffer logs' , ( ) => {
@@ -195,6 +197,34 @@ describe('Buffer logs', () => {
195197 ) ;
196198 } ) ;
197199
200+ it ( 'it safely short circuits when clearBuffer is called without a trace id' , ( ) => {
201+ // Prepare
202+ process . env . _X_AMZN_TRACE_ID = undefined ;
203+ const logger = new Logger ( {
204+ logLevel : LogLevel . ERROR ,
205+ logBufferOptions : { enabled : true , bufferAtVerbosity : LogLevel . DEBUG } ,
206+ } ) ;
207+
208+ // Assess
209+ expect ( ( ) => logger . clearBuffer ( ) ) . not . toThrow ( ) ;
210+ } ) ;
211+
212+ it ( 'it clears the buffer' , ( ) => {
213+ // Prepare
214+ const logger = new Logger ( {
215+ logLevel : LogLevel . ERROR ,
216+ logBufferOptions : { enabled : true , bufferAtVerbosity : LogLevel . DEBUG } ,
217+ } ) ;
218+
219+ // Arrange
220+ logger . debug ( 'This is a log message' ) ;
221+ logger . clearBuffer ( ) ;
222+
223+ logger . flushBuffer ( ) ;
224+
225+ // Assess
226+ expect ( console . debug ) . not . toBeCalled ;
227+ } ) ;
198228 it ( 'it flushes the buffer when an error in logged' , ( ) => {
199229 // Prepare
200230 const logger = new Logger ( {
@@ -213,39 +243,113 @@ describe('Buffer logs', () => {
213243 expect ( console . error ) . toBeCalledTimes ( 1 ) ;
214244 } ) ;
215245
216- it ( 'flushes the buffer when an uncaught error is thrown' , async ( ) => {
217- // Prepare
218- const logger = new Logger ( { logBufferOptions : { enabled : true } } ) ;
219- class TestClass {
220- @logger . injectLambdaContext ( { flushBufferOnUncaughtError : true } )
221- async handler ( _event : unknown , _context : Context ) {
222- logger . debug ( 'This is a log message' ) ;
223- logger . info ( 'This is an info message' ) ;
224- throw new Error ( 'This is an error' ) ;
225- }
246+ it . each ( [
247+ {
248+ handlerFactory : ( logger : Logger ) =>
249+ middy ( )
250+ . use (
251+ injectLambdaContext ( logger , { flushBufferOnUncaughtError : true } )
252+ )
253+ . handler ( async ( ) => {
254+ logger . debug ( 'This is a log message' ) ;
255+ logger . info ( 'This is an info message' ) ;
256+ throw new Error ( 'This is an error' ) ;
257+ } ) ,
258+ case : 'middleware' ,
259+ } ,
260+ {
261+ handlerFactory : ( logger : Logger ) => {
262+ class TestClass {
263+ @logger . injectLambdaContext ( { flushBufferOnUncaughtError : true } )
264+ async handler ( _event : unknown , _context : Context ) {
265+ logger . debug ( 'This is a log message' ) ;
266+ logger . info ( 'This is an info message' ) ;
267+ throw new Error ( 'This is an error' ) ;
268+ }
269+ }
270+ const lambda = new TestClass ( ) ;
271+ return lambda . handler . bind ( lambda ) ;
272+ } ,
273+ case : 'decorator' ,
274+ } ,
275+ ] ) (
276+ 'flushes the buffer when an uncaught error is thrown ($case)' ,
277+ async ( { handlerFactory } ) => {
278+ // Prepare
279+ const logger = new Logger ( { logBufferOptions : { enabled : true } } ) ;
280+ const handler = handlerFactory ( logger ) ;
281+
282+ // Act & Assess
283+ await expect ( ( ) =>
284+ handler (
285+ {
286+ foo : 'bar' ,
287+ } ,
288+ context
289+ )
290+ ) . rejects . toThrow ( new Error ( 'This is an error' ) ) ;
291+ expect ( console . debug ) . toBeCalledTimes ( 1 ) ;
292+ expect ( console . info ) . toBeCalledTimes ( 1 ) ;
293+ expect ( console . error ) . toHaveLogged (
294+ expect . objectContaining ( {
295+ message : UncaughtErrorLogMessage ,
296+ } )
297+ ) ;
298+ // If debug is called after info, it means it was buffered and then flushed
299+ expect ( console . debug ) . toHaveBeenCalledAfter ( console . info as Mock ) ;
300+ // If error is called after debug, it means the buffer was flushed before the error log
301+ expect ( console . debug ) . toHaveBeenCalledBefore ( console . error as Mock ) ;
226302 }
227- const lambda = new TestClass ( ) ;
228- const handler = lambda . handler . bind ( lambda ) ;
229-
230- // Act & Assess
231- await expect ( ( ) =>
232- handler (
233- {
234- foo : 'bar' ,
235- } ,
236- context
237- )
238- ) . rejects . toThrow ( new Error ( 'This is an error' ) ) ;
239- expect ( console . debug ) . toBeCalledTimes ( 1 ) ;
240- expect ( console . info ) . toBeCalledTimes ( 1 ) ;
241- expect ( console . error ) . toHaveLogged (
242- expect . objectContaining ( {
243- message : UncaughtErrorLogMessage ,
244- } )
245- ) ;
246- // If debug is called after info, it means it was buffered and then flushed
247- expect ( console . debug ) . toHaveBeenCalledAfter ( console . info as Mock ) ;
248- // If error is called after debug, it means the buffer was flushed before the error log
249- expect ( console . debug ) . toHaveBeenCalledBefore ( console . error as Mock ) ;
250- } ) ;
303+ ) ;
304+ it . each ( [
305+ {
306+ handlerFactory : ( logger : Logger ) =>
307+ middy ( )
308+ . use (
309+ injectLambdaContext ( logger , { flushBufferOnUncaughtError : false } )
310+ )
311+ . handler ( async ( ) => {
312+ logger . debug ( 'This is a log message' ) ;
313+ logger . info ( 'This is an info message' ) ;
314+ throw new Error ( 'This is an error' ) ;
315+ } ) ,
316+ case : 'middleware' ,
317+ } ,
318+ {
319+ handlerFactory : ( logger : Logger ) => {
320+ class TestClass {
321+ @logger . injectLambdaContext ( { flushBufferOnUncaughtError : false } )
322+ async handler ( _event : unknown , _context : Context ) {
323+ logger . debug ( 'This is a log message' ) ;
324+ logger . info ( 'This is an info message' ) ;
325+ throw new Error ( 'This is an error' ) ;
326+ }
327+ }
328+ const lambda = new TestClass ( ) ;
329+ return lambda . handler . bind ( lambda ) ;
330+ } ,
331+ case : 'decorator' ,
332+ } ,
333+ ] ) (
334+ 'clears the buffer when an uncaught error is thrown and flushBufferOnUncaughtError is false ($case)' ,
335+ async ( { handlerFactory } ) => {
336+ // Prepare
337+ const logger = new Logger ( { logBufferOptions : { enabled : true } } ) ;
338+ const handler = handlerFactory ( logger ) ;
339+
340+ // Act & Assess
341+ await expect ( ( ) =>
342+ handler (
343+ {
344+ foo : 'bar' ,
345+ } ,
346+ context
347+ )
348+ ) . rejects . toThrow ( new Error ( 'This is an error' ) ) ;
349+
350+ // Assess
351+ expect ( console . debug ) . not . toBeCalled ;
352+ expect ( console . info ) . not . toBeCalled ;
353+ }
354+ ) ;
251355} ) ;
0 commit comments