# The following code and documentation was inspired, and in some cases # copied and modified, from the work of Vinay Sajip and contributors # on cpython's logging package import os import time import types from collections.abc import Mapping from typing import Optional, Tuple, Type from aiologger.levels import LogLevel, get_level_name ExceptionInfo = Tuple[Type[BaseException], BaseException, types.TracebackType] class LogRecord: """ A LogRecord instance represents an event being logged. ExtendedLogRecord instances are created every time something is logged. They contain all the information pertinent to the event being logged. The main information passed in is in msg and args, which are combined using str(msg) % args to create the message field of the record. The record also includes information such as when the record was created, the source line where the logging call was made, and any exception information to be logged. """ def __init__( self, name: str, level: LogLevel, pathname: str, lineno: int, msg, args: Optional[Tuple[Mapping]] = None, exc_info: Optional[ExceptionInfo] = None, func: Optional[str] = None, sinfo: Optional[str] = None, **kwargs, ) -> None: """ :param name: The name of the logger used to log the event represented by this LogRecord. Note that this name will always have this value, even though it may be emitted by a handler attached to a different (ancestor) logger. :param level: The numeric level of the logging event (one of DEBUG, INFO etc.) Note that this is converted to two attributes of the LogRecord: levelno for the numeric value and levelname for the corresponding level name. :param pathname: The full pathname of the source file where the logging call was made. :param lineno: The line number in the source file where the logging call was made. :param msg: The event description message, possibly a format string with placeholders for variable data. :param args: Variable data to merge into the msg argument to obtain the event description. :param exc_info: An exception tuple with the current exception information, or None if no exception information is available. :param func: The name of the function or method from which the logging call was invoked. :param sinfo: A text string representing stack information from the base of the stack in the current thread, up to the logging call. """ created_at = time.time() self.name = name self.msg = msg self.args: Optional[Mapping] if args: if len(args) != 1 or not isinstance(args[0], Mapping): raise ValueError( f"Invalid LogRecord args type: {type(args[0])}. " f"Expected Mapping" ) self.args: Optional[Mapping] = args[0] else: self.args = args self.levelname = get_level_name(level) self.levelno = level self.pathname = pathname try: self.filename = os.path.basename(pathname) self.module = os.path.splitext(self.filename)[0] except (TypeError, ValueError, AttributeError): self.filename = pathname self.module = "Unknown module" self.exc_info = exc_info self.exc_text: Optional[str] = None # used to cache the traceback text self.stack_info = sinfo self.lineno = lineno self.funcName = func self.created = created_at self.msecs = (created_at - int(created_at)) * 1000 self.process = os.getpid() self.asctime: Optional[str] = None self.message: Optional[str] = None def __str__(self): return ( f"<{self.__class__.__name__}: {self.name}, {self.levelname}, " f'{self.pathname}, {self.lineno}, "{self.msg}">' ) __repr__ = __str__ def get_message(self): """ Return the message for this LogRecord after merging any user-supplied arguments with the message. """ msg = str(self.msg) if self.args: msg = msg % self.args return msg class ExtendedLogRecord(LogRecord): def __init__( self, name: str, level: LogLevel, pathname: str, lineno: int, msg, args: Optional[Tuple[Mapping]], exc_info: Optional[ExceptionInfo], func: Optional[str] = None, sinfo: Optional[str] = None, **kwargs, ) -> None: super().__init__( name, level, pathname, lineno, msg, args, exc_info, func, sinfo ) self.extra = kwargs["extra"] self.flatten = kwargs["flatten"] self.serializer_kwargs = kwargs["serializer_kwargs"]