Source code for vcorelib.logging.list
"""
A module implementing a logger interface that uses lists.
"""
# built-in
import logging
from typing import Iterator
# third-party
from vcorelib.logging.args import DEFAULT_TIME_FORMAT
[docs]
class ListLogger(logging.Handler):
"""An interface facilitating sending log messages to browser tabs."""
max_size: int = 2**10
dropped: int
log_messages: list[logging.LogRecord]
[docs]
def drain(self) -> list[logging.LogRecord]:
"""Drain messages."""
result = self.log_messages
self.log_messages = []
return result
[docs]
def drain_str_iter(self) -> Iterator[str]:
"""Iterate over string messages."""
for record in self.drain():
yield (
self.format(record)
# Respect 'external' logs that don't warrant full formatting.
if not getattr(record, "external", False)
else record.getMessage()
)
# Create a message for drops.
if self.dropped:
yield (
f"(logger dropped {self.dropped} messages, "
f"max_size={self.max_size})"
)
self.dropped = 0
[docs]
def drain_str(self) -> list[str]:
"""Drain formatted messages."""
return list(self.drain_str_iter())
def __bool__(self) -> bool:
"""Evaluate this instance as boolean."""
return bool(self.log_messages)
[docs]
def emit(self, record: logging.LogRecord) -> None:
"""Send the log message."""
# Could do something with the lost messages at some point.
while len(self.log_messages) >= self.max_size:
self.log_messages.pop(0)
self.dropped += 1
self.log_messages.append(record)
[docs]
@staticmethod
def create(fmt: str = DEFAULT_TIME_FORMAT) -> "ListLogger":
"""Create an instance of this handler."""
logger = ListLogger()
logger.log_messages = []
logger.dropped = 0
logger.setFormatter(logging.Formatter(fmt))
return logger