Module log_verifier.
LogVer
The LogVer class is intended to be used during testing to allow a pytest test case to verify that the code under test issued log messages as expected. This is done by providing a collection of regex patterns that the LogVer will match up to the issued log messages. A report is printed to the syslog to show any patterns or messages that failed to match, and optionally the log messages that did match.
- Example1:
pytest test case logs a message and verifies
from scottbrian_utils.log_verifier import LogVer
import logging
def test_example1(caplog: pytest.LogCaptureFixture) -> None:
t_logger = logging.getLogger("example_1")
log_ver = LogVer(log_name="example_1")
log_msg = "hello"
log_ver.add_pattern(pattern=log_msg)
t_logger.debug(log_msg)
match_results = log_ver.get_match_results(caplog)
log_ver.print_match_results(match_results, print_matched=True)
log_ver.verify_match_results(match_results)
The output from LogVer.print_match_results()
for test_example1:
************************************************
* log verifier results *
************************************************
Start: Thu Apr 11 2024 19:24:28
End: Thu Apr 11 2024 19:24:28
Elapsed time: 0:00:00.006002
************************************************
* summary stats *
************************************************
type records matched unmatched
patterns 1 1 0
log_msgs 1 1 0
***********************
* unmatched patterns: *
***********************
*** no unmatched patterns found ***
***********************
* unmatched log_msgs: *
***********************
*** no unmatched log messages found ***
***********************
* matched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_1 10 hello 1 1 0
- Example2:
pytest test case expects two log records, only one is issued
from scottbrian_utils.log_verifier import LogVer
import logging
def test_example2(caplog: pytest.LogCaptureFixture) -> None:
t_logger = logging.getLogger("example_2")
log_ver = LogVer(log_name="example_2")
log_msg1 = "hello"
log_ver.add_pattern(pattern=log_msg1)
log_msg2 = "goodbye"
log_ver.add_pattern(pattern=log_msg2)
t_logger.debug(log_msg1)
match_results = log_ver.get_match_results(caplog)
log_ver.print_match_results(match_results, print_matched=True)
with pytest.raises(UnmatchedPatterns):
log_ver.verify_match_results(match_results)
The output from LogVer.print_match_results()
for test_example2:
************************************************
* log verifier results *
************************************************
Start: Thu Apr 11 2024 19:24:28
End: Thu Apr 11 2024 19:24:28
Elapsed time: 0:00:00.006002
************************************************
* summary stats *
************************************************
type records matched unmatched
patterns 2 1 1
log_msgs 1 1 0
***********************
* unmatched patterns: *
***********************
log_name level pattern fullmatch records matched unmatched
example_2 10 goodbye True 1 0 1
***********************
* unmatched log_msgs: *
***********************
*** no unmatched log messages found ***
***********************
* matched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_2 10 hello 1 1 0
- Example3:
pytest test case expects one log record, two were issued
from scottbrian_utils.log_verifier import LogVer
import logging
def test_example3(caplog: pytest.LogCaptureFixture) -> None:
t_logger = logging.getLogger("example_3")
log_ver = LogVer(log_name="example_3")
log_msg1 = "hello"
log_ver.add_pattern(pattern=log_msg1)
log_msg2 = "goodbye"
t_logger.debug(log_msg1)
t_logger.debug(log_msg2)
log_ver.print_match_results(
match_results := log_ver.get_match_results(caplog),
print_matched=True
)
with pytest.raises(UnmatchedLogMessages):
log_ver.verify_match_results(match_results)
The output from LogVer.print_match_results()
for test_example3:
************************************************
* log verifier results *
************************************************
Start: Thu Apr 11 2024 19:24:28
End: Thu Apr 11 2024 19:24:28
Elapsed time: 0:00:00.006002
************************************************
* summary stats *
************************************************
type records matched unmatched
patterns 1 1 0
log_msgs 2 1 1
***********************
* unmatched patterns: *
***********************
*** no unmatched patterns found ***
***********************
* unmatched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_3 10 goodbye 1 0 1
***********************
* matched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_3 10 hello 1 1 0
- Example4:
pytest test case expect two log records, two were issued, one different
from scottbrian_utils.log_verifier import LogVer
import logging
def test_example4(caplog: pytest.LogCaptureFixture) -> None:
t_logger = logging.getLogger("example_4")
log_ver = LogVer(log_name="example_4")
log_msg1 = "hello"
log_ver.add_pattern(pattern=log_msg1)
log_msg2a = "goodbye"
log_ver.add_pattern(pattern=log_msg2a)
log_msg2b = "see you soon"
t_logger.debug(log_msg1)
t_logger.debug(log_msg2b)
log_ver.print_match_results(
match_results := log_ver.get_match_results(caplog),
print_matched=True
)
with pytest.raises(UnmatchedPatterns):
log_ver.verify_match_results(match_results)
The output from LogVer.print_match_results()
for test_example4:
************************************************
* log verifier results *
************************************************
Start: Thu Apr 11 2024 19:24:28
End: Thu Apr 11 2024 19:24:28
Elapsed time: 0:00:00.006002
************************************************
* summary stats *
************************************************
type records matched unmatched
patterns 2 1 1
log_msgs 2 1 1
***********************
* unmatched patterns: *
***********************
log_name level pattern fullmatch records matched unmatched
example_4 10 goodbye True 1 0 1
***********************
* unmatched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_4 10 see you soon 1 0 1
***********************
* matched log_msgs: *
***********************
log_name level log_msg records matched unmatched
example_4 10 hello 1 1 0
The log_verifier module contains:
LogVer class with methods:
add_call_seq
get_call_seq
add_pattern
get_match_results
print_match_results
verify_match_results
- class log_verifier.LogVer(log_name='root', str_col_width=None)
Log Message Verification Class.
Initialize a LogVer object.
- Parameters:
log_name (
str
) – name of the loggerstr_col_width (
Optional
[int
]) – If specifief, limits the maximum width for string values in the display produced by method print_match_results. The string values that are limited are for columns log_name, log_msg, pattern, and fullmatch. The specified limit must be an int with a value of 9 or greater.
Example: create a logger and a LogVer instance >>> logger = logging.getLogger(‘example_logger’) >>> log_ver = LogVer(‘example_logger’)
- add_call_seq(name, seq)
Add a call sequence for a given name.
- Parameters:
name (
str
) – name for whom the call sequence representsseq (
str
) – the call sequence in a format as described by get_formatted_call_sequence in diag_msg.py from the scottbrian_utils package
- Return type:
None
- add_msg(log_msg, log_level=10, log_name=None, fullmatch=False)
Add a message to the expected log messages.
- Parameters:
log_msg (
str
) – expected message to addlog_level (
int
) – expected logging levellog_name (
Optional
[str
]) – expected logger namefullmatch (
bool
) – if True, use regex fullmatch instead of match in method get_match_results
- Return type:
None
Deprecated since version 3.0.0: Use method
add_pattern()
instead.
- add_pattern(pattern, level=10, log_name=None, fullmatch=True)
Add a pattern to be matched to a log message.
- Parameters:
pattern (
str
) – pattern to use to find log_msg in the loglevel (
int
) – logging level to uselog_name (
Optional
[str
]) – logger name to usefullmatch (
bool
) – if True, use regex fullmatch in method get_match_results, otherwise use regex match
- Return type:
None
Added in version 3.0.0: Method
add_pattern()
replaces methodadd_msg()
.Example: add two patterns, each at a different level
def test_example(caplog: pytest.LogCaptureFixture) -> None: t_logger = logging.getLogger("example_5") log_ver = LogVer("example_5") log_msg1 = "hello" log_msg2 = "goodbye" log_ver.add_pattern(pattern=log_msg1) log_ver.add_pattern(pattern=log_msg2, level=logging.ERROR) t_logger.debug(log_msg1) t_logger.error(log_msg2) match_results = log_ver.get_match_results(caplog=caplog) log_ver.print_match_results(match_results, print_matched=True) log_ver.verify_match_results(match_results)
The output from
LogVer.print_match_results()
for test_example:************************************************ * log verifier results * ************************************************ Start: Thu Apr 11 2024 19:24:28 End: Thu Apr 11 2024 19:24:28 Elapsed time: 0:00:00.006002 ************************************************ * summary stats * ************************************************ type records matched unmatched patterns 2 2 0 log_msgs 2 2 0 *********************** * unmatched patterns: * *********************** *** no unmatched patterns found *** *********************** * unmatched log_msgs: * *********************** *** no unmatched log messages found *** *********************** * matched log_msgs: * *********************** log_name level log_msg records matched unmatched example_5 10 hello 1 1 0 example_5 40 goodbye 1 1 0
- get_call_seq(name)
Retrieve a call sequence by name.
- Parameters:
name (
str
) – name for whom the call sequence represents- Return type:
str
- Returns:
- the call sequence in a format as described by
get_formatted_call_sequence in diag_msg.py with the regex string “:[0-9]*” appended to represent the source line number to match
- get_match_results(caplog)
Match the patterns to log records.
- Parameters:
caplog (
LogCaptureFixture
) – pytest fixture that captures log messages- Return type:
MatchResults
- Returns:
MatchResults object, which contain the results of the matching operation. This will include a summary for the patterns and messages, and the data frames containing the patterns and messaged used to print and verify the results.
- print_df(df_to_print, col_names, left_justify_col_names)
Prin the data set to screen.
- Parameters:
df_to_print (
DataFrame
) – the dataframe to printcol_names (
list
[str
]) – list of column names to be printedleft_justify_col_names (
list
[str
]) – list of column names to be printed left justified
- Return type:
None
- print_match_results(match_results, print_matched=False)
Print the match results.
- Parameters:
match_results (
MatchResults
) – contains the results to be printedprint_matched (
bool
) – if True, print the matched records, otherwise skip printing the matched records
- Return type:
None
Changed in version 3.0.0: print_matched keyword default changed to False
- static search_df(avail_df, search_arg_df, search_targ_df, targ_work_grp, min_potential_matches)
Search the data frames for matches.
- Parameters:
avail_df (
DataFrame
) – data frame of available entriessearch_arg_df (
DataFrame
) – data frame that has the search argsearch_targ_df (
DataFrame
) – data frame that has the search targettarg_work_grp (
DataFrame
) – work group dataframe that has the target avail countmin_potential_matches (
int
) – the currently known minimum number of non-zero potential matches that need to be processed
- Return type:
None
- test_msg(log_msg, level=10)
Issue a log msg and add its pattern.
- Parameters:
log_msg (
str
) – log message to issuelevel (
int
) – logging level to use
- Return type:
None
Notes
This method makes it easier to issue a log message in a test case by also adding the pattern.
Added in version 3.0.0.
Example: issue a test msg
def test_example(caplog: pytest.LogCaptureFixture) -> None: log_ver = LogVer("example_6") log_ver.test_msg("my test message") match_results = log_ver.get_match_results(caplog=caplog) log_ver.print_match_results(match_results, print_matched=True) log_ver.verify_match_results(match_results)
The output from
LogVer.print_match_results()
for test_example:************************************************ * log verifier results * ************************************************ Start: Thu Apr 11 2024 19:24:28 End: Thu Apr 11 2024 19:24:28 Elapsed time: 0:00:00.006002 ************************************************ * summary stats * ************************************************ type records matched unmatched patterns 1 1 0 log_msgs 1 1 0 *********************** * unmatched patterns: * *********************** *** no unmatched patterns found *** *********************** * unmatched log_msgs: * *********************** *** no unmatched log messages found *** *********************** * matched log_msgs: * *********************** log_name level log_msg records matched unmatched example_6 10 my test msg 1 1 0
- static verify_log_results(match_results)
Verify that each log message issued is as expected.
- Parameters:
match_results (
MatchResults
) – contains the results to be verified- Return type:
None
Deprecated since version 3.0.0: Use method
verify_match_results()
instead.- Raises:
UnmatchedExpectedMessages – There are expected log messages that failed to match actual log messages.
UnmatchedActualMessages – There are actual log messages that failed to match expected log messages.
- static verify_match_results(match_results)
Verify that each log message issued is as expected.
- Parameters:
match_results (
MatchResults
) – contains the results to be verified- Raises:
UnmatchedPatterns – One or more patterns failed to match their intended log messages. The patterns and/or the log messages may have been incorrectly specified.
UnmatchedLogMessages – One or more log messages failed to be matched by corresponding patterns. The patterns and/or the log messages may have been incorrectly specified.
- Return type:
None