]> jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/pip/_vendor/rich/logging.py
init: venv aand flask
[dlqueue.git] / venv / lib / python3.11 / site-packages / pip / _vendor / rich / logging.py
1 import logging
2 from datetime import datetime
3 from logging import Handler, LogRecord
4 from pathlib import Path
5 from types import ModuleType
6 from typing import ClassVar, Iterable, List, Optional, Type, Union
7
8 from pip._vendor.rich._null_file import NullFile
9
10 from . import get_console
11 from ._log_render import FormatTimeCallable, LogRender
12 from .console import Console, ConsoleRenderable
13 from .highlighter import Highlighter, ReprHighlighter
14 from .text import Text
15 from .traceback import Traceback
16
17
18 class RichHandler(Handler):
19 """A logging handler that renders output with Rich. The time / level / message and file are displayed in columns.
20 The level is color coded, and the message is syntax highlighted.
21
22 Note:
23 Be careful when enabling console markup in log messages if you have configured logging for libraries not
24 under your control. If a dependency writes messages containing square brackets, it may not produce the intended output.
25
26 Args:
27 level (Union[int, str], optional): Log level. Defaults to logging.NOTSET.
28 console (:class:`~rich.console.Console`, optional): Optional console instance to write logs.
29 Default will use a global console instance writing to stdout.
30 show_time (bool, optional): Show a column for the time. Defaults to True.
31 omit_repeated_times (bool, optional): Omit repetition of the same time. Defaults to True.
32 show_level (bool, optional): Show a column for the level. Defaults to True.
33 show_path (bool, optional): Show the path to the original log call. Defaults to True.
34 enable_link_path (bool, optional): Enable terminal link of path column to file. Defaults to True.
35 highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None.
36 markup (bool, optional): Enable console markup in log messages. Defaults to False.
37 rich_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False.
38 tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks, or None for full width. Defaults to None.
39 tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks, or None for full width. Defaults to None.
40 tracebacks_theme (str, optional): Override pygments theme used in traceback.
41 tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to True.
42 tracebacks_show_locals (bool, optional): Enable display of locals in tracebacks. Defaults to False.
43 tracebacks_suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
44 locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
45 Defaults to 10.
46 locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
47 log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%x %X] ".
48 keywords (List[str], optional): List of words to highlight instead of ``RichHandler.KEYWORDS``.
49 """
50
51 KEYWORDS: ClassVar[Optional[List[str]]] = [
52 "GET",
53 "POST",
54 "HEAD",
55 "PUT",
56 "DELETE",
57 "OPTIONS",
58 "TRACE",
59 "PATCH",
60 ]
61 HIGHLIGHTER_CLASS: ClassVar[Type[Highlighter]] = ReprHighlighter
62
63 def __init__(
64 self,
65 level: Union[int, str] = logging.NOTSET,
66 console: Optional[Console] = None,
67 *,
68 show_time: bool = True,
69 omit_repeated_times: bool = True,
70 show_level: bool = True,
71 show_path: bool = True,
72 enable_link_path: bool = True,
73 highlighter: Optional[Highlighter] = None,
74 markup: bool = False,
75 rich_tracebacks: bool = False,
76 tracebacks_width: Optional[int] = None,
77 tracebacks_extra_lines: int = 3,
78 tracebacks_theme: Optional[str] = None,
79 tracebacks_word_wrap: bool = True,
80 tracebacks_show_locals: bool = False,
81 tracebacks_suppress: Iterable[Union[str, ModuleType]] = (),
82 locals_max_length: int = 10,
83 locals_max_string: int = 80,
84 log_time_format: Union[str, FormatTimeCallable] = "[%x %X]",
85 keywords: Optional[List[str]] = None,
86 ) -> None:
87 super().__init__(level=level)
88 self.console = console or get_console()
89 self.highlighter = highlighter or self.HIGHLIGHTER_CLASS()
90 self._log_render = LogRender(
91 show_time=show_time,
92 show_level=show_level,
93 show_path=show_path,
94 time_format=log_time_format,
95 omit_repeated_times=omit_repeated_times,
96 level_width=None,
97 )
98 self.enable_link_path = enable_link_path
99 self.markup = markup
100 self.rich_tracebacks = rich_tracebacks
101 self.tracebacks_width = tracebacks_width
102 self.tracebacks_extra_lines = tracebacks_extra_lines
103 self.tracebacks_theme = tracebacks_theme
104 self.tracebacks_word_wrap = tracebacks_word_wrap
105 self.tracebacks_show_locals = tracebacks_show_locals
106 self.tracebacks_suppress = tracebacks_suppress
107 self.locals_max_length = locals_max_length
108 self.locals_max_string = locals_max_string
109 self.keywords = keywords
110
111 def get_level_text(self, record: LogRecord) -> Text:
112 """Get the level name from the record.
113
114 Args:
115 record (LogRecord): LogRecord instance.
116
117 Returns:
118 Text: A tuple of the style and level name.
119 """
120 level_name = record.levelname
121 level_text = Text.styled(
122 level_name.ljust(8), f"logging.level.{level_name.lower()}"
123 )
124 return level_text
125
126 def emit(self, record: LogRecord) -> None:
127 """Invoked by logging."""
128 message = self.format(record)
129 traceback = None
130 if (
131 self.rich_tracebacks
132 and record.exc_info
133 and record.exc_info != (None, None, None)
134 ):
135 exc_type, exc_value, exc_traceback = record.exc_info
136 assert exc_type is not None
137 assert exc_value is not None
138 traceback = Traceback.from_exception(
139 exc_type,
140 exc_value,
141 exc_traceback,
142 width=self.tracebacks_width,
143 extra_lines=self.tracebacks_extra_lines,
144 theme=self.tracebacks_theme,
145 word_wrap=self.tracebacks_word_wrap,
146 show_locals=self.tracebacks_show_locals,
147 locals_max_length=self.locals_max_length,
148 locals_max_string=self.locals_max_string,
149 suppress=self.tracebacks_suppress,
150 )
151 message = record.getMessage()
152 if self.formatter:
153 record.message = record.getMessage()
154 formatter = self.formatter
155 if hasattr(formatter, "usesTime") and formatter.usesTime():
156 record.asctime = formatter.formatTime(record, formatter.datefmt)
157 message = formatter.formatMessage(record)
158
159 message_renderable = self.render_message(record, message)
160 log_renderable = self.render(
161 record=record, traceback=traceback, message_renderable=message_renderable
162 )
163 if isinstance(self.console.file, NullFile):
164 # Handles pythonw, where stdout/stderr are null, and we return NullFile
165 # instance from Console.file. In this case, we still want to make a log record
166 # even though we won't be writing anything to a file.
167 self.handleError(record)
168 else:
169 try:
170 self.console.print(log_renderable)
171 except Exception:
172 self.handleError(record)
173
174 def render_message(self, record: LogRecord, message: str) -> "ConsoleRenderable":
175 """Render message text in to Text.
176
177 Args:
178 record (LogRecord): logging Record.
179 message (str): String containing log message.
180
181 Returns:
182 ConsoleRenderable: Renderable to display log message.
183 """
184 use_markup = getattr(record, "markup", self.markup)
185 message_text = Text.from_markup(message) if use_markup else Text(message)
186
187 highlighter = getattr(record, "highlighter", self.highlighter)
188 if highlighter:
189 message_text = highlighter(message_text)
190
191 if self.keywords is None:
192 self.keywords = self.KEYWORDS
193
194 if self.keywords:
195 message_text.highlight_words(self.keywords, "logging.keyword")
196
197 return message_text
198
199 def render(
200 self,
201 *,
202 record: LogRecord,
203 traceback: Optional[Traceback],
204 message_renderable: "ConsoleRenderable",
205 ) -> "ConsoleRenderable":
206 """Render log for display.
207
208 Args:
209 record (LogRecord): logging Record.
210 traceback (Optional[Traceback]): Traceback instance or None for no Traceback.
211 message_renderable (ConsoleRenderable): Renderable (typically Text) containing log message contents.
212
213 Returns:
214 ConsoleRenderable: Renderable to display log.
215 """
216 path = Path(record.pathname).name
217 level = self.get_level_text(record)
218 time_format = None if self.formatter is None else self.formatter.datefmt
219 log_time = datetime.fromtimestamp(record.created)
220
221 log_renderable = self._log_render(
222 self.console,
223 [message_renderable] if not traceback else [message_renderable, traceback],
224 log_time=log_time,
225 time_format=time_format,
226 level=level,
227 path=path,
228 line_no=record.lineno,
229 link_path=record.pathname if self.enable_link_path else None,
230 )
231 return log_renderable
232
233
234 if __name__ == "__main__": # pragma: no cover
235 from time import sleep
236
237 FORMAT = "%(message)s"
238 # FORMAT = "%(asctime)-15s - %(levelname)s - %(message)s"
239 logging.basicConfig(
240 level="NOTSET",
241 format=FORMAT,
242 datefmt="[%X]",
243 handlers=[RichHandler(rich_tracebacks=True, tracebacks_show_locals=True)],
244 )
245 log = logging.getLogger("rich")
246
247 log.info("Server starting...")
248 log.info("Listening on http://127.0.0.1:8080")
249 sleep(1)
250
251 log.info("GET /index.html 200 1298")
252 log.info("GET /imgs/backgrounds/back1.jpg 200 54386")
253 log.info("GET /css/styles.css 200 54386")
254 log.warning("GET /favicon.ico 404 242")
255 sleep(1)
256
257 log.debug(
258 "JSONRPC request\n--> %r\n<-- %r",
259 {
260 "version": "1.1",
261 "method": "confirmFruitPurchase",
262 "params": [["apple", "orange", "mangoes", "pomelo"], 1.123],
263 "id": "194521489",
264 },
265 {"version": "1.1", "result": True, "error": None, "id": "194521489"},
266 )
267 log.debug(
268 "Loading configuration file /adasd/asdasd/qeqwe/qwrqwrqwr/sdgsdgsdg/werwerwer/dfgerert/ertertert/ertetert/werwerwer"
269 )
270 log.error("Unable to find 'pomelo' in database!")
271 log.info("POST /jsonrpc/ 200 65532")
272 log.info("POST /admin/ 401 42234")
273 log.warning("password was rejected for admin site.")
274
275 def divide() -> None:
276 number = 1
277 divisor = 0
278 foos = ["foo"] * 100
279 log.debug("in divide")
280 try:
281 number / divisor
282 except:
283 log.exception("An error of some kind occurred!")
284
285 divide()
286 sleep(1)
287 log.critical("Out of memory!")
288 log.info("Server exited with code=-1")
289 log.info("[bold]EXITING...[/bold]", extra=dict(markup=True))