Skip to content

Commit 51fb8e2

Browse files
feat: merge develop into main (#368)
BREAKING CHANGE: add logging function for basic error types
2 parents 2952714 + 9cb5638 commit 51fb8e2

File tree

2 files changed

+86
-8
lines changed

2 files changed

+86
-8
lines changed

solnlib/log.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import logging.handlers
2121
import os.path as op
2222
import traceback
23+
from functools import partial
2324
from threading import Lock
2425
from typing import Dict, Any
2526

@@ -251,6 +252,31 @@ def modular_input_end(logger: logging.Logger, modular_input_name: str):
251252
)
252253

253254

255+
def _base_error_log(
256+
logger,
257+
exc: Exception,
258+
exe_label,
259+
full_msg: bool = True,
260+
msg_before: str = None,
261+
msg_after: str = None,
262+
):
263+
log_exception(
264+
logger,
265+
exc,
266+
exc_label=exe_label,
267+
full_msg=full_msg,
268+
msg_before=msg_before,
269+
msg_after=msg_after,
270+
)
271+
272+
273+
log_connection_error = partial(_base_error_log, exe_label="Connection Error")
274+
log_configuration_error = partial(_base_error_log, exe_label="Configuration Error")
275+
log_permission_error = partial(_base_error_log, exe_label="Permission Error")
276+
log_authentication_error = partial(_base_error_log, exe_label="Authentication Error")
277+
log_server_error = partial(_base_error_log, exe_label="Server Error")
278+
279+
254280
def events_ingested(
255281
logger: logging.Logger,
256282
modular_input_name: str,
@@ -303,12 +329,34 @@ def events_ingested(
303329
def log_exception(
304330
logger: logging.Logger,
305331
e: Exception,
332+
exc_label: str,
306333
full_msg: bool = True,
307334
msg_before: str = None,
308335
msg_after: str = None,
309336
log_level: int = logging.ERROR,
310337
):
311-
"""General function to log exceptions."""
338+
"""General function to log exceptions.
339+
340+
Arguments:
341+
logger: Add-on logger.
342+
e: Exception to log.
343+
exc_label: label for the error to categorize it.
344+
full_msg: if set to True, full traceback will be logged. Default: True
345+
msg_before: custom message before exception traceback. Default: None
346+
msg_after: custom message after exception traceback. Default: None
347+
log_level: Log level to log exception. Default: ERROR.
348+
"""
349+
350+
msg = _get_exception_message(e, full_msg, msg_before, msg_after)
351+
logger.log(log_level, f'exc_l="{exc_label}" {msg}')
352+
353+
354+
def _get_exception_message(
355+
e: Exception,
356+
full_msg: bool = True,
357+
msg_before: str = None,
358+
msg_after: str = None,
359+
) -> str:
312360
exc_type, exc_value, exc_traceback = type(e), e, e.__traceback__
313361
if full_msg:
314362
error = traceback.format_exception(exc_type, exc_value, exc_traceback)
@@ -318,5 +366,4 @@ def log_exception(
318366
msg_start = msg_before if msg_before is not None else ""
319367
msg_mid = "".join(error)
320368
msg_end = msg_after if msg_after is not None else ""
321-
msg = f"{msg_start}\n{msg_mid}\n{msg_end}"
322-
logger.log(log_level, msg)
369+
return f"{msg_start}\n{msg_mid}\n{msg_end}"

tests/unit/test_log.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,10 @@ def test_log_exceptions_full_msg():
247247
test_jsons = "{'a': 'aa'"
248248
json.loads(test_jsons)
249249
except Exception as e:
250-
log.log_exception(mock_logger, e, msg_before=start_msg)
250+
log.log_exception(mock_logger, e, "test type1", msg_before=start_msg)
251251
mock_logger.log.assert_called_with(
252-
logging.ERROR, f"{start_msg}\n{traceback.format_exc()}\n"
252+
logging.ERROR,
253+
f'exc_l="test type1" {start_msg}\n{traceback.format_exc()}\n',
253254
)
254255

255256

@@ -262,10 +263,40 @@ def test_log_exceptions_partial_msg():
262263
json.loads(test_jsons)
263264
except Exception as e:
264265
log.log_exception(
265-
mock_logger, e, full_msg=False, msg_before=start_msg, msg_after=end_msg
266+
mock_logger,
267+
e,
268+
exc_label="test type",
269+
full_msg=False,
270+
msg_before=start_msg,
271+
msg_after=end_msg,
266272
)
267273
mock_logger.log.assert_called_with(
268274
logging.ERROR,
269-
"some msg before exception\njson.decoder.JSONDecodeError: Expecting property name enclosed in double "
270-
"quotes: line 1 column 2 (char 1)\n\nsome msg after exception",
275+
'exc_l="test type" some msg before exception\njson.decoder.JSONDecodeError: Expecting property '
276+
"name enclosed in double quotes: line 1 column 2 (char 1)\n\nsome msg after exception",
277+
)
278+
279+
280+
@pytest.mark.parametrize(
281+
"func,result",
282+
[
283+
("log_connection_error", '"Connection Error"'),
284+
("log_configuration_error", '"Configuration Error"'),
285+
("log_permission_error", '"Permission Error"'),
286+
("log_authentication_error", '"Authentication Error"'),
287+
("log_server_error", '"Server Error"'),
288+
],
289+
)
290+
def test_log_basic_error(func, result):
291+
class AddonComplexError(Exception):
292+
pass
293+
294+
with mock.patch("logging.Logger") as mock_logger:
295+
try:
296+
raise AddonComplexError
297+
except AddonComplexError as e:
298+
fun = getattr(log, func)
299+
fun(mock_logger, e)
300+
mock_logger.log.assert_called_with(
301+
logging.ERROR, f"exc_l={result} \n{traceback.format_exc()}\n"
271302
)

0 commit comments

Comments
 (0)