Skip to content

Commit b389df4

Browse files
committedFeb 6, 2022
Add heartbeat option for Loggers
If set, then the Logger will only log for Monitors which executed in this loop. Closes #636
1 parent 14f0b12 commit b389df4

File tree

7 files changed

+61
-4
lines changed

7 files changed

+61
-4
lines changed
 

‎.python-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.8.2
1+
3.10.1

‎docs/loggers.rst

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ These options are common to all logger types.
5656
* ``timestamp`` (UNIX timestamp)
5757
* ``iso8601`` (``YYYY-MM-DDTHH:MM:SS``)
5858

59+
.. confval:: heartbeat
60+
61+
:type: bool
62+
:required: false
63+
:default: ``false``
64+
65+
if set, the logger only logs for monitors which executed on an iteration. Intended to be combined with the :ref:`gap<gap>` property of a Monitor.
66+
5967
.. _loggers-list:
6068

6169
Loggers

‎old_docs/logging.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The section name should be the name of your logger. This is the name you should
2727
| depend | lists (comma-separated, no spaces) the names of the monitors this logger depends on. Use this if the database file lives over the network. If a monitor it depends on fails, no attempt will be made to update the database.| no | |
2828
| groups | comma-separated list of monitor groups this logger should operate for. Use `_all` to match all groups. | no | "default" |
2929
| tz | The [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) the logger should convert date/times to. | no | UTC |
30+
| heartbeat | If set, the logger only logs for monitors which executed on an iteration. Intended to be combined with the `gap` property of a Monitor. | no | 0 |
3031

3132
### <a name="db"></a><a name="dbstatus"></a>db and dbstatus loggers
3233

‎simplemonitor/Loggers/logger.py

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def __init__(self, config_options: Dict[str, Any]) -> None:
5353

5454
if self._global_info is None:
5555
self._global_info = {}
56+
self.heartbeat = cast(
57+
bool, self.get_config_option("heartbeat", required_type=bool, default=False)
58+
)
5659

5760
def __enter__(self) -> None:
5861
"""Context manager entry."""

‎simplemonitor/Monitors/monitor.py

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def __init__(
107107
self._force_run = True # set to ensure we re-run ASAP after a HUP
108108
if self._first_load is None:
109109
self._first_load = arrow.utcnow()
110+
self.ran_this_time = False
110111

111112
def get_config_option(
112113
self,

‎simplemonitor/simplemonitor.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ def reset_monitors(self) -> None:
402402
"""Clear all all monitors' dependency info back to default."""
403403
for key in list(self.monitors.keys()):
404404
self.monitors[key].reset_dependencies()
405+
self.monitors[key].ran_this_time = False
405406

406407
def _verify_dependencies(self) -> bool:
407408
"""Check if all monitors have valid dependencies."""
@@ -460,6 +461,7 @@ def _run_monitor(monitor: Monitor) -> bool:
460461
try:
461462
if monitor.should_run():
462463
did_run = True
464+
monitor.ran_this_time = True
463465
start_time = time.time()
464466
monitor.run_test()
465467
end_time = time.time()
@@ -585,16 +587,24 @@ def log_result(self, logger: Logger) -> None:
585587
logger.check_dependencies(self.failed + self.still_failing + self.skipped)
586588
with logger:
587589
for key, monitor in self.monitors.items():
588-
if check_group_match(monitor.group, logger.groups):
589-
logger.save_result2(key, monitor)
590-
else:
590+
if not check_group_match(monitor.group, logger.groups):
591591
module_logger.debug(
592592
"not logging for %s due to group mismatch (monitor in group %s, "
593593
"logger has groups %s",
594594
key,
595595
monitor.group,
596596
logger.groups,
597597
)
598+
continue
599+
if logger.heartbeat and not monitor.ran_this_time:
600+
module_logger.debug(
601+
"not logging for %s as this logger is in heartbeat mode and"
602+
" the monitor did not run this loop",
603+
key,
604+
)
605+
continue
606+
logger.save_result2(key, monitor)
607+
598608
try:
599609
# need to work on a copy here to prevent the dicts changing under us
600610
# during the loop, as remote instances can connect and update our data

‎tests/test_logger.py

+34
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,40 @@ def test_groups_all_match(self):
107107
s.log_result(this_logger)
108108
mock_method.assert_called_once()
109109

110+
def test_heartbeat_off(self):
111+
with patch.object(logger.Logger, "save_result2") as mock_method:
112+
this_logger = logger.Logger({})
113+
s = SimpleMonitor(Path("tests/monitor-empty.ini"))
114+
s.add_monitor("test", MonitorNull("unnamed"))
115+
s.add_logger("test", this_logger)
116+
s.run_loop()
117+
s.run_loop()
118+
self.assertEqual(mock_method.call_count, 2)
119+
120+
def test_heartbeat_on(self):
121+
with patch.object(logger.Logger, "save_result2") as mock_method:
122+
this_logger = logger.Logger({"heartbeat": 1})
123+
this_monitor = MonitorNull("unnamed", {"gap": 10})
124+
s = SimpleMonitor(Path("tests/monitor-empty.ini"))
125+
s.add_monitor("test", this_monitor)
126+
s.add_logger("test", this_logger)
127+
s.run_loop()
128+
s.run_loop()
129+
mock_method.assert_called_once()
130+
131+
def test_reset_monitor(self):
132+
s = SimpleMonitor(Path("tests/monitor-empty.ini"))
133+
s.add_monitor("monitor1", MonitorNull("monitor1"))
134+
s.add_monitor("monitor2", MonitorNull("monitor2", {"depend": "monitor1"}))
135+
s.run_loop()
136+
self.assertTrue(s.monitors["monitor1"].ran_this_time)
137+
self.assertTrue(s.monitors["monitor2"].ran_this_time)
138+
self.assertEqual(s.monitors["monitor2"].remaining_dependencies, [])
139+
s.reset_monitors()
140+
self.assertFalse(s.monitors["monitor1"].ran_this_time)
141+
self.assertFalse(s.monitors["monitor2"].ran_this_time)
142+
self.assertEqual(s.monitors["monitor2"].remaining_dependencies, ["monitor1"])
143+
110144

111145
class TestFileLogger(unittest.TestCase):
112146
@freeze_time("2020-04-18 12:00+00:00")

0 commit comments

Comments
 (0)
Please sign in to comment.