logger-36 2025.22__py3-none-any.whl → 2025.24__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/api/memory.py +0 -9
- logger_36/api/storage.py +0 -1
- logger_36/api/time.py +0 -1
- logger_36/catalog/handler/console.py +1 -1
- logger_36/catalog/handler/console_rich.py +1 -1
- logger_36/catalog/handler/generic.py +1 -1
- logger_36/{extension/html_.py → catalog/handler/memory.py} +53 -45
- logger_36/catalog/logger/system.py +6 -5
- logger_36/{api/system.py → config/rule.py} +2 -1
- logger_36/{api/gpu.py → constant/date_time.py} +8 -1
- logger_36/constant/path.py +8 -7
- logger_36/constant/record.py +0 -1
- logger_36/constant/rule.py +2 -2
- logger_36/{task → extension}/inspection.py +15 -29
- logger_36/extension/record.py +66 -0
- logger_36/task/measure/chronos.py +2 -4
- logger_36/task/storage.py +61 -20
- logger_36/type/handler.py +6 -10
- logger_36/type/logger.py +82 -182
- logger_36/version.py +1 -1
- {logger_36-2025.22.dist-info → logger_36-2025.24.dist-info}/METADATA +1 -1
- {logger_36-2025.22.dist-info → logger_36-2025.24.dist-info}/RECORD +26 -25
- /logger_36/api/{type.py → logger.py} +0 -0
- /logger_36/api/{content.py → message.py} +0 -0
- {logger_36-2025.22.dist-info → logger_36-2025.24.dist-info}/WHEEL +0 -0
- {logger_36-2025.22.dist-info → logger_36-2025.24.dist-info}/top_level.txt +0 -0
logger_36/api/memory.py
CHANGED
@@ -4,15 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
from logger_36.catalog.logger.memory import ( # noqa
|
8
|
-
LogMaximumMemoryUsage,
|
9
|
-
LogMemoryUsages,
|
10
|
-
)
|
11
|
-
from logger_36.task.format.memory import FormattedUsage as FormattedMemoryUsage # noqa
|
12
|
-
from logger_36.task.format.memory import ( # noqa
|
13
|
-
FormattedUsageWithAutoUnit as FormattedMemoryUsageWithAutoUnit,
|
14
|
-
)
|
15
|
-
from logger_36.task.format.memory import UsageBar as MemoryUsageBar # noqa
|
16
7
|
from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage # noqa
|
17
8
|
from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage # noqa
|
18
9
|
|
logger_36/api/storage.py
CHANGED
logger_36/api/time.py
CHANGED
@@ -26,7 +26,7 @@ from logger_36.catalog.config.console_rich import (
|
|
26
26
|
)
|
27
27
|
from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS, WHERE_SEPARATOR
|
28
28
|
from logger_36.constant.message import CONTEXT_LENGTH
|
29
|
-
from logger_36.type.handler import
|
29
|
+
from logger_36.type.handler import non_file_handler_t as base_t
|
30
30
|
|
31
31
|
_COMMON_TRACEBACK_ARGUMENTS = ("theme", "width")
|
32
32
|
_EXCLUSIVE_TRACEBACK_ARGUMENTS = (
|
@@ -4,60 +4,68 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
import
|
8
|
-
import
|
9
|
-
|
7
|
+
import json
|
8
|
+
import logging as l
|
9
|
+
import typing as h
|
10
10
|
|
11
|
-
|
11
|
+
from logger_36.type.handler import non_file_handler_t as base_t
|
12
12
|
|
13
|
+
formats_h = h.Literal["dict", "json", "message", "raw"]
|
13
14
|
|
14
|
-
@d.dataclass(slots=True, repr=False, eq=False)
|
15
|
-
class html_content_t(base_t):
|
16
|
-
source: str = ""
|
17
|
-
inside_body: bool = d.field(init=False, default=False)
|
18
|
-
body_position_start: tuple[int, int] = d.field(init=False, default=(-1, -1))
|
19
|
-
body_position_end: tuple[int, int] = d.field(init=False, default=(-1, -1))
|
20
|
-
pieces: list[str] = d.field(init=False, default_factory=list)
|
21
15
|
|
22
|
-
|
23
|
-
def
|
16
|
+
class memory_handler_t(base_t):
|
17
|
+
def __init__(
|
18
|
+
self, name: str | None, message_width: int, level: int, format_: formats_h
|
19
|
+
) -> None:
|
24
20
|
""""""
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
21
|
+
assert format_ in h.get_args(formats_h)
|
22
|
+
|
23
|
+
base_t.__init__(self, name, message_width, None, level)
|
24
|
+
|
25
|
+
self.format_ = format_
|
26
|
+
self.records = []
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
def New(
|
30
|
+
cls,
|
31
|
+
/,
|
32
|
+
*,
|
33
|
+
name: str | None = None,
|
34
|
+
message_width: int = -1,
|
35
|
+
level: int = l.NOTSET,
|
36
|
+
format_: formats_h = "message",
|
37
|
+
**_,
|
38
|
+
) -> h.Self:
|
36
39
|
""""""
|
37
|
-
return
|
40
|
+
return cls(name, message_width, level, format_)
|
38
41
|
|
39
|
-
def
|
42
|
+
def emit(self, record: l.LogRecord, /) -> None:
|
40
43
|
""""""
|
41
|
-
|
42
|
-
|
43
|
-
self.
|
44
|
-
|
45
|
-
|
44
|
+
level = record.levelno
|
45
|
+
|
46
|
+
if self.format_ == "raw":
|
47
|
+
is_not_a_rule = True
|
48
|
+
elif self.format_ == "dict":
|
49
|
+
record = dict(record.__dict__)
|
50
|
+
is_not_a_rule = True
|
51
|
+
elif self.format_ == "json":
|
52
|
+
record = json.dumps(record.__dict__)
|
53
|
+
is_not_a_rule = True
|
54
|
+
else:
|
55
|
+
record, is_not_a_rule = self.MessageFromRecord(record)
|
56
|
+
|
57
|
+
self.records.append((level, record, is_not_a_rule))
|
58
|
+
|
59
|
+
def EmitMessage(self, message: str, /) -> None:
|
46
60
|
""""""
|
47
|
-
if
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
self.inside_body = False
|
56
|
-
|
57
|
-
def handle_data(self, data: str, /) -> None:
|
58
|
-
""""""
|
59
|
-
if self.inside_body:
|
60
|
-
self.pieces.append(data)
|
61
|
+
if self.format_ == "message":
|
62
|
+
message_key = "msg"
|
63
|
+
else:
|
64
|
+
message_key = "message"
|
65
|
+
record = l.makeLogRecord(
|
66
|
+
{"name": "<UNKNOWN LOGGER>", "levelno": l.INFO, message_key: message}
|
67
|
+
)
|
68
|
+
self.emit(record)
|
61
69
|
|
62
70
|
|
63
71
|
"""
|
@@ -5,16 +5,17 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
from logger_36.constant.system import MAX_DETAIL_NAME_LENGTH, SYSTEM_DETAILS_AS_DICT
|
8
|
+
from logger_36.extension.inspection import Modules
|
8
9
|
from logger_36.instance.logger import L
|
9
|
-
from logger_36.task.inspection import Modules
|
10
10
|
from logger_36.type.logger import logger_t
|
11
11
|
|
12
12
|
|
13
13
|
def LogSystemDetails(
|
14
14
|
*,
|
15
|
+
should_restrict_modules_to_loaded: bool = True,
|
15
16
|
modules_with_version: bool = True,
|
16
17
|
modules_formatted: bool = True,
|
17
|
-
|
18
|
+
indent: int = 4,
|
18
19
|
logger: logger_t = L,
|
19
20
|
) -> None:
|
20
21
|
""""""
|
@@ -23,10 +24,10 @@ def LogSystemDetails(
|
|
23
24
|
for _key, _vle in SYSTEM_DETAILS_AS_DICT.items()
|
24
25
|
)
|
25
26
|
modules = Modules(
|
26
|
-
modules_with_version,
|
27
|
-
modules_formatted,
|
28
27
|
only_loaded=should_restrict_modules_to_loaded,
|
29
|
-
|
28
|
+
with_version=modules_with_version,
|
29
|
+
formatted=modules_formatted,
|
30
|
+
indent=indent,
|
30
31
|
)
|
31
32
|
|
32
33
|
logger.info(
|
@@ -4,7 +4,14 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
from
|
7
|
+
from datetime import datetime as date_time_t
|
8
|
+
|
9
|
+
# This module is imported early. Therefore, the current date and time should be close
|
10
|
+
# enough to the real start date and time of the main script.
|
11
|
+
START_DATE_TIME = date_time_t.now()
|
12
|
+
|
13
|
+
DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
|
14
|
+
DATE_ORIGIN = DATE_TIME_ORIGIN.date()
|
8
15
|
|
9
16
|
"""
|
10
17
|
COPYRIGHT NOTICE
|
logger_36/constant/path.py
CHANGED
@@ -12,15 +12,16 @@ USER_FOLDER = path_t.home()
|
|
12
12
|
|
13
13
|
frame = e.stack(context=0)[-1] # -1=root caller.
|
14
14
|
if path_t(frame.filename).exists():
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
LAUNCH_ROOT_FILE = path_t(frame.filename)
|
16
|
+
LAUNCH_FOLDER = LAUNCH_ROOT_FILE.parent
|
17
|
+
|
18
|
+
if LAUNCH_ROOT_FILE.is_relative_to(USER_FOLDER):
|
19
|
+
LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE.relative_to(USER_FOLDER)
|
18
20
|
else:
|
19
|
-
|
20
|
-
PROJECT_FOLDER = PROJECT_FILE.parent
|
21
|
+
LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE
|
21
22
|
else:
|
22
|
-
|
23
|
-
|
23
|
+
LAUNCH_ROOT_FILE = LAUNCH_ROOT_FILE_relative = "<unknown launch root file>"
|
24
|
+
LAUNCH_FOLDER = path_t(tmps.mkdtemp())
|
24
25
|
|
25
26
|
"""
|
26
27
|
COPYRIGHT NOTICE
|
logger_36/constant/record.py
CHANGED
logger_36/constant/rule.py
CHANGED
@@ -4,9 +4,9 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
|
7
|
+
from logger_36.config.rule import DEFAULT_RULE_LENGTH, RULE_CHARACTER
|
8
|
+
|
8
9
|
MIN_HALF_RULE_LENGTH = 4
|
9
|
-
DEFAULT_RULE_LENGTH = 50
|
10
10
|
DEFAULT_RULE = DEFAULT_RULE_LENGTH * RULE_CHARACTER
|
11
11
|
|
12
12
|
"""
|
@@ -4,14 +4,16 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
import importlib.metadata as mprt
|
8
7
|
import pkgutil as pkgs
|
9
8
|
import sys as s
|
10
|
-
from types import FunctionType, MethodType
|
11
9
|
|
12
10
|
|
13
11
|
def Modules(
|
14
|
-
|
12
|
+
*,
|
13
|
+
only_loaded: bool = True,
|
14
|
+
with_version: bool = True,
|
15
|
+
formatted: bool = False,
|
16
|
+
indent: int = 0,
|
15
17
|
) -> tuple[str, ...] | str:
|
16
18
|
""""""
|
17
19
|
output = []
|
@@ -61,23 +63,6 @@ def Modules(
|
|
61
63
|
return tuple(output)
|
62
64
|
|
63
65
|
|
64
|
-
def WhereFunction(function: FunctionType, /) -> str:
|
65
|
-
""""""
|
66
|
-
return f"{function.__module__}:{function.__name__}"
|
67
|
-
|
68
|
-
|
69
|
-
def WhereMethod(instance: object, method: MethodType, /) -> str:
|
70
|
-
"""
|
71
|
-
method: Could be a str instead, which would require changing method.__name__ into
|
72
|
-
getattr(cls, method). But if the method name changes while forgetting to change the
|
73
|
-
string in the call to WhereMethod accordingly, then an exception would be raised
|
74
|
-
here.
|
75
|
-
"""
|
76
|
-
cls = instance.__class__
|
77
|
-
|
78
|
-
return f"{cls.__module__}:{cls.__name__}:{method.__name__}"
|
79
|
-
|
80
|
-
|
81
66
|
def _ModulesUsingPkgUtil() -> tuple[str, ...]:
|
82
67
|
"""
|
83
68
|
Returns more results than using importlib.
|
@@ -91,15 +76,16 @@ def _ModulesUsingPkgUtil() -> tuple[str, ...]:
|
|
91
76
|
)
|
92
77
|
|
93
78
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
79
|
+
# import importlib.metadata as mprt
|
80
|
+
# def _ModulesUsingImportlib() -> tuple[str, ...]:
|
81
|
+
# """"""
|
82
|
+
# return tuple(
|
83
|
+
# sorted(
|
84
|
+
# _elm
|
85
|
+
# for _elm in mprt.packages_distributions()
|
86
|
+
# if (_elm[0] != "_") and ("__" not in _elm) and ("/" not in _elm)
|
87
|
+
# )
|
88
|
+
# )
|
103
89
|
|
104
90
|
|
105
91
|
"""
|
@@ -0,0 +1,66 @@
|
|
1
|
+
"""
|
2
|
+
Copyright CNRS (https://www.cnrs.fr/index.php/en)
|
3
|
+
Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
4
|
+
SEE COPYRIGHT NOTICE BELOW
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging as l
|
8
|
+
import sys as s
|
9
|
+
from os import sep as FOLDER_SEPARATOR
|
10
|
+
from pathlib import Path as path_t
|
11
|
+
|
12
|
+
from logger_36.constant.path import USER_FOLDER
|
13
|
+
from logger_36.constant.record import WHERE_ATTR
|
14
|
+
|
15
|
+
|
16
|
+
def RecordLocation(record: l.LogRecord, should_also_store: bool, /) -> str:
|
17
|
+
""""""
|
18
|
+
module = path_t(record.pathname)
|
19
|
+
for path in s.path:
|
20
|
+
if module.is_relative_to(path):
|
21
|
+
module = module.relative_to(path).with_suffix("")
|
22
|
+
module = str(module).replace(FOLDER_SEPARATOR, ".")
|
23
|
+
break
|
24
|
+
else:
|
25
|
+
if module.is_relative_to(USER_FOLDER):
|
26
|
+
module = module.relative_to(USER_FOLDER)
|
27
|
+
|
28
|
+
output = f"{module}:{record.funcName}:{record.lineno}"
|
29
|
+
|
30
|
+
if should_also_store:
|
31
|
+
setattr(record, WHERE_ATTR, output)
|
32
|
+
|
33
|
+
return output
|
34
|
+
|
35
|
+
|
36
|
+
"""
|
37
|
+
COPYRIGHT NOTICE
|
38
|
+
|
39
|
+
This software is governed by the CeCILL license under French law and
|
40
|
+
abiding by the rules of distribution of free software. You can use,
|
41
|
+
modify and/ or redistribute the software under the terms of the CeCILL
|
42
|
+
license as circulated by CEA, CNRS and INRIA at the following URL
|
43
|
+
"http://www.cecill.info".
|
44
|
+
|
45
|
+
As a counterpart to the access to the source code and rights to copy,
|
46
|
+
modify and redistribute granted by the license, users are provided only
|
47
|
+
with a limited warranty and the software's author, the holder of the
|
48
|
+
economic rights, and the successive licensors have only limited
|
49
|
+
liability.
|
50
|
+
|
51
|
+
In this respect, the user's attention is drawn to the risks associated
|
52
|
+
with loading, using, modifying and/or developing or reproducing the
|
53
|
+
software by the user in light of its specific status of free software,
|
54
|
+
that may mean that it is complicated to manipulate, and that also
|
55
|
+
therefore means that it is reserved for developers and experienced
|
56
|
+
professionals having in-depth computer knowledge. Users are therefore
|
57
|
+
encouraged to load and test the software's suitability as regards their
|
58
|
+
requirements in conditions enabling the security of their systems and/or
|
59
|
+
data to be ensured and, more generally, to use and operate it in the
|
60
|
+
same conditions as regards security.
|
61
|
+
|
62
|
+
The fact that you are presently reading this means that you have had
|
63
|
+
knowledge of the CeCILL license and that you accept its terms.
|
64
|
+
|
65
|
+
SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
|
66
|
+
"""
|
@@ -7,9 +7,7 @@ SEE COPYRIGHT NOTICE BELOW
|
|
7
7
|
import time
|
8
8
|
from datetime import datetime as date_time_t
|
9
9
|
|
10
|
-
|
11
|
-
# enough to the real start time of the main script.
|
12
|
-
_START_DATE_AND_TIME = date_time_t.now()
|
10
|
+
from logger_36.constant.date_time import START_DATE_TIME
|
13
11
|
|
14
12
|
|
15
13
|
def TimeStamp(*, precision: str = "microseconds") -> str:
|
@@ -25,7 +23,7 @@ def TimeStamp(*, precision: str = "microseconds") -> str:
|
|
25
23
|
def ElapsedTime(*, should_return_now: bool = False) -> str | tuple[str, date_time_t]:
|
26
24
|
""""""
|
27
25
|
now = date_time_t.now()
|
28
|
-
elapsed_seconds = (now -
|
26
|
+
elapsed_seconds = (now - START_DATE_TIME).total_seconds()
|
29
27
|
output = time.strftime("%H:%M:%S", time.gmtime(elapsed_seconds))
|
30
28
|
while output.startswith("00:"):
|
31
29
|
output = output.split(sep=":", maxsplit=1)[-1]
|
logger_36/task/storage.py
CHANGED
@@ -5,30 +5,35 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging as l
|
8
|
+
import os as o
|
9
|
+
import tempfile as tmps
|
8
10
|
from io import IOBase as io_base_t
|
9
11
|
from pathlib import Path as path_t
|
10
12
|
|
11
13
|
from logger_36.constant.html import BODY_PLACEHOLDER, MINIMAL_HTML, TITLE_PLACEHOLDER
|
12
14
|
from logger_36.instance.logger import L
|
15
|
+
from logger_36.type.logger import logger_t
|
13
16
|
|
14
17
|
|
15
|
-
def SaveLOGasHTML(
|
18
|
+
def SaveLOGasHTML(
|
19
|
+
path: str | path_t | io_base_t | None = None, /, *, logger: logger_t = L
|
20
|
+
) -> None:
|
16
21
|
"""
|
17
22
|
From first console handler found.
|
18
23
|
"""
|
19
24
|
cannot_save = "Cannot save logging record as HTML"
|
20
25
|
|
21
26
|
if path is None:
|
22
|
-
for handler in
|
27
|
+
for handler in logger.handlers:
|
23
28
|
if isinstance(handler, l.FileHandler):
|
24
29
|
path = path_t(handler.baseFilename).with_suffix(".htm")
|
25
30
|
break
|
26
31
|
else:
|
27
|
-
|
32
|
+
logger.warning(f"{cannot_save}: No file handler to build a filename from.")
|
28
33
|
return
|
29
34
|
|
30
35
|
if path.exists():
|
31
|
-
|
36
|
+
logger.warning(
|
32
37
|
f'{cannot_save}: Automatically generated path "{path}" already exists.'
|
33
38
|
)
|
34
39
|
return
|
@@ -38,13 +43,45 @@ def SaveLOGasHTML(path: str | path_t | io_base_t | None = None) -> None:
|
|
38
43
|
actual_file = isinstance(path, path_t)
|
39
44
|
|
40
45
|
if actual_file and path.exists():
|
41
|
-
|
46
|
+
existing = path
|
47
|
+
|
48
|
+
accessor, path = tmps.mkstemp(suffix=".htm")
|
49
|
+
o.close(accessor)
|
50
|
+
path = path_t(path)
|
51
|
+
|
52
|
+
logger.warning(
|
53
|
+
f'File "{existing}" already exists: Saving LOG as HTML in {path} instead.'
|
54
|
+
)
|
55
|
+
|
56
|
+
for handler in logger.handlers:
|
57
|
+
records = getattr(handler, "records", None)
|
58
|
+
if isinstance(records, list) and (
|
59
|
+
(records.__len__() == 0)
|
60
|
+
or all(
|
61
|
+
isinstance(_, tuple)
|
62
|
+
and isinstance(_[0], int)
|
63
|
+
and isinstance(_[1], dict | str | l.LogRecord)
|
64
|
+
and isinstance(_[2], bool)
|
65
|
+
for _ in records
|
66
|
+
)
|
67
|
+
):
|
68
|
+
break
|
69
|
+
else:
|
70
|
+
logger.warning(f"{cannot_save}: No handlers with recording capability found.")
|
42
71
|
return
|
43
72
|
|
44
|
-
|
45
|
-
|
73
|
+
if records.__len__() == 0:
|
74
|
+
return
|
75
|
+
|
76
|
+
if isinstance(records[0][1], str):
|
77
|
+
records = map(_HighlightedEvent, records)
|
78
|
+
else:
|
79
|
+
records = map(lambda _: str(_[1]), records)
|
80
|
+
body = "\n".join(records)
|
81
|
+
html = MINIMAL_HTML.replace(TITLE_PLACEHOLDER, logger.name).replace(
|
46
82
|
BODY_PLACEHOLDER, body
|
47
83
|
)
|
84
|
+
|
48
85
|
if actual_file:
|
49
86
|
with open(path, "w") as accessor:
|
50
87
|
accessor.write(html)
|
@@ -52,21 +89,25 @@ def SaveLOGasHTML(path: str | path_t | io_base_t | None = None) -> None:
|
|
52
89
|
path.write(html)
|
53
90
|
|
54
91
|
|
55
|
-
def _HighlightedEvent(event: tuple[int, str], /) -> str:
|
92
|
+
def _HighlightedEvent(event: tuple[int, str, bool], /) -> str:
|
56
93
|
""""""
|
57
|
-
level, message = event
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
94
|
+
level, message, is_not_a_rule = event
|
95
|
+
|
96
|
+
if is_not_a_rule:
|
97
|
+
if level == l.DEBUG:
|
98
|
+
color = "BlueViolet"
|
99
|
+
elif level == l.INFO:
|
100
|
+
color = "black"
|
101
|
+
elif level == l.WARNING:
|
102
|
+
color = "gold"
|
103
|
+
elif level == l.ERROR:
|
104
|
+
color = "orange"
|
105
|
+
elif level == l.CRITICAL:
|
106
|
+
color = "red"
|
107
|
+
else:
|
108
|
+
color = "black"
|
68
109
|
else:
|
69
|
-
color = "
|
110
|
+
color = "DarkTurquoise"
|
70
111
|
|
71
112
|
return f'<span style="color:{color}">{message}</span>'
|
72
113
|
|
logger_36/type/handler.py
CHANGED
@@ -15,14 +15,10 @@ from logger_36.config.message import (
|
|
15
15
|
MESSAGE_MARKER,
|
16
16
|
WHERE_SEPARATOR,
|
17
17
|
)
|
18
|
+
from logger_36.config.rule import DEFAULT_RULE_LENGTH, RULE_CHARACTER
|
18
19
|
from logger_36.constant.message import NEXT_LINE_PROLOGUE
|
19
20
|
from logger_36.constant.record import SHOW_W_RULE_ATTR, WHEN_OR_ELAPSED_ATTR, WHERE_ATTR
|
20
|
-
from logger_36.constant.rule import
|
21
|
-
DEFAULT_RULE,
|
22
|
-
DEFAULT_RULE_LENGTH,
|
23
|
-
MIN_HALF_RULE_LENGTH,
|
24
|
-
RULE_CHARACTER,
|
25
|
-
)
|
21
|
+
from logger_36.constant.rule import DEFAULT_RULE, MIN_HALF_RULE_LENGTH
|
26
22
|
from logger_36.extension.line import WrappedLines
|
27
23
|
|
28
24
|
|
@@ -56,7 +52,7 @@ class extension_t:
|
|
56
52
|
raise NotImplementedError
|
57
53
|
|
58
54
|
def MessageFromRecord(
|
59
|
-
self, record: l.LogRecord, /, *, rule_color: str
|
55
|
+
self, record: l.LogRecord, /, *, rule_color: str = "black"
|
60
56
|
) -> tuple[str, bool]:
|
61
57
|
"""
|
62
58
|
The second returned value is is_not_a_rule.
|
@@ -122,7 +118,7 @@ class extension_t:
|
|
122
118
|
self.EmitMessage(self.Rule(text=text, color=color))
|
123
119
|
|
124
120
|
|
125
|
-
class
|
121
|
+
class non_file_handler_t(l.Handler, extension_t):
|
126
122
|
def __init__(
|
127
123
|
self,
|
128
124
|
name: str | None,
|
@@ -160,10 +156,10 @@ class file_handler_t(l.FileHandler, extension_t):
|
|
160
156
|
__post_init__(self, level)
|
161
157
|
|
162
158
|
|
163
|
-
|
159
|
+
handler_h = non_file_handler_t | file_handler_t
|
164
160
|
|
165
161
|
|
166
|
-
def __post_init__(handler:
|
162
|
+
def __post_init__(handler: handler_h, level: int) -> None:
|
167
163
|
""""""
|
168
164
|
handler.setLevel(level)
|
169
165
|
|
logger_36/type/logger.py
CHANGED
@@ -15,7 +15,6 @@ import types as t
|
|
15
15
|
import typing as h
|
16
16
|
from datetime import date as date_t
|
17
17
|
from datetime import datetime as date_time_t
|
18
|
-
from os import sep as FOLDER_SEPARATOR
|
19
18
|
from pathlib import Path as path_t
|
20
19
|
from traceback import TracebackException as traceback_t
|
21
20
|
|
@@ -35,22 +34,20 @@ from logger_36.config.message import (
|
|
35
34
|
TIME_FORMAT,
|
36
35
|
WHERE_SEPARATOR,
|
37
36
|
)
|
37
|
+
from logger_36.constant.date_time import DATE_ORIGIN, DATE_TIME_ORIGIN
|
38
38
|
from logger_36.constant.generic import NOT_PASSED
|
39
39
|
from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR, ORDER, order_h
|
40
40
|
from logger_36.constant.logger import WARNING_LOGGER_NAME, WARNING_TYPE_COMPILED_PATTERN
|
41
41
|
from logger_36.constant.memory import UNKNOWN_MEMORY_USAGE
|
42
42
|
from logger_36.constant.message import LINE_INDENT, TIME_LENGTH_m_1, expected_op_h
|
43
|
-
from logger_36.constant.path import
|
44
|
-
from logger_36.constant.record import
|
45
|
-
|
46
|
-
SHOW_W_RULE_ATTR,
|
47
|
-
SHOW_WHERE_ATTR,
|
48
|
-
)
|
43
|
+
from logger_36.constant.path import USER_FOLDER, LAUNCH_ROOT_FILE_relative
|
44
|
+
from logger_36.constant.record import SHOW_W_RULE_ATTR, SHOW_WHERE_ATTR
|
45
|
+
from logger_36.extension.record import RecordLocation
|
49
46
|
from logger_36.task.format.message import MessageWithActualExpected
|
50
47
|
from logger_36.task.measure.chronos import ElapsedTime
|
51
48
|
from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage
|
52
|
-
from logger_36.type.handler import any_handler_t as base_handler_t
|
53
49
|
from logger_36.type.handler import extension_t as handler_extension_t
|
50
|
+
from logger_36.type.handler import handler_h as base_handler_h
|
54
51
|
from logger_36.type.issue import NewIssue, issue_t
|
55
52
|
|
56
53
|
if RICH_IS_AVAILABLE:
|
@@ -66,9 +63,6 @@ logger_handle_raw_h = h.Callable[[l.LogRecord], None]
|
|
66
63
|
logger_handle_with_self_h = h.Callable[[l.Logger, l.LogRecord], None]
|
67
64
|
logger_handle_h = logger_handle_raw_h | logger_handle_with_self_h
|
68
65
|
|
69
|
-
_DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
|
70
|
-
_DATE_ORIGIN = _DATE_TIME_ORIGIN.date()
|
71
|
-
|
72
66
|
|
73
67
|
@d.dataclass(slots=True, repr=False, eq=False)
|
74
68
|
class logger_t(base_t):
|
@@ -79,24 +73,18 @@ class logger_t(base_t):
|
|
79
73
|
_should_activate_log_interceptions: Loggers instantiated after a logger_t logger
|
80
74
|
will be missed by an early call of ToggleLogInterceptions. Therefore, passing True
|
81
75
|
for activate_log_interceptions only sets _should_activate_log_interceptions to True,
|
82
|
-
which is later checked in AddHandler to effectively call ToggleLogInterceptions
|
83
|
-
_warming_up is False (which normally indicates that the handler about to
|
84
|
-
be added is the last one).
|
85
|
-
|
86
|
-
_warming_up: Must not be False until at least one handler has been added.
|
76
|
+
which is later checked in AddHandler to effectively call ToggleLogInterceptions.
|
87
77
|
"""
|
88
78
|
|
89
|
-
should_record_messages: bool = False
|
90
|
-
should_monitor_memory_usage: bool = False
|
91
79
|
exit_on_error: bool = False # Implies exit_on_critical.
|
92
80
|
exit_on_critical: bool = False
|
93
|
-
|
81
|
+
should_monitor_memory_usage: bool = False
|
94
82
|
|
95
|
-
|
96
|
-
|
83
|
+
history: dict[date_time_t, str] = d.field(init=False, default_factory=dict)
|
84
|
+
n_events: dict[int, int] = d.field(init=False, default_factory=dict)
|
97
85
|
|
98
|
-
last_message_now: date_time_t = d.field(init=False, default=
|
99
|
-
last_message_date: date_t = d.field(init=False, default=
|
86
|
+
last_message_now: date_time_t = d.field(init=False, default=DATE_TIME_ORIGIN)
|
87
|
+
last_message_date: date_t = d.field(init=False, default=DATE_ORIGIN)
|
100
88
|
memory_usages: list[tuple[str, int]] = d.field(init=False, default_factory=list)
|
101
89
|
context_levels: list[str] = d.field(init=False, default_factory=list)
|
102
90
|
staged_issues: list[issue_t] = d.field(init=False, default_factory=list)
|
@@ -105,12 +93,9 @@ class logger_t(base_t):
|
|
105
93
|
init=False, default_factory=dict
|
106
94
|
)
|
107
95
|
intercepts_exceptions: bool = d.field(init=False, default=False)
|
108
|
-
_recording_handler: handler_extension_t | None = d.field(init=False, default=None)
|
109
96
|
|
110
|
-
# Used only until the
|
97
|
+
# Used only until the first handler is added (see AddHandler).
|
111
98
|
_should_activate_log_interceptions: bool = d.field(init=False, default=False)
|
112
|
-
_warming_up: bool = d.field(init=False, default=True)
|
113
|
-
_on_hold: list[l.LogRecord] | None = d.field(init=False, default_factory=list)
|
114
99
|
|
115
100
|
name_: d.InitVar[str | None] = None
|
116
101
|
level_: d.InitVar[int] = l.NOTSET
|
@@ -118,6 +103,12 @@ class logger_t(base_t):
|
|
118
103
|
activate_log_interceptions: d.InitVar[bool] = True
|
119
104
|
activate_exc_interceptions: d.InitVar[bool] = True
|
120
105
|
|
106
|
+
@property
|
107
|
+
def formatted_history(self) -> str:
|
108
|
+
""""""
|
109
|
+
FormattedEntry = lambda _: f"{_[0]}: {_[1].replace('\n', '↲ ')}"
|
110
|
+
return "\n".join(map(FormattedEntry, self.history.items()))
|
111
|
+
|
121
112
|
@property
|
122
113
|
def intercepts_warnings(self) -> bool:
|
123
114
|
""""""
|
@@ -168,7 +159,10 @@ class logger_t(base_t):
|
|
168
159
|
if name_ is None:
|
169
160
|
name_ = f"{type(self).__name__}:{hex(id(self))[2:]}"
|
170
161
|
|
171
|
-
self.
|
162
|
+
self.history[date_time_t.now()] = (
|
163
|
+
f'Logger "{name_}" instantiation for "{LAUNCH_ROOT_FILE_relative}"'
|
164
|
+
)
|
165
|
+
|
172
166
|
base_t.__init__(self, name_)
|
173
167
|
self.setLevel(level_)
|
174
168
|
self.propagate = False # Part of base_t.
|
@@ -177,15 +171,7 @@ class logger_t(base_t):
|
|
177
171
|
self.exit_on_critical = True
|
178
172
|
|
179
173
|
for level_id in l.getLevelNamesMapping().values():
|
180
|
-
self.
|
181
|
-
|
182
|
-
if self.should_record_messages:
|
183
|
-
self.ActivateMessageRecording()
|
184
|
-
|
185
|
-
self.info(
|
186
|
-
f'New logger "{self.name}" for "{PROJECT_FILE_RELATIVE}"',
|
187
|
-
extra={INTERNAL_INFO_ATTR: True},
|
188
|
-
)
|
174
|
+
self.n_events[level_id] = 0
|
189
175
|
|
190
176
|
if activate_wrn_interceptions:
|
191
177
|
self.ToggleWarningInterceptions(True)
|
@@ -197,29 +183,8 @@ class logger_t(base_t):
|
|
197
183
|
if self.should_monitor_memory_usage:
|
198
184
|
self.ActivateMemoryUsageMonitoring()
|
199
185
|
|
200
|
-
def
|
186
|
+
def handle(self, record: l.LogRecord, /) -> None:
|
201
187
|
""""""
|
202
|
-
now = ElapsedTime(should_return_now=True)[1]
|
203
|
-
if (date := now.date()) != self.last_message_date:
|
204
|
-
self._AcknowledgeDateChange(date)
|
205
|
-
|
206
|
-
# When.
|
207
|
-
record.when_or_elapsed = (TIME_LENGTH_m_1 + 1) * "."
|
208
|
-
# Where.
|
209
|
-
if record.levelno != l.INFO:
|
210
|
-
_ = _RecordLocation(record, True)
|
211
|
-
# What.
|
212
|
-
if not isinstance(record.msg, str):
|
213
|
-
record.msg = str(record.msg)
|
214
|
-
|
215
|
-
self._on_hold.append(record)
|
216
|
-
|
217
|
-
def _HandleRoutine(self, record: l.LogRecord, /) -> None:
|
218
|
-
""""""
|
219
|
-
is_internal_info = getattr(record, INTERNAL_INFO_ATTR, False)
|
220
|
-
if is_internal_info and not self.verbose:
|
221
|
-
return
|
222
|
-
|
223
188
|
elapsed_time, now = ElapsedTime(should_return_now=True)
|
224
189
|
|
225
190
|
if (date := now.date()) != self.last_message_date:
|
@@ -236,7 +201,7 @@ class logger_t(base_t):
|
|
236
201
|
# Where.
|
237
202
|
should_show_where = getattr(record, SHOW_WHERE_ATTR, record.levelno != l.INFO)
|
238
203
|
if should_show_where or self.should_monitor_memory_usage:
|
239
|
-
where =
|
204
|
+
where = RecordLocation(record, should_show_where)
|
240
205
|
else:
|
241
206
|
where = None
|
242
207
|
|
@@ -244,7 +209,8 @@ class logger_t(base_t):
|
|
244
209
|
if not isinstance(record.msg, str):
|
245
210
|
record.msg = str(record.msg)
|
246
211
|
|
247
|
-
|
212
|
+
base_t.handle(self, record)
|
213
|
+
self.n_events[record.levelno] += 1
|
248
214
|
|
249
215
|
if self.should_monitor_memory_usage:
|
250
216
|
self.memory_usages.append((where, CurrentMemoryUsage()))
|
@@ -256,29 +222,6 @@ class logger_t(base_t):
|
|
256
222
|
# __post_init__ set self.exit_on_critical if self.exit_on_error.
|
257
223
|
s.exit(1)
|
258
224
|
|
259
|
-
def _HandleRaw(self, record: l.LogRecord, /) -> None:
|
260
|
-
""""""
|
261
|
-
if self.should_record_messages:
|
262
|
-
message = self._recording_handler.MessageFromRecord(record)[0]
|
263
|
-
self.recorded.append((record.levelno, message))
|
264
|
-
|
265
|
-
base_t.handle(self, record)
|
266
|
-
self.events[record.levelno] += 1
|
267
|
-
|
268
|
-
def _FlushRecordsOnHold(self) -> None:
|
269
|
-
"""
|
270
|
-
should_record_messages and verbose must have been set by now.
|
271
|
-
"""
|
272
|
-
for held in self._on_hold:
|
273
|
-
if self.verbose or not getattr(held, INTERNAL_INFO_ATTR, False):
|
274
|
-
self._HandleRaw(held)
|
275
|
-
|
276
|
-
self._on_hold.clear()
|
277
|
-
self._on_hold = None
|
278
|
-
self._warming_up = False
|
279
|
-
|
280
|
-
self.handle = self._HandleRoutine
|
281
|
-
|
282
225
|
def _AcknowledgeDateChange(self, date: date_t, /) -> None:
|
283
226
|
""""""
|
284
227
|
self.last_message_date = date
|
@@ -291,38 +234,12 @@ class logger_t(base_t):
|
|
291
234
|
SHOW_W_RULE_ATTR: True,
|
292
235
|
}
|
293
236
|
)
|
294
|
-
|
295
|
-
if self._warming_up:
|
296
|
-
self._on_hold.append(record)
|
297
|
-
else:
|
298
|
-
self._HandleRaw(record)
|
299
|
-
|
300
|
-
def ActivateMessageRecording(self) -> None:
|
301
|
-
""""""
|
302
|
-
self._recording_handler = handler_extension_t("recording_handler", 0, None)
|
303
|
-
self.should_record_messages = True # Useless if called from __post_init__.
|
304
|
-
self.info(
|
305
|
-
f'Message recording activated for logger "{self.name}"',
|
306
|
-
extra={INTERNAL_INFO_ATTR: True},
|
307
|
-
)
|
308
|
-
|
309
|
-
def ActivateMemoryUsageMonitoring(self) -> None:
|
310
|
-
""""""
|
311
|
-
if MEMORY_MEASURE_IS_AVAILABLE:
|
312
|
-
# Useless if called from __post_init__.
|
313
|
-
self.should_monitor_memory_usage = True
|
314
|
-
self.info(
|
315
|
-
f'Memory usage monitoring activated for logger "{self.name}"',
|
316
|
-
extra={INTERNAL_INFO_ATTR: True},
|
317
|
-
)
|
318
|
-
else:
|
319
|
-
self.should_monitor_memory_usage = False
|
320
|
-
self.error(MEMORY_MEASURE_ERROR)
|
237
|
+
base_t.handle(self, record)
|
321
238
|
|
322
239
|
def ResetEventCounts(self) -> None:
|
323
240
|
""""""
|
324
|
-
for level_id in self.
|
325
|
-
self.
|
241
|
+
for level_id in self.n_events:
|
242
|
+
self.n_events[level_id] = 0
|
326
243
|
|
327
244
|
def ToggleWarningInterceptions(self, state: bool, /) -> None:
|
328
245
|
""""""
|
@@ -335,7 +252,7 @@ class logger_t(base_t):
|
|
335
252
|
logger.handle = t.MethodType(_HandleForWarnings(self), logger)
|
336
253
|
|
337
254
|
l.captureWarnings(True)
|
338
|
-
self.
|
255
|
+
self.history[date_time_t.now()] = "Warning Interception: ON"
|
339
256
|
else:
|
340
257
|
if not self.intercepts_warnings:
|
341
258
|
return
|
@@ -345,12 +262,12 @@ class logger_t(base_t):
|
|
345
262
|
self.intercepted_wrn_handle = None
|
346
263
|
|
347
264
|
l.captureWarnings(False)
|
348
|
-
self.
|
265
|
+
self.history[date_time_t.now()] = "Warning Interception: OFF"
|
349
266
|
|
350
267
|
def ToggleLogInterceptions(self, state: bool, /) -> None:
|
351
268
|
""""""
|
352
269
|
if state:
|
353
|
-
if self.intercepts_logs:
|
270
|
+
if self._should_activate_log_interceptions or self.intercepts_logs:
|
354
271
|
return
|
355
272
|
|
356
273
|
# Note: Alternative to self.manager is logging.root.manager.
|
@@ -369,11 +286,14 @@ class logger_t(base_t):
|
|
369
286
|
intercepted = sorted(self.intercepted_log_handles.keys())
|
370
287
|
if intercepted.__len__() > 0:
|
371
288
|
as_str = ", ".join(intercepted)
|
372
|
-
self.
|
373
|
-
f"Now Intercepting LOGs from: {as_str}"
|
374
|
-
extra={INTERNAL_INFO_ATTR: True},
|
289
|
+
self.history[date_time_t.now()] = (
|
290
|
+
f"Now Intercepting LOGs from: {as_str}"
|
375
291
|
)
|
376
292
|
else:
|
293
|
+
if self._should_activate_log_interceptions:
|
294
|
+
self._should_activate_log_interceptions = False
|
295
|
+
return
|
296
|
+
|
377
297
|
if not self.intercepts_logs:
|
378
298
|
return
|
379
299
|
|
@@ -381,7 +301,7 @@ class logger_t(base_t):
|
|
381
301
|
logger = l.getLogger(name)
|
382
302
|
logger.handle = handle
|
383
303
|
self.intercepted_log_handles.clear()
|
384
|
-
self.
|
304
|
+
self.history[date_time_t.now()] = "Log Interception: OFF"
|
385
305
|
|
386
306
|
def ToggleExceptionInterceptions(self, state: bool, /) -> None:
|
387
307
|
""""""
|
@@ -392,7 +312,7 @@ class logger_t(base_t):
|
|
392
312
|
s.excepthook = self.DealWithException
|
393
313
|
thrd.excepthook = self.DealWithExceptionInThread
|
394
314
|
self.intercepts_exceptions = True
|
395
|
-
self.
|
315
|
+
self.history[date_time_t.now()] = "Exception Interception: ON"
|
396
316
|
else:
|
397
317
|
if not self.intercepts_exceptions:
|
398
318
|
return
|
@@ -400,12 +320,24 @@ class logger_t(base_t):
|
|
400
320
|
s.excepthook = s.__excepthook__
|
401
321
|
thrd.excepthook = thrd.__excepthook__
|
402
322
|
self.intercepts_exceptions = False
|
403
|
-
self.
|
323
|
+
self.history[date_time_t.now()] = "Exception Interception: OFF"
|
324
|
+
|
325
|
+
def ActivateMemoryUsageMonitoring(self) -> None:
|
326
|
+
""""""
|
327
|
+
if MEMORY_MEASURE_IS_AVAILABLE:
|
328
|
+
# Useless if called from __post_init__.
|
329
|
+
self.should_monitor_memory_usage = True
|
330
|
+
self.history[date_time_t.now()] = (
|
331
|
+
f'Memory usage monitoring activated for logger "{self.name}"'
|
332
|
+
)
|
333
|
+
else:
|
334
|
+
self.should_monitor_memory_usage = False
|
335
|
+
self.error(MEMORY_MEASURE_ERROR)
|
404
336
|
|
405
337
|
def AddHandler(
|
406
338
|
self,
|
407
|
-
handler_t_or_handler: type[
|
408
|
-
|
|
339
|
+
handler_t_or_handler: type[base_handler_h]
|
340
|
+
| base_handler_h
|
409
341
|
| l.Handler
|
410
342
|
| l.FileHandler,
|
411
343
|
/,
|
@@ -413,21 +345,16 @@ class logger_t(base_t):
|
|
413
345
|
name: str | None = None,
|
414
346
|
level: int = l.INFO,
|
415
347
|
message_width: int = -1,
|
416
|
-
this_is_last_handler: bool = True,
|
417
348
|
**kwargs,
|
418
349
|
) -> None:
|
419
350
|
"""
|
420
351
|
Silently ignores re-holding request after un-holding.
|
421
352
|
"""
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
self._should_activate_log_interceptions = False
|
428
|
-
|
429
|
-
should_flush_on_hold = True
|
430
|
-
new_handler_warning = "\n(Handlers added from now on will miss above logs.)"
|
353
|
+
if self._should_activate_log_interceptions:
|
354
|
+
# Turn _should_activate_log_interceptions off before calling
|
355
|
+
# ToggleLogInterceptions because it checks it.
|
356
|
+
self._should_activate_log_interceptions = False
|
357
|
+
self.ToggleLogInterceptions(True)
|
431
358
|
|
432
359
|
if isinstance(handler_t_or_handler, type):
|
433
360
|
handler = handler_t_or_handler.New(
|
@@ -437,20 +364,13 @@ class logger_t(base_t):
|
|
437
364
|
handler = handler_t_or_handler
|
438
365
|
base_t.addHandler(self, handler)
|
439
366
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
f"{new_handler_warning}",
|
448
|
-
extra={INTERNAL_INFO_ATTR: True},
|
449
|
-
)
|
450
|
-
|
451
|
-
# Wait until after the handler has been added to flush messages on hold.
|
452
|
-
if should_flush_on_hold:
|
453
|
-
self._FlushRecordsOnHold()
|
367
|
+
path = getattr(handler, "baseFilename", "")
|
368
|
+
if isinstance(path, path_t) or (path.__len__() > 0):
|
369
|
+
path = f"\nPath: {path}"
|
370
|
+
self.history[date_time_t.now()] = (
|
371
|
+
f'New handler "{handler.name}" of type "{type(handler).__name__}" and '
|
372
|
+
f"level {handler.level}={l.getLevelName(handler.level)}{path}"
|
373
|
+
)
|
454
374
|
|
455
375
|
def MakeMonochrome(self) -> None:
|
456
376
|
""""""
|
@@ -510,6 +430,20 @@ class logger_t(base_t):
|
|
510
430
|
)
|
511
431
|
self.log(level, message)
|
512
432
|
|
433
|
+
def LogAsIs(self, message: str, /, *, indented: bool = False) -> None:
|
434
|
+
""""""
|
435
|
+
if indented:
|
436
|
+
message = text.indent(message, LINE_INDENT)
|
437
|
+
|
438
|
+
for handler in self.handlers:
|
439
|
+
EmitMessage = getattr(
|
440
|
+
handler, handler_extension_t.EmitMessage.__name__, None
|
441
|
+
)
|
442
|
+
if EmitMessage is not None:
|
443
|
+
EmitMessage(message)
|
444
|
+
|
445
|
+
info_raw = LogAsIs # To follow the convention of the logging methods info, error...
|
446
|
+
|
513
447
|
def LogException(
|
514
448
|
self,
|
515
449
|
exception: Exception,
|
@@ -544,20 +478,6 @@ class logger_t(base_t):
|
|
544
478
|
""""""
|
545
479
|
self.DealWithException(exc_type, exc_value, exc_traceback)
|
546
480
|
|
547
|
-
def LogAsIs(self, message: str, /, *, indented: bool = False) -> None:
|
548
|
-
""""""
|
549
|
-
if indented:
|
550
|
-
message = text.indent(message, LINE_INDENT)
|
551
|
-
|
552
|
-
for handler in self.handlers:
|
553
|
-
EmitMessage = getattr(
|
554
|
-
handler, handler_extension_t.EmitMessage.__name__, None
|
555
|
-
)
|
556
|
-
if EmitMessage is not None:
|
557
|
-
EmitMessage(message)
|
558
|
-
|
559
|
-
info_raw = LogAsIs # To follow the convention of the logging methods info, error...
|
560
|
-
|
561
481
|
def DisplayRule(
|
562
482
|
self, /, *, message: str | None = None, color: str = "white"
|
563
483
|
) -> None:
|
@@ -692,26 +612,6 @@ class logger_t(base_t):
|
|
692
612
|
return False
|
693
613
|
|
694
614
|
|
695
|
-
def _RecordLocation(record: l.LogRecord, should_also_store: bool, /) -> str:
|
696
|
-
""""""
|
697
|
-
module = path_t(record.pathname)
|
698
|
-
for path in s.path:
|
699
|
-
if module.is_relative_to(path):
|
700
|
-
module = module.relative_to(path).with_suffix("")
|
701
|
-
module = str(module).replace(FOLDER_SEPARATOR, ".")
|
702
|
-
break
|
703
|
-
else:
|
704
|
-
if module.is_relative_to(USER_FOLDER):
|
705
|
-
module = module.relative_to(USER_FOLDER)
|
706
|
-
|
707
|
-
output = f"{module}:{record.funcName}:{record.lineno}"
|
708
|
-
|
709
|
-
if should_also_store:
|
710
|
-
record.where = output
|
711
|
-
|
712
|
-
return output
|
713
|
-
|
714
|
-
|
715
615
|
def _HandleForWarnings(interceptor: base_t, /) -> logger_handle_h:
|
716
616
|
""""""
|
717
617
|
|
logger_36/version.py
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
logger_36/__init__.py,sha256=mK6AD0eWI2Sk42oxleTvsxzYJ28FbHK5WNkpLgAhnNE,2129
|
2
|
-
logger_36/version.py,sha256=
|
3
|
-
logger_36/api/
|
4
|
-
logger_36/api/
|
5
|
-
logger_36/api/
|
6
|
-
logger_36/api/storage.py,sha256=
|
7
|
-
logger_36/api/
|
8
|
-
logger_36/api/time.py,sha256=JG0vgzPSRZ7UWQyoihnVu4sjPC-okFIKA3ZyNh2GaZo,1798
|
9
|
-
logger_36/api/type.py,sha256=eLZ2yuH-sYeh4Z2KnAwTRJEbmkmgzBPMncdqXfFUTG8,1760
|
2
|
+
logger_36/version.py,sha256=QjPDEEk8iJm0lRtofN7Pbc34N4IOYHazajxRPaje3-8,1680
|
3
|
+
logger_36/api/logger.py,sha256=eLZ2yuH-sYeh4Z2KnAwTRJEbmkmgzBPMncdqXfFUTG8,1760
|
4
|
+
logger_36/api/memory.py,sha256=U4mMEkx8WRHk9q2d3SCFGt2EJaBuflOXw2bGbAxOnSc,1828
|
5
|
+
logger_36/api/message.py,sha256=DuT4UX4r_1DTXzuuRD-tvsTZk5X-Nj11loBKhuWOMw0,1791
|
6
|
+
logger_36/api/storage.py,sha256=S1fVzrMp-_zlhg27fRPddWCFQRyvbpFwSreALOeoNFI,1713
|
7
|
+
logger_36/api/time.py,sha256=akg503WsfzSCbHS6SmMcfCUGYLdg9_TyRTFAFzLjPc8,1730
|
10
8
|
logger_36/catalog/config/console_rich.py,sha256=t9p9-AkSgPiLAsm1evAdbz77g7JcVLePhUJ1FzNi3cY,2330
|
11
9
|
logger_36/catalog/config/optional.py,sha256=8d8HdpE07gHfsdoL8mVAlRlh9AgLcb4z7I7h6ob7CfU,2174
|
12
|
-
logger_36/catalog/handler/console.py,sha256=
|
13
|
-
logger_36/catalog/handler/console_rich.py,sha256=
|
10
|
+
logger_36/catalog/handler/console.py,sha256=XIyO_8MrzaTlihDbFhIzRk47HjxMH4gV2Zqp0-1oMsU,2320
|
11
|
+
logger_36/catalog/handler/console_rich.py,sha256=WsxFg8HhqhQ0GsuiZ5NqU06PwZor1jd83dxnRoM-I1M,6199
|
14
12
|
logger_36/catalog/handler/file.py,sha256=yg8GnsV6AmDsx1R5iZlsK-5idqD733gc09Syl02TG7Y,2458
|
15
|
-
logger_36/catalog/handler/generic.py,sha256=
|
13
|
+
logger_36/catalog/handler/generic.py,sha256=Asz0yfs0cn6GTxE2bmrUEhmScOxjfm4KIZGhB4FBc5I,6370
|
14
|
+
logger_36/catalog/handler/memory.py,sha256=V7itZkDXXjdUEunl8aCI3xYc07XtupgFSE7usvd0nSQ,3351
|
16
15
|
logger_36/catalog/logger/chronos.py,sha256=S4m9TMPQy_Ju500mpE1jNzu2gZG-QKdVuvX9RVRKHR8,1911
|
17
16
|
logger_36/catalog/logger/gpu.py,sha256=Py5YY0nD_pqJzJsEKQYoOGHcPqyNVJ3J2noOS3hDL6g,2890
|
18
17
|
logger_36/catalog/logger/memory.py,sha256=J0ZGKO7j1FZA_aDGxpABtvzDy1RjCDiDmWYh4U98fEI,4253
|
19
|
-
logger_36/catalog/logger/system.py,sha256=
|
18
|
+
logger_36/catalog/logger/system.py,sha256=zEbHirATqZAVYFmHLd0pppeuRhka1ucWwyHRq0afQNE,2593
|
20
19
|
logger_36/config/issue.py,sha256=QOkVRPSLZC_2mfcFpad-pcSXJXfLHdWUAXiMbTWlZTg,1741
|
21
20
|
logger_36/config/memory.py,sha256=bZmNYsD2goVdkraS1v_t2OqAJo86jKMtP311kIVURDk,1691
|
22
21
|
logger_36/config/message.py,sha256=3PvvFNT6tzZu6lOkO3xEoyMFnJonx_CMBDwQAbrXD38,2028
|
22
|
+
logger_36/config/rule.py,sha256=BqOb4SWKgT0YQZ-DtOzkLNZNWZVZkl5GN3lMoWoPrKw,1702
|
23
23
|
logger_36/config/system.py,sha256=YRSa2eN_SoTnTXWUXAcpKt4JXifabzMR0eXwjUYlA_A,1951
|
24
|
+
logger_36/constant/date_time.py,sha256=fUqiTekMtpJc6aV6x4_2B6excMERCKlR0766bDNAV-0,1981
|
24
25
|
logger_36/constant/error.py,sha256=CGisFxb1AWjKbxIKuGqAR7gPKUaD6KkLlY-XmQuIfXg,2301
|
25
26
|
logger_36/constant/generic.py,sha256=SQgkQiRcTIjCRvbxiOb6TEm59BC0FNMcjYoIShpcwLo,1718
|
26
27
|
logger_36/constant/html.py,sha256=eCp6kumL8bvF30lBjz1iPqw1apzM1rG8rxjNr81aJbA,1989
|
@@ -28,25 +29,25 @@ logger_36/constant/issue.py,sha256=0EmcsRmSxktFUJR0qOU0PnKG-gfbLDOULH6sSRHFOcc,1
|
|
28
29
|
logger_36/constant/logger.py,sha256=ZQYX9JiPsoivwRgYNtdEqRKCagSKD88lRqvxP8MX1ZE,1942
|
29
30
|
logger_36/constant/memory.py,sha256=Q_E5tTWa-cGaNwrE_xmKa3BxQG6oJO6DHczrxc_M4sE,1817
|
30
31
|
logger_36/constant/message.py,sha256=YJOEzdI0ZjUOdHo3CsiS56FVPhrfNoQYvXuUkprH61g,2312
|
31
|
-
logger_36/constant/path.py,sha256=
|
32
|
-
logger_36/constant/record.py,sha256=
|
33
|
-
logger_36/constant/rule.py,sha256=
|
32
|
+
logger_36/constant/path.py,sha256=r-vx5ztGhcpYfg37kw0oaxBYdTSkWOJuToTmexaW8tE,2265
|
33
|
+
logger_36/constant/record.py,sha256=VMqGxVTbtHpRiDOsYiXEoyYOocYFm8vtcRY-7zXzJrk,1796
|
34
|
+
logger_36/constant/rule.py,sha256=ul-MqOdHBGBC5Nwn05EUnz2T__7VEs82qiH7Fzs5qCk,1804
|
34
35
|
logger_36/constant/system.py,sha256=pLlLXG5sepQlSUOo3TphaGrHg8xzJBp-GxpL2NPP47k,1904
|
35
|
-
logger_36/extension/
|
36
|
+
logger_36/extension/inspection.py,sha256=LoHXi4wsIgHKrq_7GYkVcfJ9rnBG16pLKMpAoHNwJiY,3922
|
36
37
|
logger_36/extension/line.py,sha256=joeojQX1bZJM53333mOEU3s-YC5ExGOrN9Cu9Lh5-FU,2617
|
38
|
+
logger_36/extension/record.py,sha256=-8nJMkGCRKGcSIV9aYsIDrLJSAYDIJuZ8drScNCCEcw,2459
|
37
39
|
logger_36/instance/logger.py,sha256=X_U10RYU1h2Aa70D8hBnmFyJZtRILK16KN-GB4xkHMU,1782
|
38
40
|
logger_36/instance/loggers.py,sha256=inBk4KKrQ-z3szaopQ29-qQwh1iSc842sWo5J6zJoiM,1725
|
39
|
-
logger_36/task/
|
40
|
-
logger_36/task/storage.py,sha256=KAILmJlF5IULxEX9QRCyXCwcalp5mpunWVh1oXuLvSs,3516
|
41
|
+
logger_36/task/storage.py,sha256=7aXX--1WNYgVLp1Enbi_TcSAjA_bVZO287hFi20661Y,4692
|
41
42
|
logger_36/task/format/memory.py,sha256=J1Oy3jw8wjSp2kuiRUm_VFpzXOHX2FOc7nuRrCyrskw,3723
|
42
43
|
logger_36/task/format/message.py,sha256=Rm6zymVEEGcgKfmxMPXP7q3PtwZJKlXGhqZ5tnvlwxA,3502
|
43
|
-
logger_36/task/measure/chronos.py,sha256=
|
44
|
+
logger_36/task/measure/chronos.py,sha256=azY6eBR-RiNyQBt-8FkTpnxo01tQMw1ZSVuD-1riGD0,2402
|
44
45
|
logger_36/task/measure/memory.py,sha256=kkPHEIUTUhkCOLrAt01eLJLnsnkl0nFPNhFZdIB_JAw,1991
|
45
|
-
logger_36/type/handler.py,sha256=
|
46
|
+
logger_36/type/handler.py,sha256=KWPHdNd_unNvU_IS-kEloZ7L5fppcR6o0kYiOt7h7KQ,6683
|
46
47
|
logger_36/type/issue.py,sha256=QHAYf7QgrjJUtF2D46z6X630qTgeP_0FE5hIwf54RsE,2688
|
47
|
-
logger_36/type/logger.py,sha256=
|
48
|
+
logger_36/type/logger.py,sha256=8Rt12lUALDt3vbxQ9dUS1_XD8VeN6gZDPpWFbQK1iKo,24262
|
48
49
|
logger_36/type/loggers.py,sha256=7EX7Sg_RlduBjdfFlNZmUfNeDloH1xU30Rdkg_-rXh8,3172
|
49
|
-
logger_36-2025.
|
50
|
-
logger_36-2025.
|
51
|
-
logger_36-2025.
|
52
|
-
logger_36-2025.
|
50
|
+
logger_36-2025.24.dist-info/METADATA,sha256=WynTu2dmNvgjXnMqQNp5RyIM3YPCcJgnL4FAW_GYAVM,6529
|
51
|
+
logger_36-2025.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
52
|
+
logger_36-2025.24.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
|
53
|
+
logger_36-2025.24.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|