def test_setup_no_service_name(root_logger, stdout): # GIVEN no service is explicitly defined # WHEN logger is setup # THEN service field should be "service_undefined" logger_setup() logger = logger_setup() logger.info("Hello") log = json.loads(stdout.getvalue()) assert "service_undefined" == log["service"]
def test_inject_process_booking_sfn_invalid(root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with process booking logger # WHEN logger is setup but event doesn't come from process booking state machine # THEN only lambda should be in the logs and no exceptions raised logger_context_keys = ( "function_name", "function_memory_size", "function_arn", "function_request_id", ) lambda_event = {"some": "value"} logger = logger_setup() @logger_inject_process_booking_sfn def handler(event, context): logger.info("Hello") handler(lambda_event, lambda_context) log = json.loads(stdout.getvalue()) for key in logger_context_keys: assert key in log
def test_inject_lambda_context_log_no_request_by_default( monkeypatch, root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with logger # WHEN logger is setup # THEN logger should not log event received by lambda handler lambda_event = {"greeting": "hello"} logger = logger_setup() @logger_inject_lambda_context() def handler(event, context): logger.info("Hello") handler(lambda_event, lambda_context) # Given that our string buffer has many log statements separated by newline \n # We need to clean it before we can assert on stdout.seek(0) logs = [json.loads(line.strip()) for line in stdout.readlines()] event = {} for log in logs: if "greeting" in log["message"]: event = log["message"] assert event != lambda_event
def test_inject_lambda_context_log_event_request_env_var( monkeypatch, root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with logger instructed to log event # via POWERTOOLS_LOGGER_LOG_EVENT env # WHEN logger is setup # THEN logger should log event received from Lambda lambda_event = {"greeting": "hello"} monkeypatch.setenv("POWERTOOLS_LOGGER_LOG_EVENT", "true") logger = logger_setup() @logger_inject_lambda_context() def handler(event, context): logger.info("Hello") handler(lambda_event, lambda_context) # Given that our string buffer has many log statements separated by newline \n # We need to clean it before we can assert on stdout.seek(0) logs = [json.loads(line.strip()) for line in stdout.readlines()] event = {} for log in logs: if "greeting" in log["message"]: event = log["message"] assert event == lambda_event
def test_setup_service_name(root_logger, stdout): # GIVEN service is explicitly defined # WHEN logger is setup # THEN service field should be equals service given service_name = "payment" logger = logger_setup(service=service_name) logger.info("Hello") log = json.loads(stdout.getvalue()) assert service_name == log["service"]
def test_setup_service_env_var(monkeypatch, root_logger, stdout): # GIVEN service is explicitly defined via POWERTOOLS_SERVICE_NAME env # WHEN logger is setup # THEN service field should be equals POWERTOOLS_SERVICE_NAME value service_name = "payment" monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", service_name) logger = logger_setup() logger.info("Hello") log = json.loads(stdout.getvalue()) assert service_name == log["service"]
def test_inject_process_booking_sfn(root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with process booking logger # WHEN logger is setup # THEN lambda and process booking contextual info should always be in the logs logger_context_keys = ( "function_name", "function_memory_size", "function_arn", "function_request_id", "outbound_flight_id", "customer_id", "charge_id", "state_machine_execution_id", "booking_id", ) process_booking_event = { "outboundFlightId": "1688a4f6-69dd-4590-833e-f349384df465", "customerId": "d749f277-0950-4ad6-ab04-98988721e475", "chargeId": "ch_1F57JxF4aIiftV70vM1BRI5Z", "bookingTable": "Booking-2pa2xn3qzzdi7ntbhdozirkmiy-twitch", "flightTable": "Flight-2pa2xn3qzzdi7ntbhdozirkmiy-twitch", "name": "7e5ecef7-84c4-4836-9500-2115c4175421", "createdAt": "2019-08-08T08:50:06.362Z", "bookingId": "f0fc04ca-a125-45cd-8c37-d09210d7a560", "payment": { "receiptUrl": "https://pay.stripe.com/receipts/acct_1Dvn7pF4aIiftV70/ch_1F57JxF4aIiftV70vM1BRI5Z/rcpt_FaHtr7NWaZuHsZPEfkqWX5UbKTGIL25", "price": 100, }, "bookingReference": "YvSY1Q", "notificationId": "4f984180-ad27-56db-8606-144549af6806", } logger = logger_setup() @logger_inject_process_booking_sfn def handler(event, context): logger.info("Hello") handler(process_booking_event, lambda_context) log = json.loads(stdout.getvalue()) for key in logger_context_keys: assert key in log
def test_inject_lambda_context_log_event_request(root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with logger instructed to log event # WHEN logger is setup # THEN logger should log event received from Lambda lambda_event = {"greeting": "hello"} logger = logger_setup() @logger_inject_lambda_context(log_event=True) def handler(event, context): logger.info("Hello") handler(lambda_event, lambda_context) # Given that our string buffer has many log statements separated by newline \n # We need to clean it before we can assert on stdout.seek(0) logs = [json.loads(line.strip()) for line in stdout.readlines()] logged_event, _ = logs assert "greeting" in logged_event["message"]
def test_inject_lambda_cold_start(root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with logger, and called twice # WHEN logger is setup # THEN cold_start key should only be true in the first call from lambda_python_powertools.logging import logger # # As we run tests in parallel global cold_start value can be false # # here we reset to simulate the correct behaviour # # since Lambda will only import our logger lib once per concurrent execution logger.is_cold_start = True logger = logger_setup() def custom_method(): logger.info("Hello from method") @logger_inject_lambda_context def handler(event, context): custom_method() logger.info("Hello") handler({}, lambda_context) handler({}, lambda_context) # Given that our string buffer has many log statements separated by newline \n # We need to clean it before we can assert on stdout.seek(0) logs = [json.loads(line.strip()) for line in stdout.readlines()] first_log, second_log, third_log, fourth_log = logs # First execution assert "true" == first_log["cold_start"] assert "true" == second_log["cold_start"] # Second execution assert "false" == third_log["cold_start"] assert "false" == fourth_log["cold_start"]
def test_inject_lambda_context(root_logger, stdout, lambda_context): # GIVEN a lambda function is decorated with logger # WHEN logger is setup # THEN lambda contextual info should always be in the logs logger_context_keys = ( "function_name", "function_memory_size", "function_arn", "function_request_id", ) logger = logger_setup() @logger_inject_lambda_context def handler(event, context): logger.info("Hello") handler({}, lambda_context) log = json.loads(stdout.getvalue()) for key in logger_context_keys: assert key in log
import os import boto3 from botocore.exceptions import ClientError from lambda_python_powertools.logging import ( logger_inject_process_booking_sfn, logger_setup, MetricUnit, log_metric, ) from lambda_python_powertools.tracing import Tracer logger = logger_setup() tracer = Tracer() session = boto3.Session() dynamodb = session.resource("dynamodb") table_name = os.getenv("BOOKING_TABLE_NAME", "undefined") table = dynamodb.Table(table_name) _cold_start = True class BookingCancellationException(Exception): def __init__(self, message=None, status_code=None, details=None): super(BookingCancellationException, self).__init__() self.message = message or "Booking cancellation failed" self.status_code = status_code or 500