Coverage for tests/test_logging.py: 9%

84 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-25 09:27 +0000

1# This file is part of utils. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# Use of this source code is governed by a 3-clause BSD-style 

10# license that can be found in the LICENSE file. 

11 

12import logging 

13import time 

14import unittest 

15 

16from lsst.utils.logging import PeriodicLogger, getLogger, trace_set_at 

17 

18 

19class TestLogging(unittest.TestCase): 

20 """Simple unit tests for Task logging.""" 

21 

22 def testLogLevels(self): 

23 """Check that the new log levels look reasonable.""" 

24 root = getLogger() 

25 

26 self.assertEqual(root.DEBUG, logging.DEBUG) 

27 self.assertGreater(root.VERBOSE, logging.DEBUG) 

28 self.assertLess(root.VERBOSE, logging.INFO) 

29 self.assertLess(root.TRACE, logging.DEBUG) 

30 

31 def testLogCommands(self): 

32 """Check that all the log commands work.""" 

33 root = getLogger() 

34 

35 with self.assertLogs(level=root.TRACE) as cm: 

36 root.trace("Trace") 

37 root.debug("Debug") 

38 root.verbose("Verbose") 

39 root.verbose("Verbose with stacklevel", stacklevel=1) 

40 root.info("Info") 

41 root.warning("Warning") 

42 root.fatal("Fatal") 

43 root.critical("Critical") 

44 root.error("Error") 

45 

46 self.assertEqual(len(cm.records), 9) 

47 

48 # Check that each record has an explicit level name rather than 

49 # "Level N" and comes from this file (and not the logging.py). 

50 for record in cm.records: 

51 self.assertRegex(record.levelname, "^[A-Z]+$") 

52 self.assertEqual(record.filename, "test_logging.py") 

53 

54 with self.assertLogs(level=root.DEBUG) as cm: 

55 # Should only issue the INFO message. 

56 with root.temporary_log_level(root.INFO): 

57 root.info("Info") 

58 root.debug("Debug") 

59 self.assertEqual(len(cm.records), 1) 

60 

61 child = root.getChild("child") 

62 self.assertEqual(child.getEffectiveLevel(), root.getEffectiveLevel()) 

63 

64 # The root logger could be modified by the test environment. 

65 # We need to pick a level that is different. 

66 child.setLevel(root.getEffectiveLevel() - 5) 

67 self.assertNotEqual(child.getEffectiveLevel(), root.getEffectiveLevel()) 

68 

69 def testTraceSetAt(self): 

70 log_name = "lsst.afw" 

71 root_level = logging.getLogger().getEffectiveLevel() 

72 trace_set_at(log_name, 2) 

73 trace2_log = getLogger(f"TRACE2.{log_name}") 

74 trace3_log = getLogger(f"TRACE3.{log_name}") 

75 self.assertEqual(trace2_log.getEffectiveLevel(), logging.DEBUG) 

76 self.assertEqual(trace3_log.getEffectiveLevel(), logging.INFO) 

77 

78 # Check that child loggers are affected. 

79 log_name = "lsst.daf" 

80 child3_log = getLogger("TRACE3.lsst.daf") 

81 child2_log = getLogger("TRACE2.lsst.daf") 

82 self.assertEqual(child3_log.getEffectiveLevel(), root_level) 

83 self.assertEqual(child2_log.getEffectiveLevel(), root_level) 

84 trace_set_at("lsst", 2) 

85 self.assertEqual(child3_log.getEffectiveLevel(), logging.INFO) 

86 self.assertEqual(child2_log.getEffectiveLevel(), logging.DEBUG) 

87 

88 # Also check the root logger. 

89 trace_set_at("", 3) 

90 self.assertEqual(trace3_log.getEffectiveLevel(), logging.INFO) 

91 self.assertEqual(getLogger("TRACE3.test").getEffectiveLevel(), logging.DEBUG) 

92 

93 def test_periodic(self): 

94 logger = getLogger("test.periodicity") 

95 periodic = PeriodicLogger(logger) 

96 

97 # First message will not be issued. 

98 periodic.log("Message") 

99 self.assertEqual(periodic.num_issued, 0) 

100 

101 # Create a new periodic logger with no delay. 

102 # Every message should be issued. 

103 periodic = PeriodicLogger(logger, interval=0.0) 

104 with self.assertLogs(logger.name, level=logger.VERBOSE) as cm: 

105 periodic.log("Message") 

106 periodic.log("Message %d", 1) 

107 self.assertEqual(len(cm.output), 2) 

108 self.assertEqual(periodic.num_issued, 2) 

109 self.assertEqual(cm.output[0], f"VERBOSE:{logger.name}:Message") 

110 self.assertEqual(cm.output[1], f"VERBOSE:{logger.name}:Message 1") 

111 self.assertEqual(cm.records[0].filename, "test_logging.py", str(cm.records[0])) 

112 

113 # Create a new periodic logger with small delay. 

114 # One message should be issued. 

115 periodic = PeriodicLogger(logger, interval=0.2, level=logger.INFO) 

116 with self.assertLogs(logger.name, level=logger.INFO) as cm: 

117 periodic.log("Message") 

118 time.sleep(0.5) 

119 issued = periodic.log("Message %d", 1) 

120 self.assertTrue(issued) 

121 issued = periodic.log("Message %d", 2) 

122 self.assertFalse(issued) 

123 self.assertEqual(periodic.num_issued, 1) 

124 self.assertEqual(cm.output[0], f"INFO:{logger.name}:Message 1") 

125 

126 # Again with a standard python Logger. 

127 pylog = logging.getLogger("python.logger") 

128 periodic = PeriodicLogger(pylog, interval=0.0, level=logging.DEBUG) 

129 with self.assertLogs(pylog.name, level=logging.DEBUG) as cm: 

130 periodic.log("Message") 

131 self.assertEqual(cm.records[0].filename, "test_logging.py", str(cm.records[0])) 

132 

133 

134if __name__ == "__main__": 

135 unittest.main()