-
-
Notifications
You must be signed in to change notification settings - Fork 102
/
loggers.py
143 lines (108 loc) · 4.08 KB
/
loggers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""Logging functions."""
import logging
from contextlib import suppress
from pathlib import Path
from typing import Any, Callable, MutableMapping, Optional, Sequence, Tuple
from jinja2.runtime import Context
from mkdocs.utils import warning_filter
try:
from jinja2 import pass_context
except ImportError: # TODO: remove once Jinja2 < 3.1 is dropped
from jinja2 import contextfunction as pass_context # type: ignore # noqa: WPS440
try:
import mkdocstrings_handlers
except ImportError:
TEMPLATES_DIRS: Sequence[Path] = ()
else:
TEMPLATES_DIRS = tuple(mkdocstrings_handlers.__path__) # noqa: WPS609
class LoggerAdapter(logging.LoggerAdapter):
"""A logger adapter to prefix messages."""
def __init__(self, prefix: str, logger: logging.Logger):
"""Initialize the object.
Arguments:
prefix: The string to insert in front of every message.
logger: The logger instance.
"""
super().__init__(logger, {})
self.prefix = prefix
def process(self, msg: str, kwargs: MutableMapping[str, Any]) -> Tuple[str, Any]:
"""Process the message.
Arguments:
msg: The message:
kwargs: Remaining arguments.
Returns:
The processed message.
"""
return f"{self.prefix}: {msg}", kwargs
class TemplateLogger:
"""A wrapper class to allow logging in templates.
Attributes:
debug: Function to log a DEBUG message.
info: Function to log an INFO message.
warning: Function to log a WARNING message.
error: Function to log an ERROR message.
critical: Function to log a CRITICAL message.
"""
def __init__(self, logger: LoggerAdapter):
"""Initialize the object.
Arguments:
logger: A logger adapter.
"""
self.debug = get_template_logger_function(logger.debug)
self.info = get_template_logger_function(logger.info)
self.warning = get_template_logger_function(logger.warning)
self.error = get_template_logger_function(logger.error)
self.critical = get_template_logger_function(logger.critical)
def get_template_logger_function(logger_func: Callable) -> Callable:
"""Create a wrapper function that automatically receives the Jinja template context.
Arguments:
logger_func: The logger function to use within the wrapper.
Returns:
A function.
"""
@pass_context
def wrapper(context: Context, msg: Optional[str] = None) -> str:
"""Log a message.
Arguments:
context: The template context, automatically provided by Jinja.
msg: The message to log.
Returns:
An empty string.
"""
template_path = get_template_path(context)
logger_func(f"{template_path}: {msg or 'Rendering'}")
return ""
return wrapper
def get_template_path(context: Context) -> str:
"""Return the path to the template currently using the given context.
Arguments:
context: The template context.
Returns:
The relative path to the template.
"""
context_name: str = str(context.name)
filename = context.environment.get_template(context_name).filename
if filename:
for template_dir in TEMPLATES_DIRS:
with suppress(ValueError):
return str(Path(filename).relative_to(template_dir))
with suppress(ValueError):
return str(Path(filename).relative_to(Path.cwd()))
return filename
return context_name
def get_logger(name: str) -> LoggerAdapter:
"""Return a pre-configured logger.
Arguments:
name: The name to use with `logging.getLogger`.
Returns:
A logger configured to work well in MkDocs.
"""
logger = logging.getLogger(f"mkdocs.plugins.{name}")
logger.addFilter(warning_filter)
return LoggerAdapter(name.split(".", 1)[0], logger)
def get_template_logger() -> TemplateLogger:
"""Return a logger usable in templates.
Returns:
A template logger.
"""
return TemplateLogger(get_logger("mkdocstrings.templates"))