mirror of
https://github.com/PaiGramTeam/PamGram.git
synced 2024-11-21 21:58:04 +00:00
🐛 Fix Logger
Fix the issue of incorrect colors being printed by logger when running on Linux
This commit is contained in:
parent
b3b836fb15
commit
eed8c3ad9c
@ -1,6 +1,6 @@
|
|||||||
from multiprocessing import RLock as Lock
|
from multiprocessing import RLock as Lock
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Union
|
from typing import List, Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseSettings
|
from pydantic import BaseSettings
|
||||||
|
|
||||||
@ -22,17 +22,28 @@ class LoggerConfig(BaseSettings):
|
|||||||
cls._instance = result
|
cls._instance = result
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
name: str = "logger"
|
name: str = "PaiGram-logger"
|
||||||
|
"""logger 名称"""
|
||||||
level: Optional[Union[str, int]] = None
|
level: Optional[Union[str, int]] = None
|
||||||
|
"""logger 的 level"""
|
||||||
|
|
||||||
debug: bool = False
|
debug: bool = False
|
||||||
|
"""是否 debug"""
|
||||||
width: Optional[int] = None
|
width: Optional[int] = None
|
||||||
|
"""输出时的宽度"""
|
||||||
keywords: List[str] = []
|
keywords: List[str] = []
|
||||||
|
"""高亮的关键字"""
|
||||||
time_format: str = "[%Y-%m-%d %X]"
|
time_format: str = "[%Y-%m-%d %X]"
|
||||||
|
"""时间格式"""
|
||||||
capture_warnings: bool = True
|
capture_warnings: bool = True
|
||||||
|
"""是否捕获 warning"""
|
||||||
|
color_system: Literal["auto", "standard", "256", "truecolor", "windows"] = "auto"
|
||||||
|
"""颜色模式: 自动、标准、256色、真彩、Windows模式"""
|
||||||
|
|
||||||
log_path: Union[str, Path] = "./logs"
|
log_path: Union[str, Path] = "./logs"
|
||||||
|
"""log 所保存的路径,项目根目录的相对路径"""
|
||||||
project_root: Union[str, Path] = PROJECT_ROOT
|
project_root: Union[str, Path] = PROJECT_ROOT
|
||||||
|
"""项目根目录"""
|
||||||
|
|
||||||
traceback_max_frames: int = 20
|
traceback_max_frames: int = 20
|
||||||
traceback_locals_max_depth: Optional[int] = None
|
traceback_locals_max_depth: Optional[int] = None
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, Iterable, List, Literal, Optional, TYPE_CHECKING, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Literal,
|
||||||
|
Optional,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.logging import LogRender as DefaultLogRender, RichHandler as DefaultRichHandler
|
from rich.logging import LogRender as DefaultLogRender, RichHandler as DefaultRichHandler
|
||||||
@ -15,22 +23,26 @@ from utils.log._file import FileIO
|
|||||||
from utils.log._style import DEFAULT_STYLE
|
from utils.log._style import DEFAULT_STYLE
|
||||||
from utils.log._traceback import Traceback
|
from utils.log._traceback import Traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ujson as json
|
||||||
|
from ujson import JSONDecodeError
|
||||||
|
except ImportError:
|
||||||
|
import json
|
||||||
|
from json import JSONDecodeError
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from logging import LogRecord # pylint: disable=unused-import
|
from rich.console import (
|
||||||
|
ConsoleRenderable,
|
||||||
|
RenderableType,
|
||||||
|
)
|
||||||
|
from logging import LogRecord
|
||||||
|
|
||||||
from rich.console import ConsoleRenderable, RenderableType # pylint: disable=unused-import
|
__all__ = ["LogRender", "Handler", "FileHandler"]
|
||||||
|
|
||||||
__all__ = ("LogRender", "Handler", "FileHandler")
|
|
||||||
|
|
||||||
FormatTimeCallable = Callable[[datetime], Text]
|
FormatTimeCallable = Callable[[datetime], Text]
|
||||||
|
|
||||||
logging.addLevelName(5, "TRACE")
|
logging.addLevelName(5, "TRACE")
|
||||||
logging.addLevelName(25, "SUCCESS")
|
logging.addLevelName(25, "SUCCESS")
|
||||||
color_system: Literal["windows", "truecolor"]
|
|
||||||
if sys.platform == "win32":
|
|
||||||
color_system = "windows"
|
|
||||||
else:
|
|
||||||
color_system = "truecolor"
|
|
||||||
|
|
||||||
|
|
||||||
class LogRender(DefaultLogRender):
|
class LogRender(DefaultLogRender):
|
||||||
@ -108,7 +120,9 @@ class Handler(DefaultRichHandler):
|
|||||||
tracebacks_max_frames: int = 100,
|
tracebacks_max_frames: int = 100,
|
||||||
keywords: Optional[List[str]] = None,
|
keywords: Optional[List[str]] = None,
|
||||||
log_time_format: Union[str, FormatTimeCallable] = "[%x %X]",
|
log_time_format: Union[str, FormatTimeCallable] = "[%x %X]",
|
||||||
project_root: Union[str, Path] = "./logs",
|
color_system: Literal["auto", "standard", "256", "truecolor", "windows"] = "auto",
|
||||||
|
project_root: Union[str, Path] = os.getcwd(),
|
||||||
|
auto_load_json: bool = False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> None:
|
) -> None:
|
||||||
super(Handler, self).__init__(*args, rich_tracebacks=rich_tracebacks, **kwargs)
|
super(Handler, self).__init__(*args, rich_tracebacks=rich_tracebacks, **kwargs)
|
||||||
@ -116,9 +130,10 @@ class Handler(DefaultRichHandler):
|
|||||||
self.console = Console(color_system=color_system, theme=Theme(DEFAULT_STYLE), width=width)
|
self.console = Console(color_system=color_system, theme=Theme(DEFAULT_STYLE), width=width)
|
||||||
self.tracebacks_show_locals = True
|
self.tracebacks_show_locals = True
|
||||||
self.tracebacks_max_frames = tracebacks_max_frames
|
self.tracebacks_max_frames = tracebacks_max_frames
|
||||||
self.keywords = self.KEYWORDS + (keywords or [])
|
self.render_keywords = self.KEYWORDS + (keywords or [])
|
||||||
self.locals_max_depth = locals_max_depth
|
self.locals_max_depth = locals_max_depth
|
||||||
self.project_root = project_root
|
self.project_root = project_root
|
||||||
|
self.auto_load_json = auto_load_json
|
||||||
|
|
||||||
def render(
|
def render(
|
||||||
self,
|
self,
|
||||||
@ -153,15 +168,13 @@ class Handler(DefaultRichHandler):
|
|||||||
log_time = datetime.fromtimestamp(record.created)
|
log_time = datetime.fromtimestamp(record.created)
|
||||||
|
|
||||||
if not traceback:
|
if not traceback:
|
||||||
traceback_content = [message_renderable]
|
renderables = [message_renderable]
|
||||||
elif message_renderable is not None:
|
|
||||||
traceback_content = [message_renderable, traceback]
|
|
||||||
else:
|
else:
|
||||||
traceback_content = [traceback]
|
renderables = [message_renderable, traceback] if message_renderable is not None else [traceback]
|
||||||
|
|
||||||
log_renderable = self._log_render(
|
log_renderable = self._log_render(
|
||||||
self.console,
|
self.console,
|
||||||
traceback_content,
|
renderables,
|
||||||
log_time=log_time,
|
log_time=log_time,
|
||||||
time_format=time_format,
|
time_format=time_format,
|
||||||
level=_level,
|
level=_level,
|
||||||
@ -177,10 +190,8 @@ class Handler(DefaultRichHandler):
|
|||||||
message: Any,
|
message: Any,
|
||||||
) -> "ConsoleRenderable":
|
) -> "ConsoleRenderable":
|
||||||
use_markup = getattr(record, "markup", self.markup)
|
use_markup = getattr(record, "markup", self.markup)
|
||||||
tag = getattr(record, "tag", None)
|
|
||||||
if isinstance(message, str):
|
if isinstance(message, str):
|
||||||
message_text = Text.from_markup(message) if use_markup else Text(message)
|
message_text = Text.from_markup(message) if use_markup else Text(message)
|
||||||
message_text = (Text.from_markup(f"[purple][{tag}][/]") + message_text) if tag is not None else message_text
|
|
||||||
highlighter = getattr(record, "highlighter", self.highlighter)
|
highlighter = getattr(record, "highlighter", self.highlighter)
|
||||||
else:
|
else:
|
||||||
from rich.highlighter import JSONHighlighter
|
from rich.highlighter import JSONHighlighter
|
||||||
@ -188,17 +199,16 @@ class Handler(DefaultRichHandler):
|
|||||||
|
|
||||||
highlighter = JSONHighlighter()
|
highlighter = JSONHighlighter()
|
||||||
message_text = JSON.from_data(message, indent=4).text
|
message_text = JSON.from_data(message, indent=4).text
|
||||||
message_text = (Text.from_markup(f"[purple][{tag}][/]") + message_text) if tag is not None else message_text
|
|
||||||
|
|
||||||
if highlighter is not None:
|
if highlighter is not None:
|
||||||
# noinspection PyCallingNonCallable
|
# noinspection PyCallingNonCallable
|
||||||
message_text = highlighter(message_text)
|
message_text = highlighter(message_text)
|
||||||
|
|
||||||
if self.keywords is None:
|
if self.render_keywords is None:
|
||||||
self.keywords = self.KEYWORDS
|
self.render_keywords = self.KEYWORDS
|
||||||
|
|
||||||
if self.keywords:
|
if self.render_keywords:
|
||||||
message_text.highlight_words(self.keywords, "logging.keyword")
|
message_text.highlight_words(self.render_keywords, "logging.keyword")
|
||||||
|
|
||||||
return message_text
|
return message_text
|
||||||
|
|
||||||
@ -209,22 +219,23 @@ class Handler(DefaultRichHandler):
|
|||||||
exc_type, exc_value, exc_traceback = record.exc_info
|
exc_type, exc_value, exc_traceback = record.exc_info
|
||||||
if exc_type is None or exc_value is None:
|
if exc_type is None or exc_value is None:
|
||||||
raise ValueError(record)
|
raise ValueError(record)
|
||||||
_traceback = Traceback.from_exception(
|
try:
|
||||||
exc_type,
|
_traceback = Traceback.from_exception(
|
||||||
exc_value,
|
exc_type,
|
||||||
exc_traceback,
|
exc_value,
|
||||||
width=self.tracebacks_width,
|
exc_traceback,
|
||||||
extra_lines=self.tracebacks_extra_lines,
|
width=self.tracebacks_width,
|
||||||
word_wrap=self.tracebacks_word_wrap,
|
extra_lines=self.tracebacks_extra_lines,
|
||||||
show_locals=(getattr(record, "show_locals", None) or self.tracebacks_show_locals),
|
word_wrap=self.tracebacks_word_wrap,
|
||||||
locals_max_length=(getattr(record, "locals_max_length", None) or self.locals_max_length),
|
show_locals=(getattr(record, "show_locals", None) or self.tracebacks_show_locals),
|
||||||
locals_max_string=(getattr(record, "locals_max_string", None) or self.locals_max_string),
|
locals_max_length=(getattr(record, "locals_max_length", None) or self.locals_max_length),
|
||||||
locals_max_depth=(
|
locals_max_string=(getattr(record, "locals_max_string", None) or self.locals_max_string),
|
||||||
record.locals_max_depth if hasattr(record, "locals_max_depth") else self.locals_max_depth
|
locals_max_depth=getattr(record, "locals_max_depth", self.locals_max_depth),
|
||||||
),
|
suppress=self.tracebacks_suppress,
|
||||||
suppress=self.tracebacks_suppress,
|
max_frames=self.tracebacks_max_frames,
|
||||||
max_frames=self.tracebacks_max_frames,
|
)
|
||||||
)
|
except ImportError:
|
||||||
|
return
|
||||||
message = record.getMessage()
|
message = record.getMessage()
|
||||||
if self.formatter:
|
if self.formatter:
|
||||||
record.message = record.getMessage()
|
record.message = record.getMessage()
|
||||||
@ -235,10 +246,15 @@ class Handler(DefaultRichHandler):
|
|||||||
if message == str(exc_value):
|
if message == str(exc_value):
|
||||||
message = None
|
message = None
|
||||||
|
|
||||||
|
message_renderable = None
|
||||||
if message is not None:
|
if message is not None:
|
||||||
message_renderable = self.render_message(record, message)
|
try:
|
||||||
else:
|
if self.auto_load_json:
|
||||||
message_renderable = None
|
message_renderable = self.render_message(record, json.loads(message))
|
||||||
|
except JSONDecodeError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
message_renderable = message_renderable or self.render_message(record, message)
|
||||||
log_renderable = self.render(record=record, traceback=_traceback, message_renderable=message_renderable)
|
log_renderable = self.render(record=record, traceback=_traceback, message_renderable=message_renderable)
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
|
@ -6,7 +6,7 @@ import traceback as traceback_
|
|||||||
from multiprocessing import RLock as Lock
|
from multiprocessing import RLock as Lock
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import TYPE_CHECKING, Any, Callable, List, Mapping, Optional, Tuple, Type, Union
|
from typing import Any, Callable, List, Mapping, Optional, TYPE_CHECKING, Tuple, Type, Union
|
||||||
|
|
||||||
from typing_extensions import Self
|
from typing_extensions import Self
|
||||||
|
|
||||||
@ -14,9 +14,9 @@ from utils.log._handler import FileHandler, Handler
|
|||||||
from utils.typedefs import LogFilterType
|
from utils.typedefs import LogFilterType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from logging import LogRecord # pylint: disable=unused-import
|
from logging import LogRecord
|
||||||
|
|
||||||
from utils.log._config import LoggerConfig # pylint: disable=unused-import
|
from utils.log._config import LoggerConfig
|
||||||
|
|
||||||
__all__ = ("Logger", "LogFilter")
|
__all__ = ("Logger", "LogFilter")
|
||||||
|
|
||||||
@ -52,40 +52,25 @@ class Logger(logging.Logger): # skipcq: PY-A6006
|
|||||||
)
|
)
|
||||||
|
|
||||||
log_path = Path(self.config.project_root).joinpath(self.config.log_path)
|
log_path = Path(self.config.project_root).joinpath(self.config.log_path)
|
||||||
|
handler_config = {
|
||||||
|
"width": self.config.width,
|
||||||
|
"keywords": self.config.keywords,
|
||||||
|
"locals_max_length": self.config.traceback_locals_max_length,
|
||||||
|
"locals_max_string": self.config.traceback_locals_max_string,
|
||||||
|
"project_root": self.config.project_root,
|
||||||
|
"log_time_format": self.config.time_format,
|
||||||
|
}
|
||||||
handler, debug_handler, error_handler = (
|
handler, debug_handler, error_handler = (
|
||||||
# 控制台 log 配置
|
# 控制台 log 配置
|
||||||
Handler(
|
Handler(color_system=self.config.color_system, **handler_config),
|
||||||
width=self.config.width,
|
|
||||||
keywords=self.config.keywords,
|
|
||||||
locals_max_length=self.config.traceback_locals_max_length,
|
|
||||||
locals_max_string=self.config.traceback_locals_max_string,
|
|
||||||
locals_max_depth=self.config.traceback_locals_max_depth,
|
|
||||||
project_root=self.config.project_root,
|
|
||||||
log_time_format=self.config.time_format,
|
|
||||||
),
|
|
||||||
# debug.log 配置
|
# debug.log 配置
|
||||||
FileHandler(
|
FileHandler(level=10, path=log_path.joinpath("debug/debug.log"), locals_max_depth=1, **handler_config),
|
||||||
width=self.config.width,
|
|
||||||
keywords=self.config.keywords,
|
|
||||||
level=10,
|
|
||||||
path=log_path.joinpath("debug/debug.log"),
|
|
||||||
locals_max_depth=1,
|
|
||||||
locals_max_length=self.config.traceback_locals_max_length,
|
|
||||||
locals_max_string=self.config.traceback_locals_max_string,
|
|
||||||
project_root=self.config.project_root,
|
|
||||||
log_time_format=self.config.time_format,
|
|
||||||
),
|
|
||||||
# error.log 配置
|
# error.log 配置
|
||||||
FileHandler(
|
FileHandler(
|
||||||
width=self.config.width,
|
|
||||||
keywords=self.config.keywords,
|
|
||||||
level=40,
|
level=40,
|
||||||
path=log_path.joinpath("error/error.log"),
|
path=log_path.joinpath("error/error.log"),
|
||||||
locals_max_length=self.config.traceback_locals_max_length,
|
|
||||||
locals_max_string=self.config.traceback_locals_max_string,
|
|
||||||
locals_max_depth=self.config.traceback_locals_max_depth,
|
locals_max_depth=self.config.traceback_locals_max_depth,
|
||||||
project_root=self.config.project_root,
|
**handler_config,
|
||||||
log_time_format=self.config.time_format,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import traceback as traceback_
|
import traceback as traceback_
|
||||||
from types import ModuleType, TracebackType
|
from types import ModuleType, TracebackType
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union
|
from typing import Any, Dict, Iterable, List, Mapping, Optional, TYPE_CHECKING, Tuple, Type, Union
|
||||||
|
|
||||||
from rich import pretty
|
from rich import pretty
|
||||||
from rich.columns import Columns
|
from rich.columns import Columns
|
||||||
@ -12,13 +12,20 @@ from rich.pretty import Pretty
|
|||||||
from rich.syntax import PygmentsSyntaxTheme, Syntax
|
from rich.syntax import PygmentsSyntaxTheme, Syntax
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.text import Text, TextType
|
from rich.text import Text, TextType
|
||||||
from rich.traceback import Frame, PathHighlighter, Stack, Trace, LOCALS_MAX_LENGTH, LOCALS_MAX_STRING
|
from rich.traceback import (
|
||||||
from rich.traceback import Traceback as BaseTraceback
|
Frame,
|
||||||
|
LOCALS_MAX_LENGTH,
|
||||||
|
LOCALS_MAX_STRING,
|
||||||
|
PathHighlighter,
|
||||||
|
Stack,
|
||||||
|
Trace,
|
||||||
|
Traceback as BaseTraceback,
|
||||||
|
)
|
||||||
|
|
||||||
from utils.log._style import MonokaiProStyle
|
from utils.log._style import MonokaiProStyle
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from rich.console import ConsoleRenderable # pylint: disable=W0611
|
from rich.console import ConsoleRenderable
|
||||||
|
|
||||||
__all__ = ("render_scope", "Traceback")
|
__all__ = ("render_scope", "Traceback")
|
||||||
|
|
||||||
@ -96,20 +103,18 @@ class Traceback(BaseTraceback):
|
|||||||
exc_type: Type[BaseException],
|
exc_type: Type[BaseException],
|
||||||
exc_value: BaseException,
|
exc_value: BaseException,
|
||||||
traceback: Optional[TracebackType],
|
traceback: Optional[TracebackType],
|
||||||
*,
|
|
||||||
width: Optional[int] = 100,
|
width: Optional[int] = 100,
|
||||||
extra_lines: int = 3,
|
extra_lines: int = 3,
|
||||||
theme: Optional[str] = None,
|
theme: Optional[str] = None,
|
||||||
word_wrap: bool = False,
|
word_wrap: bool = False,
|
||||||
show_locals: bool = False,
|
show_locals: bool = False,
|
||||||
|
indent_guides: bool = True,
|
||||||
locals_max_length: int = LOCALS_MAX_LENGTH,
|
locals_max_length: int = LOCALS_MAX_LENGTH,
|
||||||
locals_max_string: int = LOCALS_MAX_STRING,
|
locals_max_string: int = LOCALS_MAX_STRING,
|
||||||
locals_max_depth: Optional[int] = None,
|
locals_max_depth: Optional[int] = None,
|
||||||
locals_hide_dunder: bool = True,
|
|
||||||
locals_hide_sunder: bool = False,
|
|
||||||
indent_guides: bool = True,
|
|
||||||
suppress: Iterable[Union[str, ModuleType]] = (),
|
suppress: Iterable[Union[str, ModuleType]] = (),
|
||||||
max_frames: int = 100,
|
max_frames: int = 100,
|
||||||
|
**kwargs,
|
||||||
) -> "Traceback":
|
) -> "Traceback":
|
||||||
rich_traceback = cls.extract(
|
rich_traceback = cls.extract(
|
||||||
exc_type=exc_type,
|
exc_type=exc_type,
|
||||||
@ -141,13 +146,11 @@ class Traceback(BaseTraceback):
|
|||||||
exc_type: Type[BaseException],
|
exc_type: Type[BaseException],
|
||||||
exc_value: BaseException,
|
exc_value: BaseException,
|
||||||
traceback: Optional[TracebackType],
|
traceback: Optional[TracebackType],
|
||||||
*,
|
|
||||||
show_locals: bool = False,
|
show_locals: bool = False,
|
||||||
locals_max_length: int = LOCALS_MAX_LENGTH,
|
locals_max_length: int = 10,
|
||||||
locals_max_string: int = LOCALS_MAX_STRING,
|
locals_max_string: int = 80,
|
||||||
locals_max_depth: Optional[int] = None,
|
locals_max_depth: Optional[int] = None,
|
||||||
locals_hide_dunder: bool = True,
|
**kwargs,
|
||||||
locals_hide_sunder: bool = False,
|
|
||||||
) -> Trace:
|
) -> Trace:
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
from rich import _IMPORT_CWD
|
from rich import _IMPORT_CWD
|
||||||
|
Loading…
Reference in New Issue
Block a user