Log switch to bitwise flag settings for console format type
Has the following settings TIME, TIME_SECONDS, TIME_MILLISECONDS, TIME_MICROSECONDS: enable time output in different formats TIME and TIME_MILLISECONDS are equivalent, if multiple are set the smallest precision wins TIMEZONE: add time zone to time output NAME: log group name FILE: short file name FUNCTION: function name LINENO: line number There is a class with quick grouped settings ConsoleFormatSettings ALL: all options enabled, time is in milliseconds CONDENSED: time without time zone, file and line number MINIMAL: only time without time zone BARE: only the message, no other info
This commit is contained in:
@@ -11,6 +11,7 @@ from datetime import datetime
|
||||
import time
|
||||
from pathlib import Path
|
||||
import atexit
|
||||
from enum import Flag, auto
|
||||
from typing import MutableMapping, TextIO, TypedDict, Any, TYPE_CHECKING, cast
|
||||
from corelibs.logging_handling.logging_level_handling.logging_level import LoggingLevel
|
||||
from corelibs.string_handling.text_colors import Colors
|
||||
@@ -20,6 +21,38 @@ if TYPE_CHECKING:
|
||||
from multiprocessing import Queue
|
||||
|
||||
|
||||
class ConsoleFormat(Flag):
|
||||
"""console format type bitmap flags"""
|
||||
TIME = auto()
|
||||
TIME_SECONDS = auto()
|
||||
TIME_MILLISECONDS = auto()
|
||||
TIME_MICROSECONDS = auto()
|
||||
TIMEZONE = auto()
|
||||
NAME = auto()
|
||||
FILE = auto()
|
||||
FUNCTION = auto()
|
||||
LINENO = auto()
|
||||
|
||||
|
||||
class ConsoleFormatSettings:
|
||||
"""Console format quick settings groups"""
|
||||
# shows everything, time with milliseconds, and time zone, log name, file, function, line number
|
||||
ALL = (
|
||||
ConsoleFormat.TIME |
|
||||
ConsoleFormat.TIMEZONE |
|
||||
ConsoleFormat.NAME |
|
||||
ConsoleFormat.FILE |
|
||||
ConsoleFormat.FUNCTION |
|
||||
ConsoleFormat.LINENO
|
||||
)
|
||||
# show time with no time zone, file and line
|
||||
CONDENSED = ConsoleFormat.TIME | ConsoleFormat.FILE | ConsoleFormat.LINENO
|
||||
# only time
|
||||
MINIMAL = ConsoleFormat.TIME
|
||||
# only message
|
||||
BARE = ConsoleFormat(0)
|
||||
|
||||
|
||||
# MARK: Log settings TypedDict
|
||||
class LogSettings(TypedDict):
|
||||
"""log settings, for Log setup"""
|
||||
@@ -28,8 +61,7 @@ class LogSettings(TypedDict):
|
||||
per_run_log: bool
|
||||
console_enabled: bool
|
||||
console_color_output_enabled: bool
|
||||
console_format_type: str
|
||||
console_iso_precision: str
|
||||
console_format_type: ConsoleFormat
|
||||
add_start_info: bool
|
||||
add_end_info: bool
|
||||
log_queue: 'Queue[str] | None'
|
||||
@@ -41,18 +73,6 @@ class LoggerInit(TypedDict):
|
||||
log_queue: 'Queue[str] | None'
|
||||
|
||||
|
||||
# show log title, file, function and line number types
|
||||
CONSOLE_FORMAT_TYPE_NORMAL = 'normal'
|
||||
# show file and line number only
|
||||
CONSOLE_FORMAT_TYPE_CONDENSED = 'condensed'
|
||||
# only show timestamp, log level and message
|
||||
CONSOLE_FORMAT_TYPE_MINIMAL = 'minimal'
|
||||
# for console ISO time format
|
||||
CONSOLE_ISO_TIME_SECONDS = 'seconds'
|
||||
CONSOLE_ISO_TIME_MILLISECONDS = 'milliseconds'
|
||||
CONSOLE_ISO_TIME_MICROSECONDS = 'microseconds'
|
||||
|
||||
|
||||
# MARK: Custom color filter
|
||||
class CustomConsoleFormatter(logging.Formatter):
|
||||
"""
|
||||
@@ -70,21 +90,6 @@ class CustomConsoleFormatter(logging.Formatter):
|
||||
LoggingLevel.EXCEPTION.name: Colors.magenta_bright, # will never be written to console
|
||||
}
|
||||
|
||||
# def formatTime(self, record: logging.LogRecord, datefmt: str | None = None):
|
||||
# """
|
||||
# Set timestamp in ISO8601 format
|
||||
|
||||
# Arguments:
|
||||
# record {logging.LogRecord} -- _description_
|
||||
|
||||
# Keyword Arguments:
|
||||
# datefmt {str | None} -- _description_ (default: {None})
|
||||
|
||||
# Returns:
|
||||
# _type_ -- _description_
|
||||
# """
|
||||
# return datetime.fromtimestamp(record.created).astimezone().isoformat(sep=' ', timespec='milliseconds')
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
"""
|
||||
set the color highlight
|
||||
@@ -439,8 +444,7 @@ class Log(LogParent):
|
||||
"console_enabled": True,
|
||||
"console_color_output_enabled": True,
|
||||
# do not print log title, file, function and line number
|
||||
"console_format_type": CONSOLE_FORMAT_TYPE_NORMAL,
|
||||
"console_iso_precision": CONSOLE_ISO_TIME_MILLISECONDS,
|
||||
"console_format_type": ConsoleFormatSettings.ALL,
|
||||
"add_start_info": True,
|
||||
"add_end_info": False,
|
||||
"log_queue": None,
|
||||
@@ -451,7 +455,10 @@ class Log(LogParent):
|
||||
self,
|
||||
log_path: Path,
|
||||
log_name: str,
|
||||
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str]'] | LogSettings | None = None,
|
||||
log_settings: (
|
||||
dict[str, 'LoggingLevel | str | bool | None | Queue[str] | ConsoleFormat'] | # noqa: E501 # pylint: disable=line-too-long
|
||||
LogSettings | None
|
||||
) = None,
|
||||
other_handlers: dict[str, Any] | None = None
|
||||
):
|
||||
LogParent.__init__(self)
|
||||
@@ -496,7 +503,6 @@ class Log(LogParent):
|
||||
'stream_handler',
|
||||
self.log_settings['log_level_console'],
|
||||
console_format_type=self.log_settings['console_format_type'],
|
||||
console_iso_precision=self.log_settings['console_iso_precision']
|
||||
))
|
||||
# add other handlers,
|
||||
if other_handlers is not None:
|
||||
@@ -523,7 +529,8 @@ class Log(LogParent):
|
||||
# MARK: parse log settings
|
||||
def __parse_log_settings(
|
||||
self,
|
||||
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str]'] | LogSettings | None
|
||||
log_settings: dict[str, 'LoggingLevel | str | bool | None | Queue[str] | ConsoleFormat'] | # noqa: E501 # pylint: disable=line-too-long
|
||||
LogSettings | None
|
||||
) -> LogSettings:
|
||||
# skip with defaul it not set
|
||||
if log_settings is None:
|
||||
@@ -554,26 +561,9 @@ class Log(LogParent):
|
||||
__setting = self.DEFAULT_LOG_SETTINGS.get(__log_entry, True)
|
||||
default_log_settings[__log_entry] = __setting
|
||||
# check console log type
|
||||
default_log_settings['console_format_type'] = cast('str', log_settings.get(
|
||||
default_log_settings['console_format_type'] = cast('ConsoleFormat', log_settings.get(
|
||||
'console_format_type', self.DEFAULT_LOG_SETTINGS['console_format_type']
|
||||
))
|
||||
# if not valid
|
||||
if default_log_settings['console_format_type'] not in [
|
||||
CONSOLE_FORMAT_TYPE_NORMAL,
|
||||
CONSOLE_FORMAT_TYPE_CONDENSED,
|
||||
CONSOLE_FORMAT_TYPE_MINIMAL,
|
||||
]:
|
||||
default_log_settings['console_format_type'] = self.DEFAULT_LOG_SETTINGS['console_format_type']
|
||||
# check console iso time precision
|
||||
default_log_settings['console_iso_precision'] = cast('str', log_settings.get(
|
||||
'console_iso_precision', self.DEFAULT_LOG_SETTINGS['console_iso_precision']
|
||||
))
|
||||
if default_log_settings['console_iso_precision'] not in [
|
||||
CONSOLE_ISO_TIME_SECONDS,
|
||||
CONSOLE_ISO_TIME_MILLISECONDS,
|
||||
CONSOLE_ISO_TIME_MICROSECONDS,
|
||||
]:
|
||||
default_log_settings['console_iso_precision'] = self.DEFAULT_LOG_SETTINGS['console_iso_precision']
|
||||
# check log queue
|
||||
__setting = log_settings.get('log_queue', self.DEFAULT_LOG_SETTINGS['log_queue'])
|
||||
if __setting is not None:
|
||||
@@ -612,51 +602,89 @@ class Log(LogParent):
|
||||
self, handler_name: str,
|
||||
log_level_console: LoggingLevel = LoggingLevel.WARNING,
|
||||
filter_exceptions: bool = True,
|
||||
console_format_type: str = CONSOLE_FORMAT_TYPE_NORMAL,
|
||||
console_iso_precision: str = CONSOLE_ISO_TIME_MILLISECONDS
|
||||
console_format_type: ConsoleFormat = ConsoleFormatSettings.ALL,
|
||||
) -> logging.StreamHandler[TextIO]:
|
||||
# console logger
|
||||
if not self.validate_log_level(log_level_console):
|
||||
log_level_console = self.DEFAULT_LOG_LEVEL_CONSOLE
|
||||
console_handler = logging.StreamHandler()
|
||||
# format layouts
|
||||
format_string = (
|
||||
# '[%(asctime)s.%(msecs)03d] '
|
||||
'[%(asctime)s] '
|
||||
'[%(name)s] '
|
||||
'[%(filename)s:%(funcName)s:%(lineno)d] '
|
||||
'<%(levelname)s> '
|
||||
'%(message)s'
|
||||
)
|
||||
if console_format_type == CONSOLE_FORMAT_TYPE_CONDENSED:
|
||||
format_string = (
|
||||
'[%(asctime)s] '
|
||||
'[%(filename)s:%(lineno)d] '
|
||||
'<%(levelname)s> '
|
||||
'%(message)s'
|
||||
)
|
||||
elif console_format_type == CONSOLE_FORMAT_TYPE_MINIMAL:
|
||||
format_string = (
|
||||
'[%(asctime)s] '
|
||||
'<%(levelname)s> '
|
||||
'%(message)s'
|
||||
)
|
||||
format_date = "%Y-%m-%d %H:%M:%S"
|
||||
print(f"Console format type: {console_format_type}")
|
||||
# build the format string based on what flags are set
|
||||
format_string = ''
|
||||
# time part if any of the times are requested
|
||||
if (
|
||||
ConsoleFormat.TIME in console_format_type or
|
||||
ConsoleFormat.TIME_SECONDS in console_format_type or
|
||||
ConsoleFormat.TIME_MILLISECONDS in console_format_type or
|
||||
ConsoleFormat.TIME_MICROSECONDS in console_format_type
|
||||
):
|
||||
format_string += '[%(asctime)s] '
|
||||
# set log name
|
||||
if ConsoleFormat.NAME in console_format_type:
|
||||
format_string += '[%(name)s] '
|
||||
# for any file/function/line number call
|
||||
if (
|
||||
ConsoleFormat.FILE in console_format_type or
|
||||
ConsoleFormat.FUNCTION in console_format_type or
|
||||
ConsoleFormat.LINENO in console_format_type
|
||||
):
|
||||
format_string += '['
|
||||
set_group: list[str] = []
|
||||
if ConsoleFormat.FILE in console_format_type:
|
||||
set_group.append('%(filename)s')
|
||||
if ConsoleFormat.FUNCTION in console_format_type:
|
||||
set_group.append('%(funcName)s')
|
||||
if ConsoleFormat.LINENO in console_format_type:
|
||||
set_group.append('%(lineno)d')
|
||||
format_string += ':'.join(set_group)
|
||||
format_string += '] '
|
||||
# always level + message
|
||||
format_string += '<%(levelname)s> %(message)s'
|
||||
# basic date, but this will be overridden to ISO in formatTime
|
||||
# format_date = "%Y-%m-%d %H:%M:%S"
|
||||
# color or not
|
||||
if self.log_settings['console_color_output_enabled']:
|
||||
formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
||||
# formatter_console = CustomConsoleFormatter(format_string, datefmt=format_date)
|
||||
formatter_console = CustomConsoleFormatter(format_string)
|
||||
else:
|
||||
formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
||||
print(f"PREC: {console_iso_precision}")
|
||||
# this one needs lambda self, ...
|
||||
# logging.Formatter.formatTime = (
|
||||
formatter_console.formatTime = (
|
||||
lambda record, datefmt=None:
|
||||
datetime
|
||||
.fromtimestamp(record.created)
|
||||
.astimezone()
|
||||
.isoformat(sep="T", timespec=console_iso_precision)
|
||||
)
|
||||
# formatter_console = logging.Formatter(format_string, datefmt=format_date)
|
||||
formatter_console = logging.Formatter(format_string)
|
||||
# default for TIME is milliseconds
|
||||
# if we have multiple set, the smallest precision wins
|
||||
if ConsoleFormat.TIME_MICROSECONDS in console_format_type:
|
||||
iso_precision = 'microseconds'
|
||||
elif (
|
||||
ConsoleFormat.TIME_MILLISECONDS in console_format_type or
|
||||
ConsoleFormat.TIME in console_format_type
|
||||
):
|
||||
iso_precision = 'milliseconds'
|
||||
elif ConsoleFormat.TIME_SECONDS in console_format_type:
|
||||
iso_precision = 'seconds'
|
||||
else:
|
||||
iso_precision = 'milliseconds'
|
||||
# do timestamp modification only if we have time requested
|
||||
if (
|
||||
ConsoleFormat.TIME in console_format_type or
|
||||
ConsoleFormat.TIME_SECONDS in console_format_type or
|
||||
ConsoleFormat.TIME_MILLISECONDS in console_format_type or
|
||||
ConsoleFormat.TIME_MICROSECONDS in console_format_type
|
||||
):
|
||||
# if we have with TZ we as the asttimezone call
|
||||
if ConsoleFormat.TIMEZONE in console_format_type:
|
||||
formatter_console.formatTime = (
|
||||
lambda record, datefmt=None:
|
||||
datetime
|
||||
.fromtimestamp(record.created)
|
||||
.astimezone()
|
||||
.isoformat(sep=" ", timespec=iso_precision)
|
||||
)
|
||||
else:
|
||||
formatter_console.formatTime = (
|
||||
lambda record, datefmt=None:
|
||||
datetime
|
||||
.fromtimestamp(record.created)
|
||||
.isoformat(sep=" ", timespec=iso_precision)
|
||||
)
|
||||
console_handler.set_name(handler_name)
|
||||
console_handler.setLevel(log_level_console.name)
|
||||
# do not show exceptions logs on console
|
||||
|
||||
Reference in New Issue
Block a user