# Copyright (c) 2023-2024 Thomas Mathieson.
# Distributed under the terms of the MIT license.
import logging
from abc import abstractmethod
from io import TextIOBase
from typing import Union, TextIO
# This module provides a basic wrapper around the python logging module, to standardise the logging format and make
# logging code more concise.
[docs]
class SSVLogStream(TextIOBase):
"""
A StringIO pipe for sending log messages with a severity level.
"""
[docs]
@abstractmethod
def write(self, text: str, severity: int = logging.INFO) -> int:
"""
Called to write a log message to the stream.
:param text: the message to log.
:param severity: the severity to log the message with.
:return: the number of characters written to the stream.
"""
...
[docs]
class SSVStreamHandler(logging.StreamHandler):
stream: Union[SSVLogStream, TextIO]
def __init__(self, stream=None):
super().__init__()
if stream is not None:
self.stream = stream
[docs]
def emit(self, record: logging.LogRecord) -> None:
# Small modification of the build in StreamHandler to pass the log level to the stream
# noinspection PyBroadException
try:
msg = self.format(record)
stream = self.stream
if isinstance(stream, SSVLogStream):
stream.write(msg + self.terminator, severity=record.levelno)
else:
stream.write(msg + self.terminator)
self.flush()
except RecursionError:
raise
except Exception:
self.handleError(record)
[docs]
def set_output_stream(stream: TextIOBase, level=logging.INFO, prefix="pySSV"):
handler = SSVStreamHandler(stream)
handler.setFormatter(make_formatter(prefix))
handler.setLevel(level)
_ssv_logger.addHandler(handler)
[docs]
def set_severity(severity: int):
"""
Sets the minimum message severity to be logged.
:param severity: the logging severity as an integer. Preset severity levels are defined in the ``logging`` module.
Possible values include: ``logging.DEBUG``, ``logging.INFO``, ``logging.WARN``, ``logging.ERROR``,
etc...
"""
_ssv_logger.setLevel(severity)
[docs]
def get_severity() -> int:
"""
Gets the minimum severity level of the current logger.
:return: the minimum severity level of the logger.
"""
return _ssv_logger.level
[docs]
def log(msg, *args, severity=logging.DEBUG, raw=False):
"""
Logs a message to the console.
:param msg: message to log to the console
:param args: objects to log to the console
:param severity: the severity to log the message with, severity levels are defined in the ``logging`` module.
:param raw: logs the message without any formatting
"""
_ssv_logger.log(severity, msg, *args, stacklevel=3, extra={"raw": raw})
if "_ssv_logger" not in globals():
logging.basicConfig()
_ssv_logger = logging.getLogger("pySSV")
# Steal all the default log handlers
# for h in logging.getLogger(None).handlers:
# _ssv_logger.addHandler(h)
_ssv_logger.setLevel(logging.INFO)
formatter = make_formatter()
for h in _ssv_logger.handlers:
h.setFormatter(formatter)