Repository: aws-powertools/powertools-lambda-python

Issue:
Logger: log_event does not serialize classes
**What were you trying to accomplish?**
I was trying to log the received S3 event. Please note that i am using the data classes present in this library for reading the event

```python
@event_source(data_class=S3Event)
@log.inject_lambda_context(
    log_event=True
)
def lambda_handler(event: S3Event, context: LambdaContext):
```

## Expected Behavior

The logged event should have all the information from the S3 event

## Current Behavior

This is the output i get in the log (trimmed)

```json
{
    "level": "INFO",
    "message": "<aws_lambda_powertools.utilities.data_classes.s3_event.S3Event object at 0x7f0be7efb2b0>",
    "timestamp": "2022-01-11 06:36:20,111+0000",
}
```

It looks to be that it was unable to properly represent the S3Event object as a string

## Possible Solution

Implement __repr__ and __str__ methods in S3Event class or in the parent DictWrapper class

## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1. Implement a lambda which receives and S3 event like the following
```python
@event_source(data_class=S3Event)
@log.inject_lambda_context(
    log_event=True
)
def lambda_handler(event: S3Event, context: LambdaContext):
   pass
```
2. Setup the lambda trigger as S3 object creation event
3. Upload a file in the S3 bucket where trigger is setup
4. See the logs in cloud watch

## Environment

* **Powertools version used**: 1.24.0
* **Packaging format (Layers, PyPi)**: PyPi
* **AWS Lambda function runtime:** 3.9
* **Debugging logs**

> [How to enable debug mode](https://awslabs.github.io/aws-lambda-powertools-python/#debug-mode)**

```python
# paste logs here
```



Discussion:
Thanks @kishaningithub . I will take a look at that. We had a related fix for idempotency. 

For now inverting the decorators:

```python3
@log.inject_lambda_context(log_event=True)
@event_source(data_class=S3Event)
def lambda_handler(event: S3Event, context: LambdaContext):
   pass
```

hey @kishaningithub thanks for raising that. The main reason we didn't do this is that these are untrusted strings. We weren't certain of the potential attack vectors this could cause (similar but not the same to Log4j).

Besides the fix of inverting the decorator, I'd be cautious on doing this in production as you might dump sensitive data into the logs.

All that being said, you can bring your own JSON serializer for Logger via [LambdaPowertoolsFormatter](https://awslabs.github.io/aws-lambda-powertools-python/latest/core/logger/#lambdapowertoolsformatter) - this would be an explicit way to opt-in to serialize any data you want.

Keen to hear your thoughts

Thank you!


Resolving patch:
diff --git a/aws_lambda_powertools/logging/logger.py b/aws_lambda_powertools/logging/logger.py
--- a/aws_lambda_powertools/logging/logger.py
+++ b/aws_lambda_powertools/logging/logger.py
@@ -349,7 +349,7 @@ def decorate(event, context, **kwargs):
 
             if log_event:
                 logger.debug("Event received")
-                self.info(event)
+                self.info(getattr(event, "raw_event", event))
 
             return lambda_handler(event, context)
 


Test patch:
diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py
--- a/tests/functional/test_logger.py
+++ b/tests/functional/test_logger.py
@@ -17,6 +17,7 @@
 from aws_lambda_powertools.logging.formatter import BasePowertoolsFormatter
 from aws_lambda_powertools.logging.logger import set_package_logger
 from aws_lambda_powertools.shared import constants
+from aws_lambda_powertools.utilities.data_classes import S3Event, event_source
 
 
 @pytest.fixture
@@ -635,3 +636,21 @@ def test_use_datetime(stdout, service_name, utc):
     assert re.fullmatch(
         f"custom timestamp: milliseconds=[0-9]+ microseconds=[0-9]+ timezone={re.escape(expected_tz)}", log["timestamp"]
     )
+
+
+def test_inject_lambda_context_log_event_request_data_classes(lambda_context, stdout, lambda_event, service_name):
+    # GIVEN Logger is initialized
+    logger = Logger(service=service_name, stream=stdout)
+
+    # WHEN a lambda function is decorated with logger instructed to log event
+    # AND the event is an event source data class
+    @event_source(data_class=S3Event)
+    @logger.inject_lambda_context(log_event=True)
+    def handler(event, context):
+        logger.info("Hello")
+
+    handler(lambda_event, lambda_context)
+
+    # THEN logger should log event received from Lambda
+    logged_event, _ = capture_multiple_logging_statements_output(stdout)
+    assert logged_event["message"] == lambda_event