14
14
from .lambda_runtime_client import LambdaRuntimeClient
15
15
from .lambda_runtime_exception import FaultException
16
16
from .lambda_runtime_log_utils import (
17
- INVOCATION_LOGGING_CONTEXT ,
18
17
JsonFormatter ,
19
18
DATETIME_FORMAT ,
20
- LambdaLogFormat ,
19
+ JSON_FORMAT ,
20
+ TEXT_FORMAT ,
21
+ get_log_format_from_str ,
21
22
)
22
23
from .lambda_runtime_marshaller import to_json
23
24
24
25
ERROR_LOG_LINE_TERMINATE = "\r "
25
26
ERROR_LOG_IDENT = "\u00a0 " # NO-BREAK SPACE U+00A0
26
27
RUNTIME_ERROR_LOGGER_NAME = "system"
28
+ AWS_LAMBDA_LOG_FORMAT = get_log_format_from_str (
29
+ os .environ .get ("AWS_LAMBDA_LOG_FORMAT" , "TEXT" ).upper ()
30
+ )
31
+ AWS_LAMBDA_LOG_LEVEL = os .environ .get ("AWS_LAMBDA_LOG_LEVEL" )
27
32
28
33
29
34
def _get_handler (handler ):
@@ -106,18 +111,11 @@ def replace_line_indentation(line, indent_char, new_indent_char):
106
111
return (new_indent_char * ident_chars_count ) + line [ident_chars_count :]
107
112
108
113
109
- def log_error (error_result , log_sink ):
110
- if AWS_LAMBDA_LOG_FORMAT == LambdaLogFormat .JSON :
111
- log_error_json (error_result , log_sink )
112
- else :
113
- log_error_text (error_result , log_sink )
114
-
115
-
116
114
def log_error_json (error_result , log_sink ):
117
115
log_level = error_result .pop ("log_level" , logging .ERROR )
118
116
error_result ["level" ] = logging .getLevelName (log_level )
119
117
log_sink .log_error (
120
- [to_json (error_result )],
118
+ [to_json (error_result , ensure_ascii = False )],
121
119
log_level = log_level ,
122
120
)
123
121
@@ -154,6 +152,12 @@ def log_error_text(error_result, log_sink):
154
152
)
155
153
156
154
155
+ if AWS_LAMBDA_LOG_FORMAT == JSON_FORMAT :
156
+ log_error = log_error_json
157
+ else :
158
+ log_error = log_error_text
159
+
160
+
157
161
def handle_event_request (
158
162
lambda_runtime_client ,
159
163
request_handler ,
@@ -292,13 +296,13 @@ def __init__(self, log_sink):
292
296
logging .Handler .__init__ (self )
293
297
self .log_sink = log_sink
294
298
295
- def emit (self , record : logging . LogRecord ):
299
+ def emit (self , record ):
296
300
msg = self .format (record )
297
301
298
302
self .log_sink .log (
299
303
msg ,
300
304
log_level = record .levelno ,
301
- log_format = getattr (record , "log_format" , LambdaLogFormat . TEXT ),
305
+ log_format = getattr (record , "log_format" , TEXT_FORMAT ),
302
306
)
303
307
304
308
@@ -340,14 +344,31 @@ def __enter__(self):
340
344
def __exit__ (self , exc_type , exc_value , exc_tb ):
341
345
pass
342
346
343
- def log (self , msg , log_level = logging . NOTSET , log_format = LambdaLogFormat . TEXT ):
347
+ def log (self , msg , log_level = None , log_format = None ):
344
348
sys .stdout .write (msg )
345
349
346
350
def log_error (self , message_lines , log_level = logging .ERROR ):
347
351
error_message = ERROR_LOG_LINE_TERMINATE .join (message_lines ) + "\n "
348
352
sys .stdout .write (error_message )
349
353
350
354
355
+ FRAME_TYPES = {
356
+ (JSON_FORMAT , logging .NOTSET ): 0xA55A0002 .to_bytes (4 , "big" ),
357
+ (JSON_FORMAT , logging .DEBUG ): 0xA55A000A .to_bytes (4 , "big" ),
358
+ (JSON_FORMAT , logging .INFO ): 0xA55A000E .to_bytes (4 , "big" ),
359
+ (JSON_FORMAT , logging .WARNING ): 0xA55A0012 .to_bytes (4 , "big" ),
360
+ (JSON_FORMAT , logging .ERROR ): 0xA55A0016 .to_bytes (4 , "big" ),
361
+ (JSON_FORMAT , logging .CRITICAL ): 0xA55A001A .to_bytes (4 , "big" ),
362
+ (TEXT_FORMAT , logging .NOTSET ): 0xA55A0003 .to_bytes (4 , "big" ),
363
+ (TEXT_FORMAT , logging .DEBUG ): 0xA55A000B .to_bytes (4 , "big" ),
364
+ (TEXT_FORMAT , logging .INFO ): 0xA55A000F .to_bytes (4 , "big" ),
365
+ (TEXT_FORMAT , logging .WARNING ): 0xA55A0013 .to_bytes (4 , "big" ),
366
+ (TEXT_FORMAT , logging .ERROR ): 0xA55A0017 .to_bytes (4 , "big" ),
367
+ (TEXT_FORMAT , logging .CRITICAL ): 0xA55A001B .to_bytes (4 , "big" ),
368
+ }
369
+ DEFAULT_FRAME_TYPE = 0xA55A0003 .to_bytes (4 , "big" )
370
+
371
+
351
372
class FramedTelemetryLogSink (object ):
352
373
"""
353
374
FramedTelemetryLogSink implements the logging contract between runtimes and the platform. It implements a simple
@@ -364,19 +385,8 @@ class FramedTelemetryLogSink(object):
364
385
The next 'len' bytes contain the message. The byte order is big-endian.
365
386
"""
366
387
367
- LEVEL_TO_MASK = {
368
- logging .NOTSET : 0b00000 ,
369
- logging .DEBUG : 0b01000 ,
370
- logging .INFO : 0b01100 ,
371
- logging .WARNING : 0b10000 ,
372
- logging .ERROR : 0b10100 ,
373
- logging .FATAL : 0b11000 ,
374
- }
375
- DEFAULT_LEVEL_MASK = 0b00000
376
-
377
388
def __init__ (self , fd ):
378
389
self .fd = int (fd )
379
- self .frame_type = 0xA55A0002
380
390
381
391
def __enter__ (self ):
382
392
self .file = os .fdopen (self .fd , "wb" , 0 )
@@ -385,16 +395,13 @@ def __enter__(self):
385
395
def __exit__ (self , exc_type , exc_value , exc_tb ):
386
396
self .file .close ()
387
397
388
- def log (self , msg , log_level = logging .NOTSET , log_format = LambdaLogFormat .TEXT ):
389
- frame_type = self .frame_type | self .LEVEL_TO_MASK .get (
390
- log_level , self .DEFAULT_LEVEL_MASK
391
- )
392
- frame_type = frame_type | log_format
393
-
398
+ def log (self , msg , log_level = logging .NOTSET , log_format : int = TEXT_FORMAT ):
399
+ frame_type = FRAME_TYPES .get ((log_format , log_level ), DEFAULT_FRAME_TYPE )
394
400
encoded_msg = msg .encode ("utf8" )
401
+
395
402
timestamp = int (time .time_ns () / 1000 ) # UNIX timestamp in microseconds
396
403
log_msg = (
397
- frame_type . to_bytes ( 4 , "big" )
404
+ frame_type
398
405
+ len (encoded_msg ).to_bytes (4 , "big" )
399
406
+ timestamp .to_bytes (8 , "big" )
400
407
+ encoded_msg
@@ -424,10 +431,6 @@ def create_log_sink():
424
431
return StandardLogSink ()
425
432
426
433
427
- AWS_LAMBDA_LOG_FORMAT = LambdaLogFormat .from_str (
428
- os .environ .get ("AWS_LAMBDA_LOG_FORMAT" , "TEXT" )
429
- )
430
- AWS_LAMBDA_LOG_LEVEL = os .environ .get ("AWS_LAMBDA_LOG_LEVEL" )
431
434
_GLOBAL_AWS_REQUEST_ID = None
432
435
433
436
@@ -436,7 +439,7 @@ def setup_logging(log_format, log_level, log_sink):
436
439
logging .Formatter .converter = time .gmtime
437
440
logger = logging .getLogger ()
438
441
logger_handler = LambdaLoggerHandler (log_sink )
439
- if log_format == LambdaLogFormat . JSON :
442
+ if log_format == JSON_FORMAT :
440
443
logger_handler .setFormatter (JsonFormatter ())
441
444
else :
442
445
logger_handler .setFormatter (
@@ -475,7 +478,6 @@ def run(app_root, handler, lambda_runtime_api_addr):
475
478
476
479
while True :
477
480
event_request = lambda_runtime_client .wait_next_invocation ()
478
- INVOCATION_LOGGING_CONTEXT .clear ()
479
481
480
482
_GLOBAL_AWS_REQUEST_ID = event_request .invoke_id
481
483
0 commit comments