66from enum import Enum
77
88import pytest
9+ from pytest_mock import MockerFixture
910
1011from aws_lambda_powertools import Logger
1112from aws_lambda_powertools .logging import formatter , utils
@@ -184,7 +185,7 @@ def test_copy_config_to_ext_loggers_custom_log_level(stdout, logger, log_level):
184185 assert log ["level" ] == log_level .WARNING .name
185186
186187
187- def test_copy_config_to_ext_loggers_should_not_break_append_keys (stdout , logger , log_level ):
188+ def test_copy_config_to_ext_loggers_should_not_break_append_keys (stdout , log_level ):
188189 # GIVEN powertools logger initialized
189190 powertools_logger = Logger (service = service_name (), level = log_level .INFO .value , stream = stdout )
190191
@@ -193,3 +194,87 @@ def test_copy_config_to_ext_loggers_should_not_break_append_keys(stdout, logger,
193194
194195 # THEN append_keys should not raise an exception
195196 powertools_logger .append_keys (key = "value" )
197+
198+
199+ def test_copy_config_to_ext_loggers_child_loggers_append_before_work (stdout ):
200+ # GIVEN powertools logger AND child initialized AND
201+
202+ # GIVEN Loggers are initialized
203+ # create child logger before parent to mimick
204+ # importing logger from another module/file
205+ # as loggers are created in global scope
206+ service = service_name ()
207+ child = Logger (stream = stdout , service = service , child = True )
208+ parent = Logger (stream = stdout , service = service )
209+
210+ # WHEN a child Logger adds an additional key AND parent logger adds additional key
211+ child .structure_logs (append = True , customer_id = "value" )
212+ parent .structure_logs (append = True , user_id = "value" )
213+ # WHEN configuration copied from powertools logger
214+ # AND powertools logger and child logger used
215+ utils .copy_config_to_registered_loggers (source_logger = parent )
216+ parent .warning ("Logger message" )
217+ child .warning ("Child logger message" )
218+
219+ # THEN payment_id key added to both powertools logger and child logger
220+ parent_log , child_log = capture_multiple_logging_statements_output (stdout )
221+ assert "customer_id" in parent_log
222+ assert "customer_id" in child_log
223+ assert "user_id" in parent_log
224+ assert "user_id" in child_log
225+ assert child .parent .name == service
226+
227+
228+ def test_copy_config_to_ext_loggers_child_loggers_append_after_works (stdout ):
229+ # GIVEN powertools logger AND child initialized AND
230+
231+ # GIVEN Loggers are initialized
232+ # create child logger before parent to mimick
233+ # importing logger from another module/file
234+ # as loggers are created in global scope
235+ service = service_name ()
236+ child = Logger (stream = stdout , service = service , child = True )
237+ parent = Logger (stream = stdout , service = service )
238+
239+ # WHEN a child Logger adds an additional key AND parent logger adds additional key
240+ # AND configuration copied from powertools logger
241+ # AND powertools logger and child logger used
242+ utils .copy_config_to_registered_loggers (source_logger = parent )
243+ child .structure_logs (append = True , customer_id = "value" )
244+ parent .structure_logs (append = True , user_id = "value" )
245+ parent .warning ("Logger message" )
246+ child .warning ("Child logger message" )
247+
248+ # THEN payment_id key added to both powertools logger and child logger
249+ parent_log , child_log = capture_multiple_logging_statements_output (stdout )
250+ assert "customer_id" in parent_log
251+ assert "customer_id" in child_log
252+ assert "user_id" in parent_log
253+ assert "user_id" in child_log
254+ assert child .parent .name == service
255+
256+
257+ def test_copy_config_to_ext_loggers_no_duplicate_logs (stdout , logger , log_level ):
258+ # GIVEN an root logger, external logger and powertools logger initialized
259+
260+ root_logger = logging .getLogger ()
261+ handler = logging .StreamHandler (stdout )
262+ formatter = logging .Formatter ('{"message": "%(message)s"}' )
263+ handler .setFormatter (formatter )
264+ root_logger .handlers = [handler ]
265+
266+ logger = logger ()
267+
268+ powertools_logger = Logger (service = service_name (), level = log_level .CRITICAL .value , stream = stdout )
269+ level = log_level .WARNING .name
270+
271+ # WHEN configuration copied from powertools logger
272+ # AND external logger used with custom log_level
273+ utils .copy_config_to_registered_loggers (source_logger = powertools_logger , include = {logger .name }, log_level = level )
274+ msg = "test message4"
275+ logger .warning (msg )
276+
277+ # THEN no root logger logs AND log is not duplicated
278+ logs = capture_multiple_logging_statements_output (stdout )
279+ assert not {"message" : msg } in logs
280+ assert sum (msg in log .values () for log in logs ) == 1
0 commit comments