omlish 0.0.0.dev424__py3-none-any.whl → 0.0.0.dev425__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.
- omlish/__about__.py +3 -3
- omlish/dataclasses/impl/configs.py +2 -1
- omlish/formats/json/stream/lexing.py +8 -0
- omlish/formats/json/stream/utils.py +3 -0
- omlish/formats/json5/streams.py +22 -0
- omlish/lang/__init__.py +3 -1
- omlish/lang/asyncs.py +12 -0
- omlish/lang/functions.py +0 -11
- omlish/lang/lazyglobals.py +27 -5
- omlish/lang/maysync.py +2 -2
- omlish/lifecycles/contextmanagers.py +1 -2
- omlish/lifecycles/controller.py +1 -2
- omlish/lite/asyncs.py +15 -0
- omlish/lite/timing.py +2 -2
- omlish/logs/all.py +23 -34
- omlish/logs/base.py +248 -0
- omlish/logs/callers.py +21 -15
- omlish/logs/infos.py +105 -0
- omlish/logs/levels.py +64 -0
- omlish/logs/protocols.py +31 -0
- omlish/logs/standard.py +12 -11
- omlish/logs/std/adapters.py +41 -0
- omlish/logs/std/configs.py +29 -0
- omlish/logs/{filters.py → std/filters.py} +1 -1
- omlish/logs/{handlers.py → std/handlers.py} +1 -1
- omlish/logs/{json.py → std/json.py} +2 -2
- omlish/logs/{proxy.py → std/proxy.py} +3 -3
- omlish/logs/std/records.py +286 -0
- omlish/logs/times.py +89 -0
- omlish/logs/typed/bindings.py +24 -0
- omlish/logs/utils.py +60 -4
- omlish/logs/warnings.py +8 -0
- omlish/manifests/loading.py +1 -1
- omlish/os/journald.py +3 -3
- omlish/testing/pytest/plugins/skips.py +0 -4
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/RECORD +44 -86
- omlish/defs.py +0 -216
- omlish/dispatch/_dispatch2.py +0 -69
- omlish/dispatch/_dispatch3.py +0 -108
- omlish/dynamic.py +0 -219
- omlish/formats/json/Json.g4 +0 -77
- omlish/formats/json/_antlr/JsonLexer.py +0 -109
- omlish/formats/json/_antlr/JsonListener.py +0 -61
- omlish/formats/json/_antlr/JsonParser.py +0 -457
- omlish/formats/json/_antlr/JsonVisitor.py +0 -42
- omlish/io/trampoline.py +0 -289
- omlish/logs/abc.py +0 -319
- omlish/logs/color.py +0 -27
- omlish/logs/configs.py +0 -29
- omlish/logs/protocol.py +0 -218
- omlish/logs/timing.py +0 -58
- omlish/specs/irc/__init__.py +0 -0
- omlish/specs/irc/messages/__init__.py +0 -0
- omlish/specs/irc/messages/base.py +0 -49
- omlish/specs/irc/messages/formats.py +0 -92
- omlish/specs/irc/messages/messages.py +0 -774
- omlish/specs/irc/messages/parsing.py +0 -98
- omlish/specs/irc/numerics/__init__.py +0 -0
- omlish/specs/irc/numerics/formats.py +0 -97
- omlish/specs/irc/numerics/numerics.py +0 -865
- omlish/specs/irc/numerics/types.py +0 -59
- omlish/specs/irc/protocol/LICENSE +0 -11
- omlish/specs/irc/protocol/__init__.py +0 -61
- omlish/specs/irc/protocol/consts.py +0 -6
- omlish/specs/irc/protocol/errors.py +0 -30
- omlish/specs/irc/protocol/message.py +0 -21
- omlish/specs/irc/protocol/nuh.py +0 -55
- omlish/specs/irc/protocol/parsing.py +0 -158
- omlish/specs/irc/protocol/rendering.py +0 -153
- omlish/specs/irc/protocol/tags.py +0 -102
- omlish/specs/irc/protocol/utils.py +0 -30
- omlish/specs/proto/Protobuf3.g4 +0 -396
- omlish/specs/proto/__init__.py +0 -0
- omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
- omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
- omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
- omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
- omlish/specs/proto/_antlr/__init__.py +0 -0
- omlish/specs/proto/nodes.py +0 -54
- omlish/specs/proto/parsing.py +0 -97
- omlish/sql/parsing/Minisql.g4 +0 -292
- omlish/sql/parsing/__init__.py +0 -0
- omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
- omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
- omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
- omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
- omlish/sql/parsing/_antlr/__init__.py +0 -0
- omlish/sql/parsing/parsing.py +0 -119
- /omlish/{.manifests.json → .omlish-manifests.json} +0 -0
- /omlish/{formats/json/_antlr → logs/std}/__init__.py +0 -0
- /omlish/logs/{noisy.py → std/noisy.py} +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/top_level.txt +0 -0
omlish/logs/callers.py
CHANGED
@@ -12,32 +12,36 @@ import typing as ta
|
|
12
12
|
|
13
13
|
|
14
14
|
class LoggingCaller(ta.NamedTuple):
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
file_path: str
|
16
|
+
line_no: int
|
17
|
+
name: str
|
18
|
+
stack_info: ta.Optional[str]
|
19
19
|
|
20
20
|
@classmethod
|
21
21
|
def is_internal_frame(cls, frame: types.FrameType) -> bool:
|
22
|
-
|
22
|
+
file_path = os.path.normcase(frame.f_code.co_filename)
|
23
23
|
|
24
|
+
# Yes, really.
|
25
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L204
|
24
26
|
# https://github.com/python/cpython/commit/5ca6d7469be53960843df39bb900e9c3359f127f
|
25
|
-
if 'importlib' in
|
27
|
+
if 'importlib' in file_path and '_bootstrap' in file_path:
|
26
28
|
return True
|
27
29
|
|
28
30
|
return False
|
29
31
|
|
30
32
|
@classmethod
|
31
|
-
def find_frame(cls, ofs: int = 0) -> types.FrameType:
|
33
|
+
def find_frame(cls, ofs: int = 0) -> ta.Optional[types.FrameType]:
|
32
34
|
f: ta.Optional[types.FrameType] = sys._getframe(2 + ofs) # noqa
|
33
35
|
|
34
|
-
while f is not None
|
35
|
-
|
36
|
+
while f is not None:
|
37
|
+
# NOTE: We don't check __file__ like stdlib since we may be running amalgamated - we rely on careful, manual
|
38
|
+
# stack_offset management.
|
39
|
+
if hasattr(f, 'f_code'):
|
36
40
|
return f
|
37
41
|
|
38
42
|
f = f.f_back
|
39
43
|
|
40
|
-
|
44
|
+
return None
|
41
45
|
|
42
46
|
@classmethod
|
43
47
|
def find(
|
@@ -45,14 +49,16 @@ class LoggingCaller(ta.NamedTuple):
|
|
45
49
|
ofs: int = 0,
|
46
50
|
*,
|
47
51
|
stack_info: bool = False,
|
48
|
-
) -> 'LoggingCaller':
|
49
|
-
f
|
50
|
-
|
52
|
+
) -> ta.Optional['LoggingCaller']:
|
53
|
+
if (f := cls.find_frame(ofs + 1)) is None:
|
54
|
+
return None
|
51
55
|
|
56
|
+
# https://github.com/python/cpython/blob/08e9794517063c8cd92c48714071b1d3c60b71bd/Lib/logging/__init__.py#L1616-L1623 # noqa
|
52
57
|
sinfo = None
|
53
58
|
if stack_info:
|
54
59
|
sio = io.StringIO()
|
55
|
-
|
60
|
+
# In stdlib, but done elsewhere here:
|
61
|
+
# sio.write('Stack (most recent call last):\n')
|
56
62
|
traceback.print_stack(f, file=sio)
|
57
63
|
sinfo = sio.getvalue()
|
58
64
|
sio.close()
|
@@ -61,7 +67,7 @@ class LoggingCaller(ta.NamedTuple):
|
|
61
67
|
|
62
68
|
return cls(
|
63
69
|
f.f_code.co_filename,
|
64
|
-
f.f_lineno,
|
70
|
+
f.f_lineno or 0,
|
65
71
|
f.f_code.co_name,
|
66
72
|
sinfo,
|
67
73
|
)
|
omlish/logs/infos.py
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# ruff: noqa: UP045
|
2
|
+
# @omlish-lite
|
3
|
+
import os.path
|
4
|
+
import sys
|
5
|
+
import threading
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
@ta.final
|
13
|
+
class LoggingSourceFileInfo(ta.NamedTuple):
|
14
|
+
file_name: str
|
15
|
+
module: str
|
16
|
+
|
17
|
+
@classmethod
|
18
|
+
def build(cls, file_path: ta.Optional[str]) -> ta.Optional['LoggingSourceFileInfo']:
|
19
|
+
if file_path is None:
|
20
|
+
return None
|
21
|
+
|
22
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L331-L336 # noqa
|
23
|
+
try:
|
24
|
+
file_name = os.path.basename(file_path)
|
25
|
+
module = os.path.splitext(file_name)[0]
|
26
|
+
except (TypeError, ValueError, AttributeError):
|
27
|
+
return None
|
28
|
+
|
29
|
+
return cls(
|
30
|
+
file_name,
|
31
|
+
module,
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
##
|
36
|
+
|
37
|
+
|
38
|
+
@ta.final
|
39
|
+
class LoggingThreadInfo(ta.NamedTuple):
|
40
|
+
ident: int
|
41
|
+
native_id: ta.Optional[int]
|
42
|
+
name: str
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def build(cls) -> 'LoggingThreadInfo':
|
46
|
+
return cls(
|
47
|
+
threading.get_ident(),
|
48
|
+
threading.get_native_id() if hasattr(threading, 'get_native_id') else None,
|
49
|
+
threading.current_thread().name,
|
50
|
+
)
|
51
|
+
|
52
|
+
|
53
|
+
##
|
54
|
+
|
55
|
+
|
56
|
+
@ta.final
|
57
|
+
class LoggingProcessInfo(ta.NamedTuple):
|
58
|
+
pid: int
|
59
|
+
|
60
|
+
@classmethod
|
61
|
+
def build(cls) -> 'LoggingProcessInfo':
|
62
|
+
return cls(
|
63
|
+
os.getpid(),
|
64
|
+
)
|
65
|
+
|
66
|
+
|
67
|
+
##
|
68
|
+
|
69
|
+
|
70
|
+
@ta.final
|
71
|
+
class LoggingMultiprocessingInfo(ta.NamedTuple):
|
72
|
+
process_name: str
|
73
|
+
|
74
|
+
@classmethod
|
75
|
+
def build(cls) -> ta.Optional['LoggingMultiprocessingInfo']:
|
76
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L355-L364 # noqa
|
77
|
+
if (mp := sys.modules.get('multiprocessing')) is None:
|
78
|
+
return None
|
79
|
+
|
80
|
+
return cls(
|
81
|
+
mp.current_process().name,
|
82
|
+
)
|
83
|
+
|
84
|
+
|
85
|
+
##
|
86
|
+
|
87
|
+
|
88
|
+
@ta.final
|
89
|
+
class LoggingAsyncioTaskInfo(ta.NamedTuple):
|
90
|
+
name: str
|
91
|
+
|
92
|
+
@classmethod
|
93
|
+
def build(cls) -> ta.Optional['LoggingAsyncioTaskInfo']:
|
94
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L372-L377 # noqa
|
95
|
+
if (asyncio := sys.modules.get('asyncio')) is None:
|
96
|
+
return None
|
97
|
+
|
98
|
+
try:
|
99
|
+
task = asyncio.current_task()
|
100
|
+
except Exception: # noqa
|
101
|
+
return None
|
102
|
+
|
103
|
+
return cls(
|
104
|
+
task.get_name(), # Always non-None
|
105
|
+
)
|
omlish/logs/levels.py
CHANGED
@@ -1,7 +1,71 @@
|
|
1
|
+
# ruff: noqa: UP006 UP045
|
1
2
|
# @omlish-lite
|
3
|
+
import logging
|
4
|
+
import typing as ta
|
2
5
|
|
3
6
|
|
4
7
|
LogLevel = int # ta.TypeAlias
|
5
8
|
|
6
9
|
|
7
10
|
##
|
11
|
+
|
12
|
+
|
13
|
+
@ta.final
|
14
|
+
class NamedLogLevel(int):
|
15
|
+
# logging.getLevelNamesMapping (or, as that is unavailable <3.11, logging._nameToLevel) includes the deprecated
|
16
|
+
# aliases.
|
17
|
+
_NAMES_BY_INT: ta.ClassVar[ta.Mapping[LogLevel, str]] = dict(sorted(logging._levelToName.items(), key=lambda t: -t[0])) # noqa
|
18
|
+
|
19
|
+
_INTS_BY_NAME: ta.ClassVar[ta.Mapping[str, LogLevel]] = {v: k for k, v in _NAMES_BY_INT.items()}
|
20
|
+
|
21
|
+
_NAME_INT_PAIRS: ta.ClassVar[ta.Sequence[ta.Tuple[str, LogLevel]]] = list(_INTS_BY_NAME.items())
|
22
|
+
|
23
|
+
#
|
24
|
+
|
25
|
+
@property
|
26
|
+
def exact_name(self) -> ta.Optional[str]:
|
27
|
+
return self._NAMES_BY_INT.get(self)
|
28
|
+
|
29
|
+
_effective_name: ta.Optional[str]
|
30
|
+
|
31
|
+
@property
|
32
|
+
def effective_name(self) -> ta.Optional[str]:
|
33
|
+
try:
|
34
|
+
return self._effective_name
|
35
|
+
except AttributeError:
|
36
|
+
pass
|
37
|
+
|
38
|
+
if (n := self.exact_name) is None:
|
39
|
+
for n, i in self._NAME_INT_PAIRS: # noqa
|
40
|
+
if self >= i:
|
41
|
+
break
|
42
|
+
else:
|
43
|
+
n = None
|
44
|
+
|
45
|
+
self._effective_name = n
|
46
|
+
return n
|
47
|
+
|
48
|
+
#
|
49
|
+
|
50
|
+
def __repr__(self) -> str:
|
51
|
+
return f'{self.__class__.__name__}({int(self)})'
|
52
|
+
|
53
|
+
def __str__(self) -> str:
|
54
|
+
return self.exact_name or f'{self.effective_name or "INVALID"}:{int(self)}'
|
55
|
+
|
56
|
+
#
|
57
|
+
|
58
|
+
CRITICAL: ta.ClassVar['NamedLogLevel']
|
59
|
+
ERROR: ta.ClassVar['NamedLogLevel']
|
60
|
+
WARNING: ta.ClassVar['NamedLogLevel']
|
61
|
+
INFO: ta.ClassVar['NamedLogLevel']
|
62
|
+
DEBUG: ta.ClassVar['NamedLogLevel']
|
63
|
+
NOTSET: ta.ClassVar['NamedLogLevel']
|
64
|
+
|
65
|
+
|
66
|
+
NamedLogLevel.CRITICAL = NamedLogLevel(logging.CRITICAL)
|
67
|
+
NamedLogLevel.ERROR = NamedLogLevel(logging.ERROR)
|
68
|
+
NamedLogLevel.WARNING = NamedLogLevel(logging.WARNING)
|
69
|
+
NamedLogLevel.INFO = NamedLogLevel(logging.INFO)
|
70
|
+
NamedLogLevel.DEBUG = NamedLogLevel(logging.DEBUG)
|
71
|
+
NamedLogLevel.NOTSET = NamedLogLevel(logging.NOTSET)
|
omlish/logs/protocols.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# @omlish-lite
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from .levels import LogLevel
|
5
|
+
|
6
|
+
|
7
|
+
##
|
8
|
+
|
9
|
+
|
10
|
+
class LoggerLike(ta.Protocol):
|
11
|
+
"""Satisfied by both our Logger and stdlib logging.Logger."""
|
12
|
+
|
13
|
+
def isEnabledFor(self, level: LogLevel) -> bool: ... # noqa
|
14
|
+
|
15
|
+
def getEffectiveLevel(self) -> LogLevel: ... # noqa
|
16
|
+
|
17
|
+
#
|
18
|
+
|
19
|
+
def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
20
|
+
|
21
|
+
def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
22
|
+
|
23
|
+
def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
24
|
+
|
25
|
+
def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
26
|
+
|
27
|
+
def exception(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
28
|
+
|
29
|
+
def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
30
|
+
|
31
|
+
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
omlish/logs/standard.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# @omlish-lite
|
3
3
|
"""
|
4
4
|
TODO:
|
5
|
+
- !! move to std !!
|
5
6
|
- structured
|
6
7
|
- prefixed
|
7
8
|
- debug
|
@@ -12,9 +13,9 @@ import datetime
|
|
12
13
|
import logging
|
13
14
|
import typing as ta
|
14
15
|
|
15
|
-
from .filters import
|
16
|
-
from .json import
|
17
|
-
from .proxy import
|
16
|
+
from .std.filters import TidLoggingFilter
|
17
|
+
from .std.json import JsonLoggingFormatter
|
18
|
+
from .std.proxy import ProxyLoggingHandler
|
18
19
|
|
19
20
|
|
20
21
|
##
|
@@ -31,7 +32,7 @@ STANDARD_LOG_FORMAT_PARTS = [
|
|
31
32
|
]
|
32
33
|
|
33
34
|
|
34
|
-
class
|
35
|
+
class StandardLoggingFormatter(logging.Formatter):
|
35
36
|
@staticmethod
|
36
37
|
def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
|
37
38
|
return ' '.join(v for k, v in parts)
|
@@ -50,7 +51,7 @@ class StandardLogFormatter(logging.Formatter):
|
|
50
51
|
##
|
51
52
|
|
52
53
|
|
53
|
-
class
|
54
|
+
class StandardConfiguredLoggingHandler(ProxyLoggingHandler):
|
54
55
|
def __init_subclass__(cls, **kwargs):
|
55
56
|
raise TypeError('This class serves only as a marker and should not be subclassed.')
|
56
57
|
|
@@ -83,7 +84,7 @@ def configure_standard_logging(
|
|
83
84
|
target: ta.Optional[logging.Logger] = None,
|
84
85
|
force: bool = False,
|
85
86
|
handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
|
86
|
-
) -> ta.Optional[
|
87
|
+
) -> ta.Optional[StandardConfiguredLoggingHandler]:
|
87
88
|
with _locking_logging_module_lock():
|
88
89
|
if target is None:
|
89
90
|
target = logging.root
|
@@ -91,7 +92,7 @@ def configure_standard_logging(
|
|
91
92
|
#
|
92
93
|
|
93
94
|
if not force:
|
94
|
-
if any(isinstance(h,
|
95
|
+
if any(isinstance(h, StandardConfiguredLoggingHandler) for h in list(target.handlers)):
|
95
96
|
return None
|
96
97
|
|
97
98
|
#
|
@@ -105,14 +106,14 @@ def configure_standard_logging(
|
|
105
106
|
|
106
107
|
formatter: logging.Formatter
|
107
108
|
if json:
|
108
|
-
formatter =
|
109
|
+
formatter = JsonLoggingFormatter()
|
109
110
|
else:
|
110
|
-
formatter =
|
111
|
+
formatter = StandardLoggingFormatter(StandardLoggingFormatter.build_log_format(STANDARD_LOG_FORMAT_PARTS))
|
111
112
|
handler.setFormatter(formatter)
|
112
113
|
|
113
114
|
#
|
114
115
|
|
115
|
-
handler.addFilter(
|
116
|
+
handler.addFilter(TidLoggingFilter())
|
116
117
|
|
117
118
|
#
|
118
119
|
|
@@ -125,4 +126,4 @@ def configure_standard_logging(
|
|
125
126
|
|
126
127
|
#
|
127
128
|
|
128
|
-
return
|
129
|
+
return StandardConfiguredLoggingHandler(handler)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# @omlish-lite
|
2
|
+
import logging
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from ..base import Logger
|
6
|
+
from ..base import LoggingContext
|
7
|
+
from ..base import LogLevel
|
8
|
+
from .records import LoggingContextLogRecord
|
9
|
+
|
10
|
+
|
11
|
+
##
|
12
|
+
|
13
|
+
|
14
|
+
class StdLogger(Logger):
|
15
|
+
def __init__(self, std: logging.Logger) -> None:
|
16
|
+
super().__init__()
|
17
|
+
|
18
|
+
self._std = std
|
19
|
+
|
20
|
+
@property
|
21
|
+
def std(self) -> logging.Logger:
|
22
|
+
return self._std
|
23
|
+
|
24
|
+
def get_effective_level(self) -> LogLevel:
|
25
|
+
return self._std.getEffectiveLevel()
|
26
|
+
|
27
|
+
def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any) -> None:
|
28
|
+
if not self.is_enabled_for(ctx.level):
|
29
|
+
return
|
30
|
+
|
31
|
+
ctx.build_caller()
|
32
|
+
|
33
|
+
rec = LoggingContextLogRecord(
|
34
|
+
name=self._std.name,
|
35
|
+
msg=msg,
|
36
|
+
args=args,
|
37
|
+
|
38
|
+
_logging_context=ctx,
|
39
|
+
)
|
40
|
+
|
41
|
+
self._std.handle(rec)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# ruff: noqa: UP006 UP045
|
2
|
+
# @omlish-lite
|
3
|
+
"""
|
4
|
+
https://docs.python.org/3/howto/logging.html#configuring-logging
|
5
|
+
https://docs.python.org/3/library/logging.config.html#logging-config-dictschema
|
6
|
+
"""
|
7
|
+
import dataclasses as dc
|
8
|
+
import typing as ta
|
9
|
+
|
10
|
+
|
11
|
+
FilterDictLoggingConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
|
12
|
+
FormatterDictLoggingConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
|
13
|
+
HandlerDictLoggingConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
|
14
|
+
LoggerDictLoggingConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
|
19
|
+
|
20
|
+
@dc.dataclass()
|
21
|
+
class DictLoggingConfig:
|
22
|
+
version: int = 1
|
23
|
+
incremental: bool = False
|
24
|
+
disable_existing_loggers: bool = False
|
25
|
+
filters: ta.Dict[str, FilterDictLoggingConfig] = dc.field(default_factory=dict)
|
26
|
+
formatters: ta.Dict[str, FormatterDictLoggingConfig] = dc.field(default_factory=dict)
|
27
|
+
handlers: ta.Dict[str, HandlerDictLoggingConfig] = dc.field(default_factory=dict)
|
28
|
+
loggers: ta.Dict[str, LoggerDictLoggingConfig] = dc.field(default_factory=dict)
|
29
|
+
root: ta.Optional[LoggerDictLoggingConfig] = None
|
@@ -7,13 +7,13 @@ TODO:
|
|
7
7
|
import logging
|
8
8
|
import typing as ta
|
9
9
|
|
10
|
-
from
|
10
|
+
from ...lite.json import json_dumps_compact
|
11
11
|
|
12
12
|
|
13
13
|
##
|
14
14
|
|
15
15
|
|
16
|
-
class
|
16
|
+
class JsonLoggingFormatter(logging.Formatter):
|
17
17
|
KEYS: ta.Mapping[str, bool] = {
|
18
18
|
'name': False,
|
19
19
|
'msg': False,
|
@@ -6,7 +6,7 @@ import logging
|
|
6
6
|
##
|
7
7
|
|
8
8
|
|
9
|
-
class
|
9
|
+
class ProxyLoggingFilterer(logging.Filterer):
|
10
10
|
def __init__(self, underlying: logging.Filterer) -> None: # noqa
|
11
11
|
self._underlying = underlying
|
12
12
|
|
@@ -32,9 +32,9 @@ class ProxyLogFilterer(logging.Filterer):
|
|
32
32
|
return self._underlying.filter(record)
|
33
33
|
|
34
34
|
|
35
|
-
class
|
35
|
+
class ProxyLoggingHandler(ProxyLoggingFilterer, logging.Handler):
|
36
36
|
def __init__(self, underlying: logging.Handler) -> None: # noqa
|
37
|
-
|
37
|
+
ProxyLoggingFilterer.__init__(self, underlying)
|
38
38
|
|
39
39
|
_underlying: logging.Handler
|
40
40
|
|