diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py index cfda64bc8e6..0140d057f0d 100644 --- a/aws_lambda_powertools/logging/formatter.py +++ b/aws_lambda_powertools/logging/formatter.py @@ -126,6 +126,24 @@ def _extract_log_exception(self, log_record: logging.LogRecord) -> Optional[str] return None + def _extract_log_exception_name(self, log_record: logging.LogRecord) -> Optional[str]: + """Extract the exception name, if available + + Parameters + ---------- + log_record : logging.LogRecord + Log record to extract exception name from + + Returns + ------- + log_record: Optional[str] + Log record with exception name + """ + if log_record.exc_info: + return log_record.exc_info[0].__name__ + + return None + def _extract_log_keys(self, log_record: logging.LogRecord) -> Dict: """Extract and parse custom and reserved log keys @@ -164,6 +182,7 @@ def _extract_log_keys(self, log_record: logging.LogRecord) -> Dict: def format(self, record): # noqa: A003 formatted_log = self._extract_log_keys(log_record=record) formatted_log["message"] = self._extract_log_message(log_record=record) + formatted_log["exception_name"] = self._extract_log_exception_name(log_record=record) formatted_log["exception"] = self._extract_log_exception(log_record=record) formatted_log.update({"xray_trace_id": self._get_latest_trace_id()}) # fetch latest Trace ID, if any diff --git a/docs/core/logger.md b/docs/core/logger.md index 0e8cca2700c..2c5c347eadf 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -451,7 +451,7 @@ You can also change the order of the following log record keys via the `log_reco #### Logging exceptions -When logging exceptions, Logger will add a new key named `exception`, and will serialize the full traceback as a string. +When logging exceptions, Logger will add new keys named `exception_name` and `exception` with the full traceback as a string. === "logging_an_exception.py" @@ -475,6 +475,7 @@ When logging exceptions, Logger will add a new key named `exception`, and will s "timestamp": "2020-08-28 18:11:38,886", "service": "service_undefined", "sampling_rate": 0.0, + "exception_name":"ValueError", "exception": "Traceback (most recent call last):\n File \"\", line 2, in \nValueError: something went wrong" } ``` diff --git a/tests/functional/test_logger.py b/tests/functional/test_logger.py index 4e1ab245141..2b4c7cf187e 100644 --- a/tests/functional/test_logger.py +++ b/tests/functional/test_logger.py @@ -422,3 +422,18 @@ def test_logger_log_twice_when_log_filter_isnt_present_and_root_logger_is_setup( # since child's log records propagated to root logger should be rejected logs = list(stdout.getvalue().strip().split("\n")) assert len(logs) == 4 + + +def test_logger_exception_extract_exception_name(stdout, service_name): + # GIVEN Logger is initialized + logger = Logger(service=service_name, stream=stdout) + + # WHEN calling a logger.exception with a ValueError + try: + raise ValueError("something went wrong") + except Exception: + logger.exception("Received an exception") + + # THEN we expect a "exception_name" to be "ValueError" + log = capture_logging_output(stdout) + assert "ValueError" == log["exception_name"]