@@ -141,9 +141,9 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
141
141
if (active.get)
142
142
then
143
143
try {
144
- reportError(createErrorMessage(e), lambdaEnvironment.initErrorUrl)
144
+ reportError(LambdaRuntime . createErrorMessage(e), lambdaEnvironment.initErrorUrl)
145
145
} catch {
146
- case e => error(createErrorMessage(e))
146
+ case e => error(LambdaRuntime . createErrorMessage(e))
147
147
}
148
148
} finally {
149
149
lambdaInvocationDebugMode = lambdaEnvironment.isDebugMode
@@ -200,17 +200,19 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
200
200
case NonFatal (e) =>
201
201
given le : LambdaEnvironment = new LambdaEnvironment ()
202
202
try {
203
- reportError(createErrorMessage(e), le.initErrorUrl)
203
+ reportError(LambdaRuntime . createErrorMessage(e), le.initErrorUrl)
204
204
} catch {
205
- case e => error(createErrorMessage(e))
205
+ case e => error(LambdaRuntime . createErrorMessage(e))
206
206
}
207
207
le.resetOut()
208
208
throw e
209
209
}
210
210
}
211
211
}
212
212
213
- /** The actual lambda invocation happens here. */
213
+ /* ----------------------------------------------------------
214
+ * THE ACTUAL LAMBDA BUSINESS METHOD INVOCATION HAPPENS HERE.
215
+ * ---------------------------------------------------------- */
214
216
private final def invokeHandleRequest (
215
217
id : Int
216
218
)(using lambdaEnvironment : LambdaEnvironment ): Unit = {
@@ -265,7 +267,9 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
265
267
.maxMemory()},"totalMemory": ${Runtime
266
268
.getRuntime()
267
269
.totalMemory()},"freeMemory": ${Runtime .getRuntime().freeMemory()}} """
268
- else s " [ $id] $tag ${REQUEST }LAMBDA REQUEST ${AnsiColor .BOLD }${event.body}"
270
+ else {
271
+ s " [ $id] $tag ${REQUEST }LAMBDA REQUEST ${AnsiColor .BOLD }${event.body}"
272
+ }
269
273
)
270
274
271
275
try {
@@ -287,78 +291,44 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
287
291
288
292
val input = event.body
289
293
290
- val logPrinter : PrintStream | NoAnsiColorJsonArray | NoAnsiColorJsonString | NoAnsiColorsSingleLine =
291
- val logPrefix =
292
- if (lambdaEnvironment.shouldLogStructuredJson)
293
- then s """ {"log":"LOGS", $structuredLogIntro, """
294
- else s " [ ${lambdaEnvironment.getFunctionName()}] [ $id] $tag LAMBDA LOGS { "
295
-
296
- val logSuffix =
297
- if (lambdaEnvironment.shouldLogStructuredJson)
298
- then s """ , $structuredLogEnd} """
299
- else " }"
300
-
301
- if (lambdaInvocationDebugMode) then {
302
- if (lambdaEnvironment.shouldDisplayAnsiColors)
303
- then LambdaEnvironment .originalOut
304
- else if (lambdaEnvironment.shouldLogInJsonArrayFormat)
305
- then new NoAnsiColorJsonArray (logPrefix, logSuffix, LambdaEnvironment .originalOut)
306
- else if (lambdaEnvironment.shouldLogInJsonStringFormat)
307
- then new NoAnsiColorJsonString (logPrefix, logSuffix, LambdaEnvironment .originalOut)
308
- else new NoAnsiColorsSingleLine (logPrefix, logSuffix, LambdaEnvironment .originalOut)
309
- } else NoOpPrinter .out
310
-
311
- extension (
312
- v : PrintStream | NoAnsiColorJsonArray | NoAnsiColorsSingleLine | NoAnsiColorJsonString
313
- )
314
- inline def out : PrintStream = v match {
315
- case out : PrintStream => out
316
- case ps : NoAnsiColorJsonArray => ps.out
317
- case ps : NoAnsiColorJsonString => ps.out
318
- case ps : NoAnsiColorsSingleLine => ps.out
319
- }
320
- def close (): Unit = v match {
321
- case out : PrintStream => ()
322
- case ps : NoAnsiColorJsonArray => ps.close()
323
- case ps : NoAnsiColorJsonString => ps.close()
324
- case ps : NoAnsiColorsSingleLine => ps.close()
325
- }
326
-
327
- val previousSystemOut = System .out
328
- var isError = false
294
+ val logPrefix =
295
+ if (lambdaEnvironment.shouldLogStructuredJson)
296
+ then s """ {"log":"LOGS", $structuredLogIntro, """
297
+ else s " [ ${lambdaEnvironment.getFunctionName()}] [ $id] $tag LAMBDA LOGS { "
329
298
330
- val output =
331
- try {
332
- System .setOut(logPrinter.out)
333
- System .setErr(logPrinter.out)
334
- Console .withOut(logPrinter.out) {
335
- Console .withErr(logPrinter.out) {
336
- try {
337
- handleRequest(input)(using context).trim()
338
- } catch {
339
- case NonFatal (e) =>
340
- isError = true
341
- error(e.toString())
342
- val stackTrace = e
343
- .getStackTrace()
344
- .filterNot { s =>
345
- val n = s.getClassName()
346
- n.startsWith(" scala" ) || n.startsWith(" java" )
347
- }
348
- if (stackTrace.size > 30 ) then
349
- stackTrace.take(15 ).foreach(println)
350
- println(" ..." )
351
- stackTrace.takeRight(15 ).foreach(println)
352
- else stackTrace.foreach(println)
353
- createErrorMessage(e)
354
- }
299
+ val logSuffix =
300
+ if (lambdaEnvironment.shouldLogStructuredJson)
301
+ then s """ , $structuredLogEnd} """
302
+ else " }"
303
+
304
+ val result : Either [String , String ] =
305
+ LambdaRuntime
306
+ .withLogCapture(
307
+ lambdaEnvironment,
308
+ logPrefix,
309
+ logSuffix,
310
+ lambdaInvocationDebugMode,
311
+ try {
312
+ Right (handleRequest(input)(using context).trim())
313
+ } catch {
314
+ case NonFatal (e) =>
315
+ error(e.toString())
316
+ val stackTrace = e
317
+ .getStackTrace()
318
+ .filterNot { s =>
319
+ val n = s.getClassName()
320
+ n.startsWith(" scala" ) || n.startsWith(" java" )
321
+ }
322
+ if (stackTrace.size > 30 ) then
323
+ stackTrace.take(15 ).foreach(println)
324
+ println(" ..." )
325
+ stackTrace.takeRight(15 ).foreach(println)
326
+ else stackTrace.foreach(println)
327
+ Left (LambdaRuntime .createErrorMessage(e))
355
328
}
356
- }
357
- } finally {
358
- logPrinter.close()
359
- System .setOut(previousSystemOut)
360
- System .setErr(previousSystemOut)
361
- }
329
+ )
330
+
331
+ val output = result.fold(identity, identity)
362
332
363
333
val isJsonReponse =
364
334
(output.startsWith(" {" ) && output.endsWith(" }" ))
@@ -375,7 +345,7 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
375
345
debug(
376
346
if (lambdaEnvironment.shouldLogStructuredJson)
377
347
then
378
- s """ { $awsEmbededMetric , "log":"RESPONSE", $structuredLogIntro, ${
348
+ s """ {"log":"RESPONSE", $structuredLogIntro, ${
379
349
if (lambdaEnvironment.shouldLogResponseIncludeRequest)
380
350
then
381
351
s """ "request": ${if (isJsonRequest) then event.body else s " \" ${event.body.replace(" \" " , " \\\" " )}\" " }, """
@@ -390,12 +360,14 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
390
360
.getRuntime()
391
361
.maxMemory()},"totalMemory": ${Runtime
392
362
.getRuntime()
393
- .totalMemory()},"freeMemory": ${Runtime .getRuntime().freeMemory()}} """
394
- else s " [ $id] $tag ${RESPONSE }LAMBDA RESPONSE [ ${t1 - t0}ms] ${AnsiColor .BOLD }$output"
363
+ .totalMemory()},"freeMemory": ${Runtime .getRuntime().freeMemory()}, $awsEmbededMetric,} """
364
+ else {
365
+ s " [ $id] $tag ${RESPONSE }LAMBDA RESPONSE [ ${t1 - t0}ms] ${AnsiColor .BOLD }$output"
366
+ }
395
367
)
396
368
397
369
val responseResult =
398
- if (isError )
370
+ if (result.isLeft )
399
371
then reportError(output, lambdaEnvironment.errorUrl(requestId))
400
372
else
401
373
httpClient
@@ -410,42 +382,16 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
410
382
411
383
} catch {
412
384
case NonFatal (e) =>
413
- val errorMessage = createErrorMessage(e)
385
+ val errorMessage = LambdaRuntime . createErrorMessage(e)
414
386
error(errorMessage)
415
387
try {
416
388
reportError(errorMessage, lambdaEnvironment.errorUrl(requestId))
417
389
} catch {
418
- case e => error(createErrorMessage(e))
390
+ case e => error(LambdaRuntime . createErrorMessage(e))
419
391
}
420
392
}
421
393
}
422
394
423
- /** Helper method to report error back to the AWS lambda host. */
424
- private final inline def reportError (
425
- errorMessage : String ,
426
- errorUrl : URI
427
- )(using lambdaEnvironment : LambdaEnvironment ): HttpResponse [String ] =
428
- httpClient
429
- .send(
430
- HttpRequest
431
- .newBuilder(errorUrl)
432
- .POST (BodyPublishers .ofString(errorMessage))
433
- .setHeader(" Lambda-Runtime-Function-Error-Type" , " Runtime.UnknownReason" )
434
- .build(),
435
- BodyHandlers .ofString()
436
- )
437
-
438
- private final def createErrorMessage (e : Throwable ): String =
439
- val stackTrace = e.getStackTrace().filterNot { s =>
440
- val n = s.getClassName()
441
- n.startsWith(" scala" ) || n.startsWith(" java" )
442
- }
443
- s " { \" success \" :false, \" errorMessage \" : \" ${e.getMessage()}\" , \" error \" : \" ${e
444
- .getClass()
445
- .getName()}\" , \" stackTrace \" : [ ${(stackTrace.take(3 ).map(_.toString()) ++ Array (" ..." ) ++ stackTrace
446
- .takeRight(3 )
447
- .map(_.toString())).map(s => s " \" $s\" " ).mkString(" ," )}]} "
448
-
449
395
// Lambda invocation for unit test purposes, does not interact with the AWS host, returns result directly. */
450
396
final def test (
451
397
input : String ,
@@ -489,8 +435,23 @@ trait LambdaRuntime extends EventHandler, EventHandlerTag {
489
435
output
490
436
} catch {
491
437
case NonFatal (e) =>
492
- createErrorMessage(e)
438
+ LambdaRuntime . createErrorMessage(e)
493
439
}
440
+
441
+ /** Report error back to the AWS lambda host. */
442
+ final inline def reportError (
443
+ errorMessage : String ,
444
+ errorUrl : URI
445
+ )(using lambdaEnvironment : LambdaEnvironment ): HttpResponse [String ] =
446
+ httpClient
447
+ .send(
448
+ HttpRequest
449
+ .newBuilder(errorUrl)
450
+ .POST (BodyPublishers .ofString(errorMessage))
451
+ .setHeader(" Lambda-Runtime-Function-Error-Type" , " Runtime.UnknownReason" )
452
+ .build(),
453
+ BodyHandlers .ofString()
454
+ )
494
455
}
495
456
496
457
object LambdaRuntime {
@@ -501,4 +462,69 @@ object LambdaRuntime {
501
462
}
502
463
503
464
inline def durationMetric = """ {"Name":"duration","Unit":"Milliseconds","StorageResolution":60}"""
465
+
466
+ final def createErrorMessage (e : Throwable ): String =
467
+ val stackTrace = e.getStackTrace().filterNot { s =>
468
+ val n = s.getClassName()
469
+ n.startsWith(" scala" ) || n.startsWith(" java" )
470
+ }
471
+ s " { \" success \" :false, \" errorMessage \" : \" ${e.getMessage()}\" , \" error \" : \" ${e
472
+ .getClass()
473
+ .getName()}\" , \" stackTrace \" : [ ${(stackTrace.take(3 ).map(_.toString()) ++ Array (" ..." ) ++ stackTrace
474
+ .takeRight(3 )
475
+ .map(_.toString())).map(s => s " \" $s\" " ).mkString(" ," )}]} "
476
+
477
+ final def withLogCapture (
478
+ lambdaEnvironment : LambdaEnvironment ,
479
+ logPrefix : String ,
480
+ logSuffix : String ,
481
+ debugMode : Boolean ,
482
+ body : => Either [String , String ]
483
+ ): Either [String , String ] = {
484
+
485
+ val logPrinter : PrintStream | NoAnsiColorJsonArray | NoAnsiColorJsonString | NoAnsiColorsSingleLine =
486
+ if (debugMode) then {
487
+ if (lambdaEnvironment.shouldDisplayAnsiColors)
488
+ then LambdaEnvironment .originalOut
489
+ else if (lambdaEnvironment.shouldLogInJsonArrayFormat)
490
+ then new NoAnsiColorJsonArray (logPrefix, logSuffix, LambdaEnvironment .originalOut)
491
+ else if (lambdaEnvironment.shouldLogInJsonStringFormat)
492
+ then new NoAnsiColorJsonString (logPrefix, logSuffix, LambdaEnvironment .originalOut)
493
+ else new NoAnsiColorsSingleLine (logPrefix, logSuffix, LambdaEnvironment .originalOut)
494
+ } else NoOpPrinter .out
495
+
496
+ extension (
497
+ v : PrintStream | NoAnsiColorJsonArray | NoAnsiColorsSingleLine | NoAnsiColorJsonString
498
+ )
499
+ inline def out : PrintStream = v match {
500
+ case out : PrintStream => out
501
+ case ps : NoAnsiColorJsonArray => ps.out
502
+ case ps : NoAnsiColorJsonString => ps.out
503
+ case ps : NoAnsiColorsSingleLine => ps.out
504
+ }
505
+
506
+ inline def close (): Unit = v match {
507
+ case out : PrintStream => ()
508
+ case ps : NoAnsiColorJsonArray => ps.close()
509
+ case ps : NoAnsiColorJsonString => ps.close()
510
+ case ps : NoAnsiColorsSingleLine => ps.close()
511
+ }
512
+
513
+ val previousSystemOut = System .out
514
+ var isError = false
515
+
516
+ try {
517
+ System .setOut(logPrinter.out)
518
+ System .setErr(logPrinter.out)
519
+ Console .withOut(logPrinter.out) {
520
+ Console .withErr(logPrinter.out) {
521
+ body
522
+ }
523
+ }
524
+ } finally {
525
+ logPrinter.close()
526
+ System .setOut(previousSystemOut)
527
+ System .setErr(previousSystemOut)
528
+ }
529
+ }
504
530
}
0 commit comments