feat: improve colorized logging

This commit is contained in:
sebthom
2024-12-27 15:35:58 +01:00
parent f90f848cba
commit e077f8d86d
4 changed files with 47 additions and 51 deletions

42
pdm.lock generated
View File

@@ -5,7 +5,7 @@
groups = ["default", "dev"] groups = ["default", "dev"]
strategy = [] strategy = []
lock_version = "4.5.0" lock_version = "4.5.0"
content_hash = "sha256:6aa6f02f71070c93d191e7242d0986a66d73173b39bfbc6568ffcbf3deb9f647" content_hash = "sha256:819a55a6259056418a7d6ba23fefef909ad33f9f73d626662e28a18438b199e0"
[[metadata.targets]] [[metadata.targets]]
requires_python = ">=3.10,<3.14" requires_python = ">=3.10,<3.14"
@@ -112,19 +112,6 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
] ]
[[package]]
name = "coloredlogs"
version = "15.0.1"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Colored terminal output for Python's logging module"
dependencies = [
"humanfriendly>=9.1",
]
files = [
{file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
{file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
]
[[package]] [[package]]
name = "deprecated" name = "deprecated"
version = "1.2.15" version = "1.2.15"
@@ -158,21 +145,6 @@ files = [
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
] ]
[[package]]
name = "humanfriendly"
version = "10.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Human friendly output for text interfaces using Python"
dependencies = [
"monotonic; python_version == \"2.7\"",
"pyreadline3; sys_platform == \"win32\" and python_version >= \"3.8\"",
"pyreadline; sys_platform == \"win32\" and python_version < \"3.8\"",
]
files = [
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
]
[[package]] [[package]]
name = "iniconfig" name = "iniconfig"
version = "2.0.0" version = "2.0.0"
@@ -362,7 +334,7 @@ version = "0.38.post1"
requires_python = ">=3.9" requires_python = ">=3.9"
git = "https://github.com/ultrafunkamsterdam/nodriver.git" git = "https://github.com/ultrafunkamsterdam/nodriver.git"
revision = "ec6c3fcd8ea18638d6d2b76d5245bed11cbf4aa2" revision = "ec6c3fcd8ea18638d6d2b76d5245bed11cbf4aa2"
summary = "\r\n [Docs here](https://ultrafunkamsterdam.github.io/nodriver)\r\n\r\n * Official successor of Undetected Chromedriver\r\n * Can be made to work for for all chromium based browsers.\r\n * Dropped selenium and chromedriver binary requirements.\r\n * fully asynchronous == bizarre performance gains, and more granular control\r\n\r\n Part of undetected-chromedriver, or merely the successor of it, this library is a full rewrite, providing a\r\n fast framework for web automation, webscraping, bots and any other creative ideas which are normally\r\n hindered by annoying anti bot systems like Captcha / CloudFlare / Imperva / hCaptcha and other\r\n big corp \"ai\" money machines using your input to make even more $$ (http://tinyurl.com/bigcorp-ai-inputs)\r\n\r\n The webdriver/selenium requirement is dropped entirely, since this library communicates directly to the browser.\r\n Being fully asynchronous, this adds massive performance improvements and more detailed control possibilities.\r\n\r\n As usual ( like undetected chromedriver) all config details and best practices are built-in, which means\r\n up and running with just a line of code.\r\n\r\n This makes it simple to use for quick prototyping, and perfect for interactive interpreter use (eg: IPython).\r\n\r\n\r\n WARNING:\r\n - results may vary due to many factors. No guarantees are given whatsoever.\r\n - Running from bad IP or datacenter may still cause captcha's and/or other problems.\r\n - With great power comes ... etc etc etc\r\n no but SERIOUS: for your own benefit, make sure \"they\" have no reason for upscaling anti-bot measurements.\r\n there might be one day it would not be feasible anymore to work up against big corp, and provide upgrades\r\n and free libraries.\r\n\r\n" summary = "[Docs here](https://ultrafunkamsterdam.github.io/nodriver)"
dependencies = [ dependencies = [
"deprecated", "deprecated",
"mss", "mss",
@@ -523,16 +495,6 @@ files = [
{file = "pylint-3.3.3.tar.gz", hash = "sha256:07c607523b17e6d16e2ae0d7ef59602e332caa762af64203c24b41c27139f36a"}, {file = "pylint-3.3.3.tar.gz", hash = "sha256:07c607523b17e6d16e2ae0d7ef59602e332caa762af64203c24b41c27139f36a"},
] ]
[[package]]
name = "pyreadline3"
version = "3.5.4"
requires_python = ">=3.8"
summary = "A python implementation of GNU readline."
files = [
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
]
[[package]] [[package]]
name = "pyright" name = "pyright"
version = "1.1.391" version = "1.1.391"

View File

@@ -18,7 +18,6 @@ datas = [
excluded_modules = [ excluded_modules = [
"_aix_support", "_aix_support",
"_pydecimal",
"argparse", "argparse",
"bz2", "bz2",
"ftplib", "ftplib",

View File

@@ -33,7 +33,6 @@ classifiers = [ # https://pypi.org/classifiers/
requires-python = ">=3.10,<3.14" requires-python = ">=3.10,<3.14"
dependencies = [ dependencies = [
"colorama", "colorama",
"coloredlogs",
"nodriver @ git+https://github.com/ultrafunkamsterdam/nodriver.git", "nodriver @ git+https://github.com/ultrafunkamsterdam/nodriver.git",
"jaraco.text", # required by pkg_resources during runtime "jaraco.text", # required by pkg_resources during runtime
"ruamel.yaml", "ruamel.yaml",

View File

@@ -11,7 +11,7 @@ from gettext import gettext as _
from types import FrameType, ModuleType, TracebackType from types import FrameType, ModuleType, TracebackType
from typing import Any, Final, TypeVar from typing import Any, Final, TypeVar
import coloredlogs import colorama
from ruamel.yaml import YAML from ruamel.yaml import YAML
from .i18n import get_translating_logger from .i18n import get_translating_logger
@@ -154,17 +154,53 @@ def safe_get(a_map:dict[Any, Any], *keys:str) -> Any:
def configure_console_logging() -> None: def configure_console_logging() -> None:
class LevelTranslatingFormatter(coloredlogs.ColoredFormatter): # type: ignore class CustomFormatter(logging.Formatter):
LEVEL_COLORS = {
logging.DEBUG: colorama.Fore.BLACK + colorama.Style.BRIGHT,
logging.INFO: colorama.Fore.BLACK + colorama.Style.BRIGHT,
logging.WARNING: colorama.Fore.YELLOW,
logging.ERROR: colorama.Fore.RED,
logging.CRITICAL: colorama.Fore.RED,
}
MESSAGE_COLORS = {
logging.DEBUG: colorama.Fore.BLACK + colorama.Style.BRIGHT,
logging.INFO: colorama.Fore.RESET,
logging.WARNING: colorama.Fore.YELLOW,
logging.ERROR: colorama.Fore.RED,
logging.CRITICAL: colorama.Fore.RED + colorama.Style.BRIGHT,
}
VALUE_COLORS = {
logging.DEBUG: colorama.Fore.BLACK + colorama.Style.BRIGHT,
logging.INFO: colorama.Fore.MAGENTA,
logging.WARNING: colorama.Fore.MAGENTA,
logging.ERROR: colorama.Fore.MAGENTA,
logging.CRITICAL: colorama.Fore.MAGENTA,
}
def format(self, record:logging.LogRecord) -> str: def format(self, record:logging.LogRecord) -> str:
msg:str = super().format(record) record = copy.deepcopy(record)
if record.levelno > logging.DEBUG:
levelname = _(record.levelname)
if levelname != record.levelname:
msg = msg.replace(record.levelname, levelname, 1)
return msg
formatter = LevelTranslatingFormatter("[%(levelname)s] %(message)s") level_color = self.LEVEL_COLORS.get(record.levelno, "")
msg_color = self.MESSAGE_COLORS.get(record.levelno, "")
value_color = self.VALUE_COLORS.get(record.levelno, "")
# translate and colorize log level name
levelname = _(record.levelname) if record.levelno > logging.DEBUG else record.levelname
record.levelname = f"{level_color}[{levelname}]{colorama.Style.RESET_ALL}"
# highlight message values enclosed by [...], "...", and '...'
record.msg = re.sub(
r"\[([^\]]+)\]|\"([^\"]+)\"|\'([^\']+)\'",
lambda match: f"[{value_color}{match.group(1) or match.group(2) or match.group(3)}{colorama.Fore.RESET}{msg_color}]",
str(record.msg),
)
# colorize message
record.msg = f"{msg_color}{record.msg}{colorama.Style.RESET_ALL}"
return super().format(record)
formatter = CustomFormatter("%(levelname)s %(message)s")
stdout_log = logging.StreamHandler(sys.stderr) stdout_log = logging.StreamHandler(sys.stderr)
stdout_log.setLevel(logging.DEBUG) stdout_log.setLevel(logging.DEBUG)