Skip to content

Commit 259da97

Browse files
committed
Truncate buffer to prevent overflow
1 parent fff6114 commit 259da97

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

mqlog/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,18 @@ def format(self, record):
7070
# Named with an underscore to avoid conflict with logging.Handler.flush
7171
async def _flush(self):
7272
if self.buffer:
73+
# Try to publish, but if we fail, just log the error – don't
74+
# want to cause cascading errors. Something else is responsible
75+
# for bringing the connection back up.
7376
try:
7477
msg = "\n".join([line for line in self.buffer])
7578
await self.client.publish(self.topic, msg, qos=self.qos)
7679
self.buffer.clear()
7780
except Exception as e:
7881
self._logger.error("Failed to publish logs", exc_info=e)
7982
self.will_flush.clear()
83+
84+
# If we were supposed to flush but couldn't, truncate the buffer
85+
# to prevent it from growing indefinitely
86+
if self.buffer and len(self.buffer) >= self.capacity:
87+
self.buffer = self.buffer[-self.capacity :]

tests/test_handler.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ def setUp(self):
2222
self.logger.addHandler(self.handler)
2323
self.logger.setLevel(logging.INFO)
2424

25+
def tearDown(self):
26+
"""Clean up after each test"""
27+
self.handler.buffer.clear()
28+
self.handler.will_flush.clear()
29+
2530
def test_default_formatter(self):
2631
"""Handler should use default formatter if none is set"""
2732
self.handler.setFormatter(None)
@@ -103,3 +108,26 @@ async def do_test(handler: logging.Handler, logger: logging.Logger):
103108
call("test_topic", "Test message 3\nTest message 4", qos=0),
104109
]
105110
)
111+
112+
def test_buffer_overflow(self):
113+
"""Buffer should get truncated if it exceeds capacity"""
114+
self.handler.capacity = 3
115+
self.client.publish = AsyncMock(side_effect=Exception("Publish failed"))
116+
117+
async def do_test(handler: logging.Handler, logger: logging.Logger):
118+
asyncio.create_task(handler.run())
119+
await asyncio.sleep(0.1)
120+
logger.info("Test message 1")
121+
await asyncio.sleep(0.1)
122+
logger.info("Test message 2")
123+
await asyncio.sleep(0.1)
124+
logger.info("Test message 3")
125+
await asyncio.sleep(0.1)
126+
logger.info("Test message 4") # This will fail to flush
127+
await asyncio.sleep(0.1)
128+
129+
asyncio.run(do_test(self.handler, self.logger))
130+
131+
self.assertEqual(
132+
self.handler.buffer, ["Test message 2", "Test message 3", "Test message 4"]
133+
)

0 commit comments

Comments
 (0)