Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
24 changes: 24 additions & 0 deletions solnlib/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import logging
import logging.handlers
import os.path as op
import sys
import traceback
from threading import Lock
from typing import Dict, Any

Expand Down Expand Up @@ -263,3 +265,25 @@ def events_ingested(
"n_events": n_events,
},
)


def log_exception(
logger: logging.Logger,
e: Exception,
full_msg: bool = True,
msg_before: str = None,
msg_after: str = None,
log_level: int = logging.INFO,
):
"""General function to log exceptions."""
exc_type, exc_value, exc_traceback = type(e), e, e.__traceback__
if full_msg:
error = traceback.format_exception(exc_type, exc_value, exc_traceback)
else:
error = traceback.format_exception_only(exc_type, exc_value)

msg_start = msg_before if msg_before is not None else ""
msg_mid = "".join(error)
msg_end = msg_after if msg_after is not None else ""
msg = f"{msg_start}\n{msg_mid}\n{msg_end}"
logger.log(log_level, msg)
33 changes: 33 additions & 0 deletions tests/unit/test_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
#

import logging
import json
import multiprocessing
import os
import shutil
import threading
import traceback
import time
from unittest import mock

Expand Down Expand Up @@ -197,3 +199,34 @@ def test_events_ingested():
logging.INFO,
"action=events_ingested modular_input_name=modular_input_name sourcetype_ingested=sourcetype n_events=5",
)


def test_log_exceptions_full_msg():
start_msg = "some msg before exception"
with mock.patch("logging.Logger") as mock_logger:
try:
test_jsons = "{'a': 'aa'"
json.loads(test_jsons)
except Exception as e:
log.log_exception(mock_logger, e, msg_before=start_msg)
mock_logger.log.assert_called_with(
logging.INFO, f"{start_msg}\n{traceback.format_exc()}\n"
)


def test_log_exceptions_partial_msg():
start_msg = "some msg before exception"
end_msg = "some msg after exception"
with mock.patch("logging.Logger") as mock_logger:
try:
test_jsons = "{'a': 'aa'"
json.loads(test_jsons)
except Exception as e:
log.log_exception(
mock_logger, e, full_msg=False, msg_before=start_msg, msg_after=end_msg
)
mock_logger.log.assert_called_with(
logging.INFO,
"some msg before exception\njson.decoder.JSONDecodeError: Expecting property name enclosed in double "
"quotes: line 1 column 2 (char 1)\n\nsome msg after exception",
)