logger-36 2024.28__py3-none-any.whl → 2024.30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- logger_36/catalog/config/console_rich.py +0 -1
- logger_36/catalog/handler/console.py +6 -9
- logger_36/catalog/handler/console_rich.py +16 -39
- logger_36/catalog/handler/file.py +6 -9
- logger_36/catalog/handler/generic.py +15 -18
- logger_36/catalog/logger/chronos.py +1 -2
- logger_36/catalog/logger/gpu.py +2 -4
- logger_36/catalog/logger/memory.py +6 -9
- logger_36/catalog/logger/system.py +0 -2
- logger_36/config/logger.py +2 -2
- logger_36/config/message.py +5 -6
- logger_36/constant/handler.py +2 -0
- logger_36/constant/logger.py +0 -4
- logger_36/constant/message.py +3 -1
- logger_36/constant/record.py +3 -4
- logger_36/content.py +1 -1
- logger_36/exception.py +8 -1
- logger_36/handler.py +8 -16
- logger_36/task/format/memory.py +2 -2
- logger_36/task/format/message.py +1 -25
- logger_36/task/format/rule.py +2 -2
- logger_36/task/measure/chronos.py +19 -9
- logger_36/task/measure/memory.py +1 -1
- logger_36/task/storage.py +1 -1
- logger_36/type/handler.py +34 -73
- logger_36/type/issue.py +2 -2
- logger_36/type/logger.py +104 -62
- logger_36/version.py +1 -1
- {logger_36-2024.28.dist-info → logger_36-2024.30.dist-info}/METADATA +1 -1
- logger_36-2024.30.dist-info/RECORD +52 -0
- {logger_36-2024.28.dist-info → logger_36-2024.30.dist-info}/WHEEL +1 -1
- logger_36-2024.28.dist-info/RECORD +0 -52
- {logger_36-2024.28.dist-info → logger_36-2024.30.dist-info}/top_level.txt +0 -0
logger_36/task/format/memory.py
CHANGED
@@ -5,7 +5,7 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
from logger_36.constant.memory import STORAGE_UNITS, storage_units_h
|
8
|
-
from logger_36.task.format.message import
|
8
|
+
from logger_36.task.format.message import MessageWithActualExpected
|
9
9
|
|
10
10
|
_KILO_UNIT = 1000.0
|
11
11
|
_MEGA_UNIT = _KILO_UNIT * 1000.0
|
@@ -41,7 +41,7 @@ def FormattedUsage(
|
|
41
41
|
value, unit = FormattedUsageWithAutoUnit(usage, decimals)
|
42
42
|
else:
|
43
43
|
raise ValueError(
|
44
|
-
|
44
|
+
MessageWithActualExpected(
|
45
45
|
"Invalid unit", actual=unit, expected=str(STORAGE_UNITS)[1:-1]
|
46
46
|
)
|
47
47
|
)
|
logger_36/task/format/message.py
CHANGED
@@ -7,35 +7,11 @@ SEE COPYRIGHT NOTICE BELOW
|
|
7
7
|
import difflib as diff
|
8
8
|
import typing as h
|
9
9
|
|
10
|
-
from logger_36.config.message import (
|
11
|
-
ELAPSED_TIME_FORMAT,
|
12
|
-
LEVEL_CLOSING,
|
13
|
-
LEVEL_OPENING,
|
14
|
-
MEMORY_FORMAT,
|
15
|
-
MESSAGE_MARKER,
|
16
|
-
)
|
17
10
|
from logger_36.constant.generic import NOT_PASSED
|
18
11
|
from logger_36.constant.message import expected_op_h
|
19
12
|
|
20
13
|
|
21
|
-
def
|
22
|
-
""""""
|
23
|
-
output = [
|
24
|
-
f"%(asctime)s"
|
25
|
-
f"{LEVEL_OPENING}%(level_first_letter)s{LEVEL_CLOSING}\t"
|
26
|
-
f"{MESSAGE_MARKER}%(message)s"
|
27
|
-
]
|
28
|
-
|
29
|
-
if with_where:
|
30
|
-
output.append("%(where)s")
|
31
|
-
output.append(ELAPSED_TIME_FORMAT)
|
32
|
-
if with_memory_usage:
|
33
|
-
output.append(MEMORY_FORMAT)
|
34
|
-
|
35
|
-
return "".join(output)
|
36
|
-
|
37
|
-
|
38
|
-
def FormattedMessage(
|
14
|
+
def MessageWithActualExpected(
|
39
15
|
message: str,
|
40
16
|
/,
|
41
17
|
*,
|
logger_36/task/format/rule.py
CHANGED
@@ -14,8 +14,8 @@ def RuleAsText(text: str | None, /) -> str:
|
|
14
14
|
|
15
15
|
|
16
16
|
try:
|
17
|
-
from rich.rule import Rule as rule_t
|
18
|
-
from rich.text import Text as text_t
|
17
|
+
from rich.rule import Rule as rule_t # noqa
|
18
|
+
from rich.text import Text as text_t # noqa
|
19
19
|
|
20
20
|
def Rule(text: str | None, color: str, /) -> rule_t | str:
|
21
21
|
""""""
|
@@ -5,25 +5,35 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import time
|
8
|
-
from datetime import datetime as
|
8
|
+
from datetime import datetime as date_time_t
|
9
9
|
|
10
10
|
# This module is imported early. Therefore, the current date and time should be close
|
11
11
|
# enough to the real start time of the main script.
|
12
|
-
_START_DATE_AND_TIME =
|
12
|
+
_START_DATE_AND_TIME = date_time_t.now()
|
13
13
|
|
14
14
|
|
15
15
|
def TimeStamp(*, precision: str = "microseconds") -> str:
|
16
16
|
""""""
|
17
|
-
return
|
17
|
+
return (
|
18
|
+
date_time_t.now()
|
19
|
+
.isoformat(timespec=precision)
|
20
|
+
.replace(".", "-")
|
21
|
+
.replace(":", "-")
|
22
|
+
)
|
18
23
|
|
19
24
|
|
20
|
-
def ElapsedTime(
|
25
|
+
def ElapsedTime(
|
26
|
+
*, should_return_now: bool = False
|
27
|
+
) -> str | tuple[str, date_time_t.date]:
|
21
28
|
""""""
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
now = date_time_t.now()
|
30
|
+
elapsed_seconds = (now - _START_DATE_AND_TIME).total_seconds()
|
31
|
+
output = time.strftime("%H:%M:%S", time.gmtime(elapsed_seconds))
|
32
|
+
while output.startswith("00:"):
|
33
|
+
output = output.split(sep=":", maxsplit=1)[-1]
|
34
|
+
|
35
|
+
if should_return_now:
|
36
|
+
return output, now
|
27
37
|
return output
|
28
38
|
|
29
39
|
|
logger_36/task/measure/memory.py
CHANGED
logger_36/task/storage.py
CHANGED
logger_36/type/handler.py
CHANGED
@@ -8,15 +8,17 @@ import dataclasses as d
|
|
8
8
|
import logging as lggg
|
9
9
|
import sys as sstm
|
10
10
|
import typing as h
|
11
|
-
from os import sep as FOLDER_SEPARATOR
|
12
|
-
from pathlib import Path as path_t
|
13
11
|
|
14
|
-
from logger_36.config.message import
|
12
|
+
from logger_36.config.message import (
|
13
|
+
LEVEL_CLOSING,
|
14
|
+
LEVEL_OPENING,
|
15
|
+
MESSAGE_MARKER,
|
16
|
+
WHERE_SEPARATOR,
|
17
|
+
)
|
15
18
|
from logger_36.constant.error import MEMORY_MEASURE_ERROR
|
16
19
|
from logger_36.constant.handler import HANDLER_CODES
|
17
20
|
from logger_36.constant.message import NEXT_LINE_PROLOGUE
|
18
|
-
from logger_36.
|
19
|
-
from logger_36.task.format.message import FormattedMessage, MessageFormat
|
21
|
+
from logger_36.task.format.message import MessageWithActualExpected
|
20
22
|
from logger_36.task.measure.chronos import TimeStamp
|
21
23
|
from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage
|
22
24
|
|
@@ -26,10 +28,9 @@ _MEMORY_MEASURE_ERROR = MEMORY_MEASURE_ERROR
|
|
26
28
|
@d.dataclass(slots=True, repr=False, eq=False)
|
27
29
|
class handler_extension_t:
|
28
30
|
name: str | None = None
|
29
|
-
|
30
|
-
show_memory_usage: bool = False
|
31
|
+
should_store_memory_usage: bool = False
|
31
32
|
message_width: int = -1
|
32
|
-
|
33
|
+
MessageFromRecord: h.Callable[..., str] = d.field(init=False)
|
33
34
|
|
34
35
|
handler: d.InitVar[lggg.Handler | None] = None
|
35
36
|
level: d.InitVar[int] = lggg.NOTSET
|
@@ -43,7 +44,7 @@ class handler_extension_t:
|
|
43
44
|
|
44
45
|
if self.name in HANDLER_CODES:
|
45
46
|
raise ValueError(
|
46
|
-
|
47
|
+
MessageWithActualExpected(
|
47
48
|
"Invalid handler name",
|
48
49
|
actual=self.name,
|
49
50
|
expected=f"a name not in {str(HANDLER_CODES)[1:-1]}",
|
@@ -53,8 +54,8 @@ class handler_extension_t:
|
|
53
54
|
if self.name is None:
|
54
55
|
self.name = TimeStamp()
|
55
56
|
|
56
|
-
if self.
|
57
|
-
self.
|
57
|
+
if self.should_store_memory_usage and not CanCheckMemoryUsage():
|
58
|
+
self.should_store_memory_usage = False
|
58
59
|
if _MEMORY_MEASURE_ERROR is not None:
|
59
60
|
print(_MEMORY_MEASURE_ERROR, file=sstm.stderr)
|
60
61
|
_MEMORY_MEASURE_ERROR = None
|
@@ -64,85 +65,45 @@ class handler_extension_t:
|
|
64
65
|
if 0 < self.message_width < 5:
|
65
66
|
self.message_width = 5
|
66
67
|
if formatter is None:
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
self.MessageFromRecord = self._MessageFromRecord
|
69
|
+
else:
|
70
|
+
handler.setFormatter(formatter)
|
71
|
+
self.MessageFromRecord = handler.formatter.format
|
71
72
|
|
72
|
-
def
|
73
|
+
def _MessageFromRecord(
|
73
74
|
self,
|
74
75
|
record: lggg.LogRecord,
|
75
76
|
/,
|
76
77
|
*,
|
77
78
|
PreProcessed: h.Callable[[str], str] | None = None,
|
78
|
-
|
79
|
-
) -> tuple[str, str | None]:
|
79
|
+
) -> str:
|
80
80
|
"""
|
81
81
|
See logger_36.catalog.handler.README.txt.
|
82
82
|
"""
|
83
|
-
record.level_first_letter = record.levelname[0]
|
84
|
-
|
85
83
|
message = record.msg
|
86
|
-
if not isinstance(message, str):
|
87
|
-
message = str(message)
|
88
|
-
original_message = message
|
89
84
|
|
90
85
|
if PreProcessed is not None:
|
91
86
|
message = PreProcessed(message)
|
92
|
-
if (
|
93
|
-
|
94
|
-
|
95
|
-
if has_newlines:
|
96
|
-
lines = message.splitlines()
|
97
|
-
if self.message_width > 0:
|
98
|
-
lines = _WrappedLines(lines, self.message_width)
|
99
|
-
else:
|
100
|
-
lines = _WrappedLines([message], self.message_width)
|
101
|
-
next_lines = NEXT_LINE_PROLOGUE.join(lines[1:])
|
102
|
-
next_lines = f"{NEXT_LINE_PROLOGUE}{next_lines}"
|
103
|
-
message = lines[0]
|
87
|
+
if (self.message_width <= 0) or (message.__len__() <= self.message_width):
|
88
|
+
if "\n" in message:
|
89
|
+
message = NEXT_LINE_PROLOGUE.join(message.splitlines())
|
104
90
|
else:
|
105
|
-
|
106
|
-
|
107
|
-
n_missing_s = self.message_width - message.__len__()
|
108
|
-
if n_missing_s > 3:
|
109
|
-
message += " " + (n_missing_s - 1) * "."
|
110
|
-
elif n_missing_s > 0:
|
111
|
-
message += n_missing_s * " "
|
112
|
-
|
113
|
-
record.msg = message
|
114
|
-
if self.show_where and not hasattr(record, SHOW_WHERE_ATTR):
|
115
|
-
hide_where = getattr(record, HIDE_WHERE_ATTR, False)
|
116
|
-
if hide_where:
|
117
|
-
record.where = ""
|
91
|
+
if "\n" in message:
|
92
|
+
lines = _WrappedLines(message.splitlines(), self.message_width)
|
118
93
|
else:
|
119
|
-
|
120
|
-
|
121
|
-
for path in sstm.path:
|
122
|
-
if module.is_relative_to(path):
|
123
|
-
module = module.relative_to(path)
|
124
|
-
path_was_found = True
|
125
|
-
break
|
126
|
-
if path_was_found:
|
127
|
-
module = str(module.parent / module.stem)
|
128
|
-
module = module.replace(FOLDER_SEPARATOR, ".")
|
129
|
-
else:
|
130
|
-
module = record.module
|
131
|
-
record.where = WHERE_FORMAT.format(
|
132
|
-
module=module, funcName=record.funcName, lineno=record.lineno
|
133
|
-
)
|
134
|
-
first_line = self.FormattedRecord(record).replace("\t", " ")
|
135
|
-
|
136
|
-
# Revert the record message to its original value for subsequent handlers.
|
137
|
-
record.msg = original_message
|
94
|
+
lines = _WrappedLines([message], self.message_width)
|
95
|
+
message = NEXT_LINE_PROLOGUE.join(lines)
|
138
96
|
|
139
|
-
if
|
140
|
-
|
141
|
-
return first_line, None
|
142
|
-
else:
|
143
|
-
return f"{first_line}{next_lines}", None
|
97
|
+
if (where := getattr(record, "where", None)) is None:
|
98
|
+
where = ""
|
144
99
|
else:
|
145
|
-
|
100
|
+
where = f"{NEXT_LINE_PROLOGUE}{WHERE_SEPARATOR} {where}"
|
101
|
+
|
102
|
+
return (
|
103
|
+
f"{record.when_or_elapsed}"
|
104
|
+
f"{LEVEL_OPENING}{record.level_first_letter}{LEVEL_CLOSING} "
|
105
|
+
f"{MESSAGE_MARKER} {message}{where}"
|
106
|
+
)
|
146
107
|
|
147
108
|
|
148
109
|
def _WrappedLines(lines: list[str], message_width: int, /) -> list[str]:
|
logger_36/type/issue.py
CHANGED
@@ -11,7 +11,7 @@ from logger_36.config.issue import ISSUE_BASE_CONTEXT
|
|
11
11
|
from logger_36.constant.generic import NOT_PASSED
|
12
12
|
from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR
|
13
13
|
from logger_36.constant.message import expected_op_h
|
14
|
-
from logger_36.task.format.message import
|
14
|
+
from logger_36.task.format.message import MessageWithActualExpected
|
15
15
|
|
16
16
|
issue_t = str
|
17
17
|
|
@@ -32,7 +32,7 @@ def NewIssue(
|
|
32
32
|
""""""
|
33
33
|
if context.__len__() == 0:
|
34
34
|
context = ISSUE_BASE_CONTEXT
|
35
|
-
message =
|
35
|
+
message = MessageWithActualExpected(
|
36
36
|
message,
|
37
37
|
actual=actual,
|
38
38
|
expected=expected,
|
logger_36/type/logger.py
CHANGED
@@ -10,35 +10,48 @@ import sys as sstm
|
|
10
10
|
import traceback as tcbk
|
11
11
|
import types as t
|
12
12
|
import typing as h
|
13
|
-
from datetime import
|
13
|
+
from datetime import date as date_t
|
14
|
+
from datetime import datetime as date_time_t
|
15
|
+
from os import sep as FOLDER_SEPARATOR
|
14
16
|
from pathlib import Path as path_t
|
15
17
|
from traceback import TracebackException as traceback_t
|
16
18
|
|
17
19
|
from logger_36.config.issue import ISSUE_CONTEXT_END, ISSUE_CONTEXT_SEPARATOR
|
18
|
-
from logger_36.config.message import
|
20
|
+
from logger_36.config.message import (
|
21
|
+
DATE_FORMAT,
|
22
|
+
ELAPSED_TIME_SEPARATOR,
|
23
|
+
LONG_ENOUGH,
|
24
|
+
TIME_FORMAT,
|
25
|
+
)
|
19
26
|
from logger_36.constant.generic import NOT_PASSED
|
27
|
+
from logger_36.constant.handler import ANONYMOUS
|
20
28
|
from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR, ORDER, order_h
|
21
29
|
from logger_36.constant.logger import (
|
22
|
-
HIDE_WHERE_KWARG,
|
23
30
|
LOGGER_NAME,
|
24
31
|
WARNING_LOGGER_NAME,
|
25
32
|
WARNING_TYPE_COMPILED_PATTERN,
|
26
33
|
logger_handle_h,
|
27
34
|
)
|
28
35
|
from logger_36.constant.memory import UNKNOWN_MEMORY_USAGE
|
29
|
-
from logger_36.constant.message import expected_op_h
|
30
|
-
from logger_36.constant.record import
|
31
|
-
|
32
|
-
|
36
|
+
from logger_36.constant.message import TIME_LENGTH_m_1, expected_op_h
|
37
|
+
from logger_36.constant.record import (
|
38
|
+
HIDE_WHERE_ATTR,
|
39
|
+
SHOW_W_RULE_ATTR,
|
40
|
+
STORE_MEMORY_ATTR,
|
33
41
|
)
|
34
|
-
from logger_36.task.format.message import
|
42
|
+
from logger_36.task.format.message import MessageWithActualExpected
|
35
43
|
from logger_36.task.measure.chronos import ElapsedTime
|
36
44
|
from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage
|
37
45
|
from logger_36.type.issue import NewIssue, issue_t
|
38
46
|
|
47
|
+
logger_base_t = lggg.Logger
|
48
|
+
|
49
|
+
_DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
|
50
|
+
_DATE_ORIGIN = _DATE_TIME_ORIGIN.date()
|
51
|
+
|
39
52
|
|
40
53
|
@d.dataclass(slots=True, repr=False, eq=False)
|
41
|
-
class logger_t(
|
54
|
+
class logger_t(logger_base_t):
|
42
55
|
name_: d.InitVar[str] = LOGGER_NAME
|
43
56
|
level_: d.InitVar[int] = lggg.NOTSET
|
44
57
|
activate_wrn_interceptions: d.InitVar[bool] = True
|
@@ -50,8 +63,9 @@ class logger_t(lggg.Logger):
|
|
50
63
|
|
51
64
|
on_hold: list[lggg.LogRecord] = d.field(init=False, default_factory=list)
|
52
65
|
events: dict[int, int] = d.field(init=False, default_factory=dict)
|
53
|
-
|
54
|
-
|
66
|
+
last_message_now: date_time_t = d.field(init=False, default=_DATE_TIME_ORIGIN)
|
67
|
+
last_message_date: date_t = d.field(init=False, default=_DATE_ORIGIN)
|
68
|
+
any_handler_stores_memory: bool = d.field(init=False, default=False)
|
55
69
|
memory_usages: list[tuple[str, int]] = d.field(init=False, default_factory=list)
|
56
70
|
context_levels: list[str] = d.field(init=False, default_factory=list)
|
57
71
|
staged_issues: list[issue_t] = d.field(init=False, default_factory=list)
|
@@ -64,9 +78,9 @@ class logger_t(lggg.Logger):
|
|
64
78
|
self, name_: str, level_: int, activate_wrn_interceptions: bool
|
65
79
|
) -> None:
|
66
80
|
""""""
|
67
|
-
|
81
|
+
logger_base_t.__init__(self, name_)
|
68
82
|
self.setLevel(level_)
|
69
|
-
self.propagate = False # Part of
|
83
|
+
self.propagate = False # Part of logger_base_t.
|
70
84
|
|
71
85
|
for level in lggg.getLevelNamesMapping().values():
|
72
86
|
self.events[level] = 0
|
@@ -92,7 +106,7 @@ class logger_t(lggg.Logger):
|
|
92
106
|
logger.handle = t.MethodType(_HandleForWarnings(self), logger)
|
93
107
|
|
94
108
|
lggg.captureWarnings(True)
|
95
|
-
self.info("Warning Interception: ON"
|
109
|
+
self.info("Warning Interception: ON")
|
96
110
|
|
97
111
|
def _DeactivateWarningInterceptions(self) -> None:
|
98
112
|
""""""
|
@@ -102,7 +116,7 @@ class logger_t(lggg.Logger):
|
|
102
116
|
self.intercepted_wrn_handle = None
|
103
117
|
|
104
118
|
lggg.captureWarnings(False)
|
105
|
-
self.info("Warning Interception: OFF"
|
119
|
+
self.info("Warning Interception: OFF")
|
106
120
|
|
107
121
|
def ToggleWarningInterceptions(self, state: bool, /) -> None:
|
108
122
|
""""""
|
@@ -130,16 +144,13 @@ class logger_t(lggg.Logger):
|
|
130
144
|
intercepted = sorted(self.intercepted_log_handles.keys())
|
131
145
|
if intercepted.__len__() > 0:
|
132
146
|
as_str = ", ".join(intercepted)
|
133
|
-
self.info(
|
134
|
-
f"Now Intercepting LOGs from: {as_str}",
|
135
|
-
**HIDE_WHERE_KWARG,
|
136
|
-
)
|
147
|
+
self.info(f"Now Intercepting LOGs from: {as_str}")
|
137
148
|
elif self.intercepted_log_handles.__len__() > 0:
|
138
149
|
for name, handle in self.intercepted_log_handles.items():
|
139
150
|
logger = lggg.getLogger(name)
|
140
151
|
logger.handle = handle
|
141
152
|
self.intercepted_log_handles.clear()
|
142
|
-
self.info("Log Interception: OFF"
|
153
|
+
self.info("Log Interception: OFF")
|
143
154
|
|
144
155
|
@property
|
145
156
|
def max_memory_usage(self) -> int:
|
@@ -162,69 +173,94 @@ class logger_t(lggg.Logger):
|
|
162
173
|
def AddHandler(self, handler: lggg.Handler, should_hold_messages: bool, /) -> None:
|
163
174
|
""""""
|
164
175
|
self.should_hold_messages = should_hold_messages
|
165
|
-
|
176
|
+
logger_base_t.addHandler(self, handler)
|
166
177
|
|
167
178
|
extension = getattr(handler, "extension", None)
|
168
179
|
if extension is None:
|
169
|
-
|
180
|
+
name = handler.name
|
181
|
+
if (name is None) or (name.__len__() == 0):
|
182
|
+
name = ANONYMOUS
|
170
183
|
else:
|
171
|
-
|
172
|
-
|
173
|
-
|
184
|
+
name = getattr(extension, "name", ANONYMOUS)
|
185
|
+
if getattr(extension, STORE_MEMORY_ATTR, False):
|
186
|
+
self.any_handler_stores_memory = True
|
187
|
+
|
188
|
+
path = getattr(handler, "baseFilename", "")
|
189
|
+
if isinstance(path, path_t) or (path.__len__() > 0):
|
190
|
+
path = f"\nPath: {path}"
|
174
191
|
|
175
|
-
extension = getattr(handler, "extension", handler.name)
|
176
|
-
if isinstance(extension, str):
|
177
|
-
name = extension
|
178
|
-
else:
|
179
|
-
name = getattr(extension, "name", "Anonymous")
|
180
192
|
self.info(
|
181
|
-
f'New handler "{name}"
|
182
|
-
f"level {lggg.getLevelName(handler.level)}",
|
183
|
-
**HIDE_WHERE_KWARG,
|
193
|
+
f'New handler "{name}" of type "{type(handler).__name__}" and '
|
194
|
+
f"level {handler.level}={lggg.getLevelName(handler.level)}{path}",
|
184
195
|
)
|
185
196
|
|
186
197
|
def handle(self, record: lggg.LogRecord, /) -> None:
|
187
198
|
""""""
|
188
|
-
|
189
|
-
for hold in self.on_hold:
|
190
|
-
lggg.Logger.handle(self, hold)
|
191
|
-
self.on_hold.clear()
|
192
|
-
|
193
|
-
record.elapsed_time = ElapsedTime()
|
194
|
-
|
195
|
-
if self.any_handler_shows_memory or not self.hasHandlers():
|
196
|
-
# Memory usage is also added if there are no handlers yet, just in case.
|
197
|
-
usage = CurrentMemoryUsage()
|
198
|
-
self.memory_usages.append(
|
199
|
-
(f"{record.module}.{record.funcName}.{record.lineno}", usage)
|
200
|
-
)
|
199
|
+
elapsed_time, now = ElapsedTime(should_return_now=True)
|
201
200
|
|
202
|
-
|
203
|
-
|
201
|
+
if (self.on_hold.__len__() > 0) and not self.should_hold_messages:
|
202
|
+
for held in self.on_hold:
|
203
|
+
logger_base_t.handle(self, held)
|
204
|
+
self.on_hold.clear()
|
204
205
|
|
205
|
-
date
|
206
|
-
if date != self.last_message_date:
|
206
|
+
if (date := now.date()) != self.last_message_date:
|
207
207
|
self.last_message_date = date
|
208
208
|
# levelno: Added for management by logging.Logger.handle.
|
209
209
|
date_record = lggg.makeLogRecord(
|
210
210
|
{
|
211
211
|
"name": self.name,
|
212
212
|
"levelno": lggg.INFO,
|
213
|
-
"msg": f"DATE: {date}",
|
213
|
+
"msg": f"DATE: {date.strftime(DATE_FORMAT)}",
|
214
214
|
SHOW_W_RULE_ATTR: True,
|
215
215
|
}
|
216
216
|
)
|
217
217
|
if self.should_hold_messages:
|
218
218
|
self.on_hold.append(date_record)
|
219
219
|
else:
|
220
|
-
|
220
|
+
logger_base_t.handle(self, date_record)
|
221
|
+
|
222
|
+
# When.
|
223
|
+
if now - self.last_message_now > LONG_ENOUGH:
|
224
|
+
record.when_or_elapsed = now.strftime(TIME_FORMAT)
|
225
|
+
else:
|
226
|
+
record.when_or_elapsed = (
|
227
|
+
f"{ELAPSED_TIME_SEPARATOR}{elapsed_time:.<{TIME_LENGTH_m_1}}"
|
228
|
+
)
|
229
|
+
self.last_message_now = now
|
230
|
+
|
231
|
+
# Where.
|
232
|
+
# Memory usage is also stored if there are no handlers yet, just in case.
|
233
|
+
should_store_where = self.any_handler_stores_memory or not self.hasHandlers()
|
234
|
+
should_show_where = (record.levelno != lggg.INFO) and not hasattr(
|
235
|
+
record, HIDE_WHERE_ATTR
|
236
|
+
)
|
237
|
+
if should_store_where or should_show_where:
|
238
|
+
module = path_t(record.pathname)
|
239
|
+
for path in sstm.path:
|
240
|
+
if module.is_relative_to(path):
|
241
|
+
module = module.relative_to(path).with_suffix("")
|
242
|
+
module = str(module).replace(FOLDER_SEPARATOR, ".")
|
243
|
+
break
|
244
|
+
else:
|
245
|
+
module = record.module
|
246
|
+
where = f"{module}:{record.funcName}:{record.lineno}"
|
247
|
+
if should_show_where:
|
248
|
+
record.where = where
|
249
|
+
else:
|
250
|
+
where = None
|
251
|
+
|
252
|
+
# How.
|
253
|
+
record.level_first_letter = record.levelname[0]
|
254
|
+
|
255
|
+
# What.
|
256
|
+
if not isinstance(record.msg, str):
|
257
|
+
record.msg = str(record.msg)
|
221
258
|
|
222
259
|
if self.should_hold_messages:
|
223
260
|
self.on_hold.append(record)
|
224
261
|
else:
|
225
|
-
|
262
|
+
logger_base_t.handle(self, record)
|
226
263
|
|
227
|
-
self.events[record.levelno] += 1
|
228
264
|
if (self.exit_on_critical and (record.levelno is lggg.CRITICAL)) or (
|
229
265
|
self.exit_on_error and (record.levelno is lggg.ERROR)
|
230
266
|
):
|
@@ -232,6 +268,11 @@ class logger_t(lggg.Logger):
|
|
232
268
|
# __post_init__ set self.exit_on_critical if self.exit_on_error.
|
233
269
|
sstm.exit(1)
|
234
270
|
|
271
|
+
self.events[record.levelno] += 1
|
272
|
+
|
273
|
+
if should_store_where:
|
274
|
+
self.memory_usages.append((where, CurrentMemoryUsage()))
|
275
|
+
|
235
276
|
def Log(
|
236
277
|
self,
|
237
278
|
message: str,
|
@@ -247,7 +288,7 @@ class logger_t(lggg.Logger):
|
|
247
288
|
""""""
|
248
289
|
if isinstance(level, str):
|
249
290
|
level = lggg.getLevelNamesMapping()[level.upper()]
|
250
|
-
message =
|
291
|
+
message = MessageWithActualExpected(
|
251
292
|
message,
|
252
293
|
actual=actual,
|
253
294
|
expected=expected,
|
@@ -357,7 +398,7 @@ class logger_t(lggg.Logger):
|
|
357
398
|
|
358
399
|
if order not in ORDER:
|
359
400
|
raise ValueError(
|
360
|
-
|
401
|
+
MessageWithActualExpected(
|
361
402
|
"Invalid commit order",
|
362
403
|
actual=order,
|
363
404
|
expected=f"One of {str(ORDER)[1:-1]}",
|
@@ -379,17 +420,18 @@ class logger_t(lggg.Logger):
|
|
379
420
|
formatted = "\n".join(lines)
|
380
421
|
"""
|
381
422
|
|
423
|
+
hide_where = {HIDE_WHERE_ATTR: None}
|
382
424
|
if unified:
|
383
425
|
level, _ = issues[0].split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
|
384
426
|
wo_level = []
|
385
427
|
for issue in issues:
|
386
428
|
_, issue = issue.split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
|
387
429
|
wo_level.append(issue)
|
388
|
-
self.log(int(level), "\n".join(wo_level), stacklevel=2)
|
430
|
+
self.log(int(level), "\n".join(wo_level), stacklevel=2, extra=hide_where)
|
389
431
|
else:
|
390
432
|
for issue in issues:
|
391
433
|
level, issue = issue.split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
|
392
|
-
self.log(int(level), issue, stacklevel=2)
|
434
|
+
self.log(int(level), issue, stacklevel=2, extra=hide_where)
|
393
435
|
self.staged_issues.clear()
|
394
436
|
|
395
437
|
def __enter__(self) -> None:
|
@@ -408,10 +450,10 @@ class logger_t(lggg.Logger):
|
|
408
450
|
return False
|
409
451
|
|
410
452
|
|
411
|
-
def _HandleForWarnings(interceptor:
|
453
|
+
def _HandleForWarnings(interceptor: logger_base_t, /) -> logger_handle_h:
|
412
454
|
""""""
|
413
455
|
|
414
|
-
def handle_p(_:
|
456
|
+
def handle_p(_: logger_base_t, record: lggg.LogRecord, /) -> None:
|
415
457
|
pieces = WARNING_TYPE_COMPILED_PATTERN.match(record.msg)
|
416
458
|
if pieces is None:
|
417
459
|
# The warning message does not follow the default format.
|
@@ -437,11 +479,11 @@ def _HandleForWarnings(interceptor: lggg.Logger, /) -> logger_handle_h:
|
|
437
479
|
|
438
480
|
|
439
481
|
def _HandleForInterceptions(
|
440
|
-
intercepted:
|
482
|
+
intercepted: logger_base_t, interceptor: logger_base_t, /
|
441
483
|
) -> logger_handle_h:
|
442
484
|
""""""
|
443
485
|
|
444
|
-
def handle_p(_:
|
486
|
+
def handle_p(_: logger_base_t, record: lggg.LogRecord, /) -> None:
|
445
487
|
duplicate = lggg.makeLogRecord(record.__dict__)
|
446
488
|
duplicate.msg = f"{record.msg} :{intercepted.name}:"
|
447
489
|
interceptor.handle(duplicate)
|
logger_36/version.py
CHANGED