omlish 0.0.0.dev425__py3-none-any.whl → 0.0.0.dev427__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 +2 -2
- omlish/c3.py +4 -1
- omlish/configs/processing/flattening.py +1 -1
- omlish/configs/processing/merging.py +8 -6
- omlish/dataclasses/impl/concerns/doc.py +1 -1
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/procfs.py +2 -2
- omlish/formats/json/stream/lexing.py +63 -16
- omlish/formats/json/stream/parsing.py +1 -1
- omlish/formats/json/stream/utils.py +2 -2
- omlish/formats/logfmt.py +8 -2
- omlish/funcs/genmachine.py +1 -1
- omlish/http/sse.py +1 -1
- omlish/inject/impl/injector.py +1 -1
- omlish/inject/impl/multis.py +2 -2
- omlish/inject/impl/providers.py +0 -4
- omlish/inject/impl/proxy.py +0 -2
- omlish/inject/scopes.py +0 -4
- omlish/io/buffers.py +1 -1
- omlish/lang/__init__.py +23 -13
- omlish/lang/{attrs.py → attrstorage.py} +15 -15
- omlish/lang/cached/property.py +2 -2
- omlish/lang/classes/simple.py +26 -4
- omlish/lang/collections.py +1 -1
- omlish/lang/iterables.py +2 -2
- omlish/lifecycles/contextmanagers.py +1 -1
- omlish/lifecycles/controller.py +1 -1
- omlish/lite/asyncs.py +5 -0
- omlish/lite/attrops.py +332 -0
- omlish/lite/cached.py +1 -1
- omlish/lite/maybes.py +2 -0
- omlish/lite/strings.py +0 -7
- omlish/lite/timing.py +4 -1
- omlish/logs/all.py +4 -0
- omlish/logs/base.py +138 -152
- omlish/logs/callers.py +3 -3
- omlish/logs/contexts.py +250 -0
- omlish/logs/infos.py +16 -5
- omlish/logs/modules.py +10 -0
- omlish/logs/protocols.py +7 -7
- omlish/logs/std/adapters.py +9 -5
- omlish/logs/std/records.py +26 -11
- omlish/logs/times.py +4 -6
- omlish/manifests/loading.py +6 -0
- omlish/os/atomics.py +1 -1
- omlish/reflect/types.py +22 -0
- omlish/sockets/server/server.py +1 -1
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/METADATA +2 -2
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/RECORD +53 -52
- omlish/lite/logs.py +0 -4
- omlish/lite/reprs.py +0 -85
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev427.dist-info}/top_level.txt +0 -0
omlish/logs/base.py
CHANGED
@@ -1,229 +1,215 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007 UP045 UP046
|
2
2
|
# @omlish-lite
|
3
3
|
import abc
|
4
|
-
import sys
|
5
|
-
import time
|
6
|
-
import types
|
7
4
|
import typing as ta
|
8
5
|
|
9
6
|
from ..lite.abstract import Abstract
|
10
|
-
from .
|
11
|
-
from .
|
12
|
-
from .
|
13
|
-
from .
|
14
|
-
from .infos import LoggingSourceFileInfo
|
15
|
-
from .infos import LoggingThreadInfo
|
7
|
+
from .contexts import CaptureLoggingContext
|
8
|
+
from .contexts import CaptureLoggingContextImpl
|
9
|
+
from .contexts import LoggingExcInfoArg
|
10
|
+
from .levels import LogLevel
|
16
11
|
from .levels import NamedLogLevel
|
17
|
-
from .times import LoggingTimeFields
|
18
12
|
|
19
13
|
|
20
14
|
T = ta.TypeVar('T')
|
21
15
|
|
22
16
|
|
23
|
-
|
24
|
-
|
25
|
-
LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
|
26
|
-
LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
27
|
-
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
17
|
+
LoggingMsgFn = ta.Callable[[], ta.Union[str, tuple]] # ta.TypeAlias
|
28
18
|
|
29
19
|
|
30
20
|
##
|
31
21
|
|
32
22
|
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
class AnyLogger(Abstract, ta.Generic[T]):
|
24
|
+
def is_enabled_for(self, level: LogLevel) -> bool:
|
25
|
+
return self.get_effective_level() >= level
|
36
26
|
|
37
|
-
|
27
|
+
@abc.abstractmethod
|
28
|
+
def get_effective_level(self) -> LogLevel:
|
29
|
+
raise NotImplementedError
|
38
30
|
|
39
|
-
|
40
|
-
exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = None
|
31
|
+
#
|
41
32
|
|
42
33
|
@ta.final
|
43
|
-
|
44
|
-
|
45
|
-
raise TypeError
|
46
|
-
|
47
|
-
#
|
34
|
+
def isEnabledFor(self, level: LogLevel) -> bool: # noqa
|
35
|
+
return self.is_enabled_for(level)
|
48
36
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
*,
|
53
|
-
time_ns: ta.Optional[int] = None,
|
37
|
+
@ta.final
|
38
|
+
def getEffectiveLevel(self) -> LogLevel: # noqa
|
39
|
+
return self.get_effective_level()
|
54
40
|
|
55
|
-
|
41
|
+
##
|
56
42
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
) -> None:
|
61
|
-
self.level = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment]
|
43
|
+
@ta.overload
|
44
|
+
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
45
|
+
...
|
62
46
|
|
63
|
-
|
47
|
+
@ta.overload
|
48
|
+
def log(self, level: LogLevel, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
49
|
+
...
|
64
50
|
|
65
|
-
|
66
|
-
|
67
|
-
|
51
|
+
@ta.overload
|
52
|
+
def log(self, level: LogLevel, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
53
|
+
...
|
68
54
|
|
69
|
-
|
55
|
+
@ta.final
|
56
|
+
def log(self, level: LogLevel, *args, **kwargs):
|
57
|
+
return self._log(CaptureLoggingContextImpl(level, stack_offset=1), *args, **kwargs)
|
70
58
|
|
71
|
-
|
72
|
-
sys_exc_info = sys.exc_info()
|
73
|
-
if sys_exc_info[0] is not None:
|
74
|
-
exc_info = sys_exc_info
|
75
|
-
else:
|
76
|
-
exc_info = None
|
77
|
-
elif exc_info is False:
|
78
|
-
exc_info = None
|
79
|
-
|
80
|
-
if exc_info is not None:
|
81
|
-
self.exc_info = exc_info
|
82
|
-
if isinstance(exc_info, BaseException):
|
83
|
-
self.exc_info_tuple = (type(exc_info), exc_info, exc_info.__traceback__)
|
84
|
-
else:
|
85
|
-
self.exc_info_tuple = exc_info
|
59
|
+
#
|
86
60
|
|
87
|
-
|
61
|
+
@ta.overload
|
62
|
+
def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
63
|
+
...
|
88
64
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
self._stack_offset = stack_offset
|
93
|
-
self._stack_info = stack_info
|
65
|
+
@ta.overload
|
66
|
+
def debug(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
67
|
+
...
|
94
68
|
|
95
|
-
|
69
|
+
@ta.overload
|
70
|
+
def debug(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
71
|
+
...
|
96
72
|
|
97
|
-
|
98
|
-
|
99
|
-
self.
|
100
|
-
self.asyncio_task = LoggingAsyncioTaskInfo.build()
|
73
|
+
@ta.final
|
74
|
+
def debug(self, *args, **kwargs):
|
75
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.DEBUG, stack_offset=1), *args, **kwargs)
|
101
76
|
|
102
77
|
#
|
103
78
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
def times(self) -> LoggingTimeFields:
|
108
|
-
try:
|
109
|
-
return self._times
|
110
|
-
except AttributeError:
|
111
|
-
pass
|
112
|
-
|
113
|
-
times = self._times = LoggingTimeFields.build(self.time_ns)
|
114
|
-
return times
|
115
|
-
|
116
|
-
#
|
79
|
+
@ta.overload
|
80
|
+
def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
81
|
+
...
|
117
82
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
return self
|
83
|
+
@ta.overload
|
84
|
+
def info(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
85
|
+
...
|
122
86
|
|
123
|
-
|
87
|
+
@ta.overload
|
88
|
+
def info(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
89
|
+
...
|
124
90
|
|
125
|
-
|
126
|
-
|
91
|
+
@ta.final
|
92
|
+
def info(self, *args, **kwargs):
|
93
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.INFO, stack_offset=1), *args, **kwargs)
|
127
94
|
|
128
|
-
|
129
|
-
return self._caller
|
130
|
-
except AttributeError:
|
131
|
-
pass
|
95
|
+
#
|
132
96
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
)
|
137
|
-
return caller
|
97
|
+
@ta.overload
|
98
|
+
def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
99
|
+
...
|
138
100
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
except AttributeError:
|
143
|
-
return None
|
101
|
+
@ta.overload
|
102
|
+
def warning(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
103
|
+
...
|
144
104
|
|
145
|
-
|
105
|
+
@ta.overload
|
106
|
+
def warning(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
107
|
+
...
|
146
108
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
except AttributeError:
|
151
|
-
pass
|
109
|
+
@ta.final
|
110
|
+
def warning(self, *args, **kwargs):
|
111
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.WARNING, stack_offset=1), *args, **kwargs)
|
152
112
|
|
153
|
-
|
154
|
-
return None
|
113
|
+
#
|
155
114
|
|
156
|
-
|
157
|
-
|
115
|
+
@ta.overload
|
116
|
+
def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
117
|
+
...
|
158
118
|
|
119
|
+
@ta.overload
|
120
|
+
def error(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
121
|
+
...
|
159
122
|
|
160
|
-
|
123
|
+
@ta.overload
|
124
|
+
def error(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
125
|
+
...
|
161
126
|
|
127
|
+
@ta.final
|
128
|
+
def error(self, *args, **kwargs):
|
129
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, stack_offset=1), *args, **kwargs)
|
162
130
|
|
163
|
-
|
164
|
-
def is_enabled_for(self, level: LogLevel) -> bool:
|
165
|
-
return self.get_effective_level() >= level
|
131
|
+
#
|
166
132
|
|
167
|
-
@
|
168
|
-
def
|
169
|
-
|
133
|
+
@ta.overload
|
134
|
+
def exception(self, msg: str, *args: ta.Any, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
135
|
+
...
|
170
136
|
|
171
|
-
|
137
|
+
@ta.overload
|
138
|
+
def exception(self, msg: ta.Tuple[ta.Any, ...], *, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
139
|
+
...
|
172
140
|
|
173
|
-
@ta.
|
174
|
-
def
|
175
|
-
|
141
|
+
@ta.overload
|
142
|
+
def exception(self, msg_fn: LoggingMsgFn, *, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
143
|
+
...
|
176
144
|
|
177
145
|
@ta.final
|
178
|
-
def
|
179
|
-
return self.
|
146
|
+
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
147
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, exc_info=exc_info, stack_offset=1), *args, **kwargs) # noqa
|
180
148
|
|
181
149
|
#
|
182
150
|
|
183
|
-
@ta.
|
184
|
-
def
|
185
|
-
|
151
|
+
@ta.overload
|
152
|
+
def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
153
|
+
...
|
186
154
|
|
187
|
-
@ta.
|
188
|
-
def
|
189
|
-
|
155
|
+
@ta.overload
|
156
|
+
def critical(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
157
|
+
...
|
190
158
|
|
191
|
-
@ta.
|
192
|
-
def
|
193
|
-
|
159
|
+
@ta.overload
|
160
|
+
def critical(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
161
|
+
...
|
194
162
|
|
195
163
|
@ta.final
|
196
|
-
def
|
197
|
-
return self._log(
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
164
|
+
def critical(self, *args, **kwargs):
|
165
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.CRITICAL, stack_offset=1), *args, **kwargs)
|
166
|
+
|
167
|
+
##
|
168
|
+
|
169
|
+
@classmethod
|
170
|
+
def _prepare_msg_args(cls, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> ta.Tuple[str, tuple]:
|
171
|
+
if callable(msg):
|
172
|
+
if args:
|
173
|
+
raise TypeError(f'Must not provide both a message function and args: {msg=} {args=}')
|
174
|
+
x = msg()
|
175
|
+
if isinstance(x, str):
|
176
|
+
return x, ()
|
177
|
+
elif isinstance(x, tuple):
|
178
|
+
if x:
|
179
|
+
return x[0], x[1:]
|
180
|
+
else:
|
181
|
+
return '', ()
|
182
|
+
else:
|
183
|
+
raise TypeError(x)
|
202
184
|
|
203
|
-
|
204
|
-
|
205
|
-
|
185
|
+
elif isinstance(msg, tuple):
|
186
|
+
if args:
|
187
|
+
raise TypeError(f'Must not provide both a tuple message and args: {msg=} {args=}')
|
188
|
+
if msg:
|
189
|
+
return msg[0], msg[1:]
|
190
|
+
else:
|
191
|
+
return '', ()
|
206
192
|
|
207
|
-
|
208
|
-
|
209
|
-
return self._log(LoggingContext(level, stack_offset=1), msg, *args, **kwargs)
|
193
|
+
elif isinstance(msg, str):
|
194
|
+
return msg, args
|
210
195
|
|
211
|
-
|
196
|
+
else:
|
197
|
+
raise TypeError(msg)
|
212
198
|
|
213
199
|
@abc.abstractmethod
|
214
|
-
def _log(self, ctx:
|
200
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> T: # noqa
|
215
201
|
raise NotImplementedError
|
216
202
|
|
217
203
|
|
218
204
|
class Logger(AnyLogger[None], Abstract):
|
219
205
|
@abc.abstractmethod
|
220
|
-
def _log(self, ctx:
|
206
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
221
207
|
raise NotImplementedError
|
222
208
|
|
223
209
|
|
224
210
|
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
225
211
|
@abc.abstractmethod
|
226
|
-
def _log(self, ctx:
|
212
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> ta.Awaitable[None]: # noqa
|
227
213
|
raise NotImplementedError
|
228
214
|
|
229
215
|
|
@@ -238,11 +224,11 @@ class AnyNopLogger(AnyLogger[T], Abstract):
|
|
238
224
|
|
239
225
|
@ta.final
|
240
226
|
class NopLogger(AnyNopLogger[None], Logger):
|
241
|
-
def _log(self, ctx:
|
227
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
242
228
|
pass
|
243
229
|
|
244
230
|
|
245
231
|
@ta.final
|
246
232
|
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
247
|
-
async def _log(self, ctx:
|
233
|
+
async def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
248
234
|
pass
|
omlish/logs/callers.py
CHANGED
@@ -7,11 +7,13 @@ import traceback
|
|
7
7
|
import types
|
8
8
|
import typing as ta
|
9
9
|
|
10
|
+
from .infos import LoggingContextInfo
|
11
|
+
|
10
12
|
|
11
13
|
##
|
12
14
|
|
13
15
|
|
14
|
-
class LoggingCaller(ta.NamedTuple):
|
16
|
+
class LoggingCaller(LoggingContextInfo, ta.NamedTuple): # type: ignore[misc]
|
15
17
|
file_path: str
|
16
18
|
line_no: int
|
17
19
|
name: str
|
@@ -57,8 +59,6 @@ class LoggingCaller(ta.NamedTuple):
|
|
57
59
|
sinfo = None
|
58
60
|
if stack_info:
|
59
61
|
sio = io.StringIO()
|
60
|
-
# In stdlib, but done elsewhere here:
|
61
|
-
# sio.write('Stack (most recent call last):\n')
|
62
62
|
traceback.print_stack(f, file=sio)
|
63
63
|
sinfo = sio.getvalue()
|
64
64
|
sio.close()
|
omlish/logs/contexts.py
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007 UP045 UP046
|
2
|
+
# @omlish-lite
|
3
|
+
import abc
|
4
|
+
import sys
|
5
|
+
import time
|
6
|
+
import types
|
7
|
+
import typing as ta
|
8
|
+
|
9
|
+
from ..lite.abstract import Abstract
|
10
|
+
from .callers import LoggingCaller
|
11
|
+
from .infos import LoggingAsyncioTaskInfo
|
12
|
+
from .infos import LoggingMultiprocessingInfo
|
13
|
+
from .infos import LoggingProcessInfo
|
14
|
+
from .infos import LoggingSourceFileInfo
|
15
|
+
from .infos import LoggingThreadInfo
|
16
|
+
from .levels import LogLevel
|
17
|
+
from .levels import NamedLogLevel
|
18
|
+
from .times import LoggingTimeFields
|
19
|
+
|
20
|
+
|
21
|
+
LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
|
22
|
+
LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
23
|
+
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
24
|
+
|
25
|
+
|
26
|
+
##
|
27
|
+
|
28
|
+
|
29
|
+
class LoggingContext(Abstract):
|
30
|
+
@property
|
31
|
+
@abc.abstractmethod
|
32
|
+
def level(self) -> NamedLogLevel:
|
33
|
+
raise NotImplementedError
|
34
|
+
|
35
|
+
#
|
36
|
+
|
37
|
+
@property
|
38
|
+
@abc.abstractmethod
|
39
|
+
def time_ns(self) -> int:
|
40
|
+
raise NotImplementedError
|
41
|
+
|
42
|
+
@property
|
43
|
+
@abc.abstractmethod
|
44
|
+
def times(self) -> LoggingTimeFields:
|
45
|
+
raise NotImplementedError
|
46
|
+
|
47
|
+
#
|
48
|
+
|
49
|
+
@property
|
50
|
+
@abc.abstractmethod
|
51
|
+
def exc_info(self) -> ta.Optional[LoggingExcInfo]:
|
52
|
+
raise NotImplementedError
|
53
|
+
|
54
|
+
@property
|
55
|
+
@abc.abstractmethod
|
56
|
+
def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
|
57
|
+
raise NotImplementedError
|
58
|
+
|
59
|
+
#
|
60
|
+
|
61
|
+
@abc.abstractmethod
|
62
|
+
def caller(self) -> ta.Optional[LoggingCaller]:
|
63
|
+
raise NotImplementedError
|
64
|
+
|
65
|
+
@abc.abstractmethod
|
66
|
+
def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
|
67
|
+
raise NotImplementedError
|
68
|
+
|
69
|
+
#
|
70
|
+
|
71
|
+
@abc.abstractmethod
|
72
|
+
def thread(self) -> ta.Optional[LoggingThreadInfo]:
|
73
|
+
raise NotImplementedError
|
74
|
+
|
75
|
+
@abc.abstractmethod
|
76
|
+
def process(self) -> ta.Optional[LoggingProcessInfo]:
|
77
|
+
raise NotImplementedError
|
78
|
+
|
79
|
+
@abc.abstractmethod
|
80
|
+
def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
|
81
|
+
raise NotImplementedError
|
82
|
+
|
83
|
+
@abc.abstractmethod
|
84
|
+
def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
|
85
|
+
raise NotImplementedError
|
86
|
+
|
87
|
+
|
88
|
+
##
|
89
|
+
|
90
|
+
|
91
|
+
class CaptureLoggingContext(LoggingContext, Abstract):
|
92
|
+
@abc.abstractmethod
|
93
|
+
def capture(self) -> None:
|
94
|
+
"""Must be cooperatively called only from the expected locations."""
|
95
|
+
|
96
|
+
raise NotImplementedError
|
97
|
+
|
98
|
+
|
99
|
+
@ta.final
|
100
|
+
class CaptureLoggingContextImpl(CaptureLoggingContext):
|
101
|
+
@ta.final
|
102
|
+
class NOT_SET: # noqa
|
103
|
+
def __new__(cls, *args, **kwargs): # noqa
|
104
|
+
raise TypeError
|
105
|
+
|
106
|
+
#
|
107
|
+
|
108
|
+
def __init__(
|
109
|
+
self,
|
110
|
+
level: LogLevel,
|
111
|
+
*,
|
112
|
+
time_ns: ta.Optional[int] = None,
|
113
|
+
|
114
|
+
exc_info: LoggingExcInfoArg = False,
|
115
|
+
|
116
|
+
caller: ta.Union[LoggingCaller, ta.Type[NOT_SET], None] = NOT_SET,
|
117
|
+
stack_offset: int = 0,
|
118
|
+
stack_info: bool = False,
|
119
|
+
) -> None:
|
120
|
+
self._level: NamedLogLevel = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment] # noqa
|
121
|
+
|
122
|
+
#
|
123
|
+
|
124
|
+
if time_ns is None:
|
125
|
+
time_ns = time.time_ns()
|
126
|
+
self._time_ns: int = time_ns
|
127
|
+
|
128
|
+
#
|
129
|
+
|
130
|
+
if exc_info is True:
|
131
|
+
sys_exc_info = sys.exc_info()
|
132
|
+
if sys_exc_info[0] is not None:
|
133
|
+
exc_info = sys_exc_info
|
134
|
+
else:
|
135
|
+
exc_info = None
|
136
|
+
elif exc_info is False:
|
137
|
+
exc_info = None
|
138
|
+
|
139
|
+
if exc_info is not None:
|
140
|
+
self._exc_info: ta.Optional[LoggingExcInfo] = exc_info
|
141
|
+
if isinstance(exc_info, BaseException):
|
142
|
+
self._exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = (type(exc_info), exc_info, exc_info.__traceback__) # noqa
|
143
|
+
else:
|
144
|
+
self._exc_info_tuple = exc_info
|
145
|
+
else:
|
146
|
+
self._exc_info = None
|
147
|
+
self._exc_info_tuple = None
|
148
|
+
|
149
|
+
#
|
150
|
+
|
151
|
+
if caller is not CaptureLoggingContextImpl.NOT_SET:
|
152
|
+
self._caller = caller # type: ignore[assignment]
|
153
|
+
else:
|
154
|
+
self._stack_offset = stack_offset
|
155
|
+
self._stack_info = stack_info
|
156
|
+
|
157
|
+
#
|
158
|
+
|
159
|
+
self._thread = LoggingThreadInfo.build()
|
160
|
+
self._process = LoggingProcessInfo.build()
|
161
|
+
self._multiprocessing = LoggingMultiprocessingInfo.build()
|
162
|
+
self._asyncio_task = LoggingAsyncioTaskInfo.build()
|
163
|
+
|
164
|
+
#
|
165
|
+
|
166
|
+
@property
|
167
|
+
def level(self) -> NamedLogLevel:
|
168
|
+
return self._level
|
169
|
+
|
170
|
+
#
|
171
|
+
|
172
|
+
@property
|
173
|
+
def time_ns(self) -> int:
|
174
|
+
return self._time_ns
|
175
|
+
|
176
|
+
_times: LoggingTimeFields
|
177
|
+
|
178
|
+
@property
|
179
|
+
def times(self) -> LoggingTimeFields:
|
180
|
+
try:
|
181
|
+
return self._times
|
182
|
+
except AttributeError:
|
183
|
+
pass
|
184
|
+
|
185
|
+
times = self._times = LoggingTimeFields.build(self.time_ns)
|
186
|
+
return times
|
187
|
+
|
188
|
+
@property
|
189
|
+
def exc_info(self) -> ta.Optional[LoggingExcInfo]:
|
190
|
+
return self._exc_info
|
191
|
+
|
192
|
+
@property
|
193
|
+
def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
|
194
|
+
return self._exc_info_tuple
|
195
|
+
|
196
|
+
#
|
197
|
+
|
198
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'LoggingContext':
|
199
|
+
if hasattr(self, '_stack_offset'):
|
200
|
+
self._stack_offset += ofs
|
201
|
+
return self
|
202
|
+
|
203
|
+
_caller: ta.Optional[LoggingCaller]
|
204
|
+
|
205
|
+
def capture(self) -> None:
|
206
|
+
"""Must be cooperatively called only from the exact configured _stack_offset."""
|
207
|
+
|
208
|
+
try:
|
209
|
+
self._caller # noqa
|
210
|
+
except AttributeError:
|
211
|
+
pass
|
212
|
+
|
213
|
+
self._caller = LoggingCaller.find(
|
214
|
+
self._stack_offset + 1,
|
215
|
+
stack_info=self._stack_info,
|
216
|
+
)
|
217
|
+
|
218
|
+
def caller(self) -> ta.Optional[LoggingCaller]:
|
219
|
+
try:
|
220
|
+
return self._caller
|
221
|
+
except AttributeError:
|
222
|
+
return None
|
223
|
+
|
224
|
+
_source_file: ta.Optional[LoggingSourceFileInfo]
|
225
|
+
|
226
|
+
def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
|
227
|
+
try:
|
228
|
+
return self._source_file
|
229
|
+
except AttributeError:
|
230
|
+
pass
|
231
|
+
|
232
|
+
if (caller := self.caller()) is None:
|
233
|
+
return None
|
234
|
+
|
235
|
+
src_file = self._source_file = LoggingSourceFileInfo.build(caller.file_path)
|
236
|
+
return src_file
|
237
|
+
|
238
|
+
#
|
239
|
+
|
240
|
+
def thread(self) -> ta.Optional[LoggingThreadInfo]:
|
241
|
+
return self._thread
|
242
|
+
|
243
|
+
def process(self) -> ta.Optional[LoggingProcessInfo]:
|
244
|
+
return self._process
|
245
|
+
|
246
|
+
def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
|
247
|
+
return self._multiprocessing
|
248
|
+
|
249
|
+
def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
|
250
|
+
return self._asyncio_task
|