Skip to content

feat(logging): Include exception_name #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions aws_lambda_powertools/logging/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion docs/core/logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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 \"<input>\", line 2, in <module>\nValueError: something went wrong"
}
```
Expand Down
15 changes: 15 additions & 0 deletions tests/functional/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]