Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add a PeriodicallyFlushingMemoryHandler to prevent logging silence #10407

Merged
merged 12 commits into from
Jul 27, 2021
1 change: 1 addition & 0 deletions changelog.d/10407.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a buffered logging handler which periodically flushes itself.
5 changes: 4 additions & 1 deletion docs/sample_log_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ handlers:
# will be a delay for INFO/DEBUG logs to get written, but WARNING/ERROR
# logs will still be flushed immediately.
buffer:
class: logging.handlers.MemoryHandler
class: synapse.logging.handlers.PeriodicallyFlushingMemoryHandler
target: file
# The capacity is the number of log lines that are buffered before
# being written to disk. Increasing this will lead to better
# performance, at the expensive of it taking longer for log lines to
# be written to disk.
capacity: 10
flushLevel: 30 # Flush for WARNING logs as well
# The period of time, in seconds, between forced flushes.
# Messages will not be delayed for longer than this time.
period: 5

# A handler that writes logs to stderr. Unused by default, but can be used
# instead of "buffer" and "file" in the logger handlers.
Expand Down
5 changes: 4 additions & 1 deletion synapse/config/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,17 @@
# will be a delay for INFO/DEBUG logs to get written, but WARNING/ERROR
# logs will still be flushed immediately.
buffer:
class: logging.handlers.MemoryHandler
class: synapse.logging.handlers.PeriodicallyFlushingMemoryHandler
target: file
# The capacity is the number of log lines that are buffered before
# being written to disk. Increasing this will lead to better
# performance, at the expensive of it taking longer for log lines to
# be written to disk.
capacity: 10
flushLevel: 30 # Flush for WARNING logs as well
# The period of time, in seconds, between forced flushes.
# Messages will not be delayed for longer than this time.
period: 5

# A handler that writes logs to stderr. Unused by default, but can be used
# instead of "buffer" and "file" in the logger handlers.
Expand Down
47 changes: 47 additions & 0 deletions synapse/logging/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import logging
import time
from logging import Handler
from logging.handlers import MemoryHandler
from threading import Thread
from typing import Optional


class PeriodicallyFlushingMemoryHandler(MemoryHandler):
"""
This is a subclass of MemoryHandler that additionally spawns a background
thread to periodically flush the buffer.

This prevents messages from being buffered for too long.
"""

def __init__(
self,
capacity: int,
flushLevel: int = logging.ERROR,
target: Optional[Handler] = None,
flushOnClose: bool = True,
period: float = 5.0,
) -> None:
super().__init__(capacity, flushLevel, target, flushOnClose)

self._flush_period: float = period
self._active: bool = True

self._flushing_thread: Thread = Thread(
name="PeriodicallyFlushingMemoryHandler flushing thread",
target=self._flush_periodically,
)
self._flushing_thread.start()

def _flush_periodically(self):
"""
Whilst this handler is active, flush the handler periodically.
"""

while self._active:
self.flush()
reivilibre marked this conversation as resolved.
Show resolved Hide resolved
time.sleep(self._flush_period)

def close(self) -> None:
self._active = False
super().close()