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
@@ -0,0 +1,286 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007 UP045
|
2
|
+
# @omlish-lite
|
3
|
+
import collections.abc
|
4
|
+
import logging
|
5
|
+
import sys
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
from ..base import LoggingContext
|
9
|
+
from ..base import LoggingExcInfoTuple
|
10
|
+
from ..warnings import LoggingSetupWarning
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
|
15
|
+
|
16
|
+
# Ref:
|
17
|
+
# - https://docs.python.org/3/library/logging.html#logrecord-attributes
|
18
|
+
#
|
19
|
+
# LogRecord:
|
20
|
+
# - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L276 (3.8)
|
21
|
+
# - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L286 (~3.14) # noqa
|
22
|
+
#
|
23
|
+
# LogRecord.__init__ args:
|
24
|
+
# - name: str
|
25
|
+
# - level: int
|
26
|
+
# - pathname: str - Confusingly referred to as `fn` before the LogRecord ctor. May be empty or "(unknown file)".
|
27
|
+
# - lineno: int - May be 0.
|
28
|
+
# - msg: str
|
29
|
+
# - args: tuple | dict | 1-tuple[dict]
|
30
|
+
# - exc_info: LoggingExcInfoTuple | None
|
31
|
+
# - func: str | None = None -> funcName
|
32
|
+
# - sinfo: str | None = None -> stack_info
|
33
|
+
#
|
34
|
+
KNOWN_STD_LOGGING_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
|
35
|
+
# Name of the logger used to log the call. Unmodified by ctor.
|
36
|
+
name=str,
|
37
|
+
|
38
|
+
# The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object
|
39
|
+
# (see Using arbitrary objects as messages). Unmodified by ctor.
|
40
|
+
msg=str,
|
41
|
+
|
42
|
+
# The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when
|
43
|
+
# there is only one argument, and it is a dictionary). Ctor will transform a 1-tuple containing a Mapping into just
|
44
|
+
# the mapping, but is otherwise unmodified.
|
45
|
+
args=ta.Union[tuple, dict],
|
46
|
+
|
47
|
+
#
|
48
|
+
|
49
|
+
# Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'). Set to
|
50
|
+
# `getLevelName(level)`.
|
51
|
+
levelname=str,
|
52
|
+
|
53
|
+
# Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL). Unmodified by ctor.
|
54
|
+
levelno=int,
|
55
|
+
|
56
|
+
#
|
57
|
+
|
58
|
+
# Full pathname of the source file where the logging call was issued (if available). Unmodified by ctor. May default
|
59
|
+
# to "(unknown file)" by Logger.findCaller / Logger._log.
|
60
|
+
pathname=str,
|
61
|
+
|
62
|
+
# Filename portion of pathname. Set to `os.path.basename(pathname)` if successful, otherwise defaults to pathname.
|
63
|
+
filename=str,
|
64
|
+
|
65
|
+
# Module (name portion of filename). Set to `os.path.splitext(filename)[0]`, otherwise defaults to
|
66
|
+
# "Unknown module".
|
67
|
+
module=str,
|
68
|
+
|
69
|
+
#
|
70
|
+
|
71
|
+
# Exception tuple (à la sys.exc_info) or, if no exception has occurred, None. Unmodified by ctor.
|
72
|
+
exc_info=ta.Optional[LoggingExcInfoTuple],
|
73
|
+
|
74
|
+
# Used to cache the traceback text. Simply set to None by ctor, later set by Formatter.format.
|
75
|
+
exc_text=ta.Optional[str],
|
76
|
+
|
77
|
+
#
|
78
|
+
|
79
|
+
# Stack frame information (where available) from the bottom of the stack in the current thread, up to and including
|
80
|
+
# the stack frame of the logging call which resulted in the creation of this record. Set by ctor to `sinfo` arg,
|
81
|
+
# unmodified. Mostly set, if requested, by `Logger.findCaller`, to `traceback.print_stack(f)`, but prepended with
|
82
|
+
# the literal "Stack (most recent call last):\n", and stripped of exactly one trailing `\n` if present.
|
83
|
+
stack_info=ta.Optional[str],
|
84
|
+
|
85
|
+
# Source line number where the logging call was issued (if available). Unmodified by ctor. May default to 0 by
|
86
|
+
# Logger.findCaller / Logger._log.
|
87
|
+
lineno=int,
|
88
|
+
|
89
|
+
# Name of function containing the logging call. Set by ctor to `func` arg, unmodified. May default to
|
90
|
+
# "(unknown function)" by Logger.findCaller / Logger._log.
|
91
|
+
funcName=str,
|
92
|
+
|
93
|
+
#
|
94
|
+
|
95
|
+
# Time when the LogRecord was created. Set to `time.time_ns() / 1e9` for >=3.13.0b1, otherwise simply `time.time()`.
|
96
|
+
#
|
97
|
+
# See:
|
98
|
+
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
99
|
+
# - https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
100
|
+
#
|
101
|
+
created=float,
|
102
|
+
|
103
|
+
# Millisecond portion of the time when the LogRecord was created.
|
104
|
+
msecs=float,
|
105
|
+
|
106
|
+
# Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
|
107
|
+
relativeCreated=float,
|
108
|
+
|
109
|
+
#
|
110
|
+
|
111
|
+
# Thread ID if available, and `logging.logThreads` is truthy.
|
112
|
+
thread=ta.Optional[int],
|
113
|
+
|
114
|
+
# Thread name if available, and `logging.logThreads` is truthy.
|
115
|
+
threadName=ta.Optional[str],
|
116
|
+
|
117
|
+
#
|
118
|
+
|
119
|
+
# Process name if available. Set to None if `logging.logMultiprocessing` is not truthy. Otherwise, set to
|
120
|
+
# 'MainProcess', then `sys.modules.get('multiprocessing').current_process().name` if that works, otherwise remains
|
121
|
+
# as 'MainProcess'.
|
122
|
+
#
|
123
|
+
# As noted by stdlib:
|
124
|
+
#
|
125
|
+
# Errors may occur if multiprocessing has not finished loading yet - e.g. if a custom import hook causes
|
126
|
+
# third-party code to run when multiprocessing calls import. See issue 8200 for an example
|
127
|
+
#
|
128
|
+
processName=ta.Optional[str],
|
129
|
+
|
130
|
+
# Process ID if available - that is, if `hasattr(os, 'getpid')` - and `logging.logProcesses` is truthy, otherwise
|
131
|
+
# None.
|
132
|
+
process=ta.Optional[int],
|
133
|
+
|
134
|
+
#
|
135
|
+
|
136
|
+
# Absent <3.12, otherwise asyncio.Task name if available, and `logging.logAsyncioTasks` is truthy. Set to
|
137
|
+
# `sys.modules.get('asyncio').current_task().get_name()`, otherwise None.
|
138
|
+
taskName=ta.Optional[str],
|
139
|
+
)
|
140
|
+
|
141
|
+
KNOWN_STD_LOGGING_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(KNOWN_STD_LOGGING_RECORD_ATTRS)
|
142
|
+
|
143
|
+
|
144
|
+
# Formatter:
|
145
|
+
# - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L514 (3.8)
|
146
|
+
# - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L554 (~3.14) # noqa
|
147
|
+
#
|
148
|
+
KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
|
149
|
+
# The logged message, computed as msg % args. Set to `record.getMessage()`.
|
150
|
+
message=str,
|
151
|
+
|
152
|
+
# Human-readable time when the LogRecord was created. By default this is of the form '2003-07-08 16:49:45,896' (the
|
153
|
+
# numbers after the comma are millisecond portion of the time). Set to `self.formatTime(record, self.datefmt)` if
|
154
|
+
# `self.usesTime()`, otherwise unset.
|
155
|
+
asctime=str,
|
156
|
+
|
157
|
+
# Used to cache the traceback text. If unset (falsey) on the record and `exc_info` is truthy, set to
|
158
|
+
# `self.formatException(record.exc_info)` - otherwise unmodified.
|
159
|
+
exc_text=ta.Optional[str],
|
160
|
+
)
|
161
|
+
|
162
|
+
KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS)
|
163
|
+
|
164
|
+
|
165
|
+
##
|
166
|
+
|
167
|
+
|
168
|
+
class UnknownStdLoggingRecordAttrsWarning(LoggingSetupWarning):
|
169
|
+
pass
|
170
|
+
|
171
|
+
|
172
|
+
def _check_std_logging_record_attrs() -> None:
|
173
|
+
rec_dct = dict(logging.makeLogRecord({}).__dict__)
|
174
|
+
|
175
|
+
if (unk_rec_fields := frozenset(rec_dct) - KNOWN_STD_LOGGING_RECORD_ATTR_SET):
|
176
|
+
import warnings # noqa
|
177
|
+
|
178
|
+
warnings.warn(
|
179
|
+
f'Unknown log record attrs detected: {sorted(unk_rec_fields)!r}',
|
180
|
+
UnknownStdLoggingRecordAttrsWarning,
|
181
|
+
)
|
182
|
+
|
183
|
+
|
184
|
+
_check_std_logging_record_attrs()
|
185
|
+
|
186
|
+
|
187
|
+
##
|
188
|
+
|
189
|
+
|
190
|
+
class LoggingContextLogRecord(logging.LogRecord):
|
191
|
+
_SHOULD_ADD_TASK_NAME: ta.ClassVar[bool] = sys.version_info >= (3, 12)
|
192
|
+
|
193
|
+
_UNKNOWN_PATH_NAME: ta.ClassVar[str] = '(unknown file)'
|
194
|
+
_UNKNOWN_FUNC_NAME: ta.ClassVar[str] = '(unknown function)'
|
195
|
+
_UNKNOWN_MODULE: ta.ClassVar[str] = 'Unknown module'
|
196
|
+
|
197
|
+
_STACK_INFO_PREFIX: ta.ClassVar[str] = 'Stack (most recent call last):\n'
|
198
|
+
|
199
|
+
def __init__( # noqa
|
200
|
+
self,
|
201
|
+
# name,
|
202
|
+
# level,
|
203
|
+
# pathname,
|
204
|
+
# lineno,
|
205
|
+
# msg,
|
206
|
+
# args,
|
207
|
+
# exc_info,
|
208
|
+
# func=None,
|
209
|
+
# sinfo=None,
|
210
|
+
# **kwargs,
|
211
|
+
*,
|
212
|
+
name: str,
|
213
|
+
msg: str,
|
214
|
+
args: ta.Union[tuple, dict],
|
215
|
+
|
216
|
+
_logging_context: LoggingContext,
|
217
|
+
) -> None:
|
218
|
+
ctx = _logging_context
|
219
|
+
|
220
|
+
self.name: str = name
|
221
|
+
|
222
|
+
self.msg: str = msg
|
223
|
+
|
224
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L307
|
225
|
+
if args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping) and args[0]:
|
226
|
+
args = args[0] # type: ignore[assignment]
|
227
|
+
self.args: ta.Union[tuple, dict] = args
|
228
|
+
|
229
|
+
self.levelname: str = logging.getLevelName(ctx.level)
|
230
|
+
self.levelno: int = ctx.level
|
231
|
+
|
232
|
+
if (caller := ctx.caller()) is not None:
|
233
|
+
self.pathname: str = caller.file_path
|
234
|
+
else:
|
235
|
+
self.pathname = self._UNKNOWN_PATH_NAME
|
236
|
+
|
237
|
+
if (src_file := ctx.source_file()) is not None:
|
238
|
+
self.filename: str = src_file.file_name
|
239
|
+
self.module: str = src_file.module
|
240
|
+
else:
|
241
|
+
self.filename = self.pathname
|
242
|
+
self.module = self._UNKNOWN_MODULE
|
243
|
+
|
244
|
+
self.exc_info: ta.Optional[LoggingExcInfoTuple] = ctx.exc_info_tuple
|
245
|
+
self.exc_text: ta.Optional[str] = None
|
246
|
+
|
247
|
+
# If ctx.build_caller() was never called, we simply don't have a stack trace.
|
248
|
+
if caller is not None:
|
249
|
+
if (sinfo := caller.stack_info) is not None:
|
250
|
+
self.stack_info: ta.Optional[str] = '\n'.join([
|
251
|
+
self._STACK_INFO_PREFIX,
|
252
|
+
sinfo[1:] if sinfo.endswith('\n') else sinfo,
|
253
|
+
])
|
254
|
+
else:
|
255
|
+
self.stack_info = None
|
256
|
+
|
257
|
+
self.lineno: int = caller.line_no
|
258
|
+
self.funcName: str = caller.name
|
259
|
+
|
260
|
+
else:
|
261
|
+
self.stack_info = None
|
262
|
+
|
263
|
+
self.lineno = 0
|
264
|
+
self.funcName = self._UNKNOWN_FUNC_NAME
|
265
|
+
|
266
|
+
times = ctx.times
|
267
|
+
self.created: float = times.created
|
268
|
+
self.msecs: float = times.msecs
|
269
|
+
self.relativeCreated: float = times.relative_created
|
270
|
+
|
271
|
+
thread = ctx.thread
|
272
|
+
self.thread: ta.Optional[int] = thread.ident
|
273
|
+
self.threadName: ta.Optional[str] = thread.name
|
274
|
+
|
275
|
+
process = ctx.process
|
276
|
+
self.process: ta.Optional[int] = process.pid
|
277
|
+
|
278
|
+
if (mp := ctx.multiprocessing) is not None:
|
279
|
+
self.processName: ta.Optional[str] = mp.process_name
|
280
|
+
else:
|
281
|
+
self.processName = None
|
282
|
+
|
283
|
+
if (at := ctx.asyncio_task) is not None:
|
284
|
+
self.taskName: ta.Optional[str] = at.name
|
285
|
+
else:
|
286
|
+
self.taskName = None
|
omlish/logs/times.py
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# ruff: noqa: UP045
|
2
|
+
# @omlish-lite
|
3
|
+
import logging
|
4
|
+
import time
|
5
|
+
import typing as ta
|
6
|
+
|
7
|
+
from .warnings import LoggingSetupWarning
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
class LoggingTimeFields(ta.NamedTuple):
|
14
|
+
"""Maps directly to stdlib `logging.LogRecord` fields, and must be kept in sync with it."""
|
15
|
+
|
16
|
+
created: float
|
17
|
+
msecs: float
|
18
|
+
relative_created: float
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def get_std_start_time_ns(cls) -> int:
|
22
|
+
x: ta.Any = logging._startTime # type: ignore[attr-defined] # noqa
|
23
|
+
|
24
|
+
# Before 3.13.0b1 this will be `time.time()`, a float of seconds. After that, it will be `time.time_ns()`, an
|
25
|
+
# int.
|
26
|
+
#
|
27
|
+
# See:
|
28
|
+
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
29
|
+
#
|
30
|
+
if isinstance(x, float):
|
31
|
+
return int(x * 1e9)
|
32
|
+
else:
|
33
|
+
return x
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def build(
|
37
|
+
cls,
|
38
|
+
time_ns: int,
|
39
|
+
*,
|
40
|
+
start_time_ns: ta.Optional[int] = None,
|
41
|
+
) -> 'LoggingTimeFields':
|
42
|
+
# https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
43
|
+
created = time_ns / 1e9 # ns to float seconds
|
44
|
+
|
45
|
+
# Get the number of whole milliseconds (0-999) in the fractional part of seconds.
|
46
|
+
# Eg: 1_677_903_920_999_998_503 ns --> 999_998_503 ns--> 999 ms
|
47
|
+
# Convert to float by adding 0.0 for historical reasons. See gh-89047
|
48
|
+
msecs = (time_ns % 1_000_000_000) // 1_000_000 + 0.0
|
49
|
+
|
50
|
+
# https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
51
|
+
if msecs == 999.0 and int(created) != time_ns // 1_000_000_000:
|
52
|
+
# ns -> sec conversion can round up, e.g:
|
53
|
+
# 1_677_903_920_999_999_900 ns --> 1_677_903_921.0 sec
|
54
|
+
msecs = 0.0
|
55
|
+
|
56
|
+
if start_time_ns is None:
|
57
|
+
start_time_ns = cls.get_std_start_time_ns()
|
58
|
+
relative_created = (time_ns - start_time_ns) / 1e6
|
59
|
+
|
60
|
+
return cls(
|
61
|
+
created,
|
62
|
+
msecs,
|
63
|
+
relative_created,
|
64
|
+
)
|
65
|
+
|
66
|
+
|
67
|
+
##
|
68
|
+
|
69
|
+
|
70
|
+
class UnexpectedLoggingStartTimeWarning(LoggingSetupWarning):
|
71
|
+
pass
|
72
|
+
|
73
|
+
|
74
|
+
def _check_logging_start_time() -> None:
|
75
|
+
x = LoggingTimeFields.get_std_start_time_ns()
|
76
|
+
ns = time.time_ns()
|
77
|
+
|
78
|
+
if x > ns:
|
79
|
+
import warnings # noqa
|
80
|
+
|
81
|
+
warnings.warn(
|
82
|
+
f'Unexpected logging start time detected: '
|
83
|
+
f'get_std_start_time_ns={x}, '
|
84
|
+
f'time.time_ns()={ns}',
|
85
|
+
UnexpectedLoggingStartTimeWarning,
|
86
|
+
)
|
87
|
+
|
88
|
+
|
89
|
+
_check_logging_start_time()
|
omlish/logs/typed/bindings.py
CHANGED
@@ -448,6 +448,30 @@ _AS_TYPED_LOGGER_BINDINGS_FIELD_VALUE_DIRECT_TYPES: ta.Tuple[type, ...] = (
|
|
448
448
|
)
|
449
449
|
|
450
450
|
|
451
|
+
# @ta.final
|
452
|
+
# class TypedLoggerBindingsBuilder:
|
453
|
+
# def __init__(
|
454
|
+
# self,
|
455
|
+
# *,
|
456
|
+
# add_default_keys: bool = False,
|
457
|
+
# default_key_filter: ta.Optional[ta.Callable[[str], bool]] = None,
|
458
|
+
#
|
459
|
+
# add_default_values: bool = False,
|
460
|
+
# default_value_filter: ta.Optional[ta.Callable[[ta.Type[DefaultTypedLoggerValue]], bool]] = None,
|
461
|
+
#
|
462
|
+
# value_wrapper: ta.Optional[TypedLoggerValueWrapperFn] = None,
|
463
|
+
# ) -> None:
|
464
|
+
# self._add_default_keys = add_default_keys
|
465
|
+
# self._default_key_filter = default_key_filter
|
466
|
+
#
|
467
|
+
# self._add_default_values = add_default_values
|
468
|
+
# self._default_value_filter = default_value_filter
|
469
|
+
#
|
470
|
+
# self._value_wrapper = value_wrapper
|
471
|
+
#
|
472
|
+
# self._lst: ta.List[TypedLoggerBindingItem] = []
|
473
|
+
|
474
|
+
|
451
475
|
def as_typed_logger_bindings(
|
452
476
|
*objs: CanTypedLoggerBinding,
|
453
477
|
|
omlish/logs/utils.py
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007 UP045
|
2
|
+
# @omlish-lite
|
1
3
|
import functools
|
2
4
|
import logging
|
5
|
+
import time
|
6
|
+
import typing as ta
|
3
7
|
|
4
|
-
|
5
|
-
##
|
8
|
+
from .protocols import LoggerLike
|
6
9
|
|
7
10
|
|
8
|
-
|
11
|
+
##
|
9
12
|
|
10
13
|
|
11
|
-
def error_logging(log
|
14
|
+
def error_logging(log): # noqa
|
12
15
|
def outer(fn):
|
13
16
|
@functools.wraps(fn)
|
14
17
|
def inner(*args, **kwargs):
|
@@ -21,3 +24,56 @@ def error_logging(log=_log): # noqa
|
|
21
24
|
return inner
|
22
25
|
|
23
26
|
return outer
|
27
|
+
|
28
|
+
|
29
|
+
##
|
30
|
+
|
31
|
+
|
32
|
+
class LogTimingContext:
|
33
|
+
DEFAULT_LOG: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
34
|
+
|
35
|
+
class _NOT_SPECIFIED: # noqa
|
36
|
+
def __new__(cls, *args, **kwargs): # noqa
|
37
|
+
raise TypeError
|
38
|
+
|
39
|
+
def __init__(
|
40
|
+
self,
|
41
|
+
description: str,
|
42
|
+
*,
|
43
|
+
log: ta.Union[LoggerLike, ta.Type[_NOT_SPECIFIED], None] = _NOT_SPECIFIED, # noqa
|
44
|
+
level: int = logging.DEBUG,
|
45
|
+
) -> None:
|
46
|
+
super().__init__()
|
47
|
+
|
48
|
+
self._description = description
|
49
|
+
if log is self._NOT_SPECIFIED:
|
50
|
+
log = self.DEFAULT_LOG # noqa
|
51
|
+
self._log: ta.Optional[LoggerLike] = log # type: ignore
|
52
|
+
self._level = level
|
53
|
+
|
54
|
+
def set_description(self, description: str) -> 'LogTimingContext':
|
55
|
+
self._description = description
|
56
|
+
return self
|
57
|
+
|
58
|
+
_begin_time: float
|
59
|
+
_end_time: float
|
60
|
+
|
61
|
+
def __enter__(self) -> 'LogTimingContext':
|
62
|
+
self._begin_time = time.time()
|
63
|
+
|
64
|
+
if self._log is not None:
|
65
|
+
self._log.log(self._level, f'Begin : {self._description}') # noqa
|
66
|
+
|
67
|
+
return self
|
68
|
+
|
69
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
70
|
+
self._end_time = time.time()
|
71
|
+
|
72
|
+
if self._log is not None:
|
73
|
+
self._log.log(
|
74
|
+
self._level,
|
75
|
+
f'End : {self._description} - {self._end_time - self._begin_time:0.2f} s elapsed',
|
76
|
+
)
|
77
|
+
|
78
|
+
|
79
|
+
log_timing_context = LogTimingContext
|
omlish/logs/warnings.py
ADDED
omlish/manifests/loading.py
CHANGED
@@ -432,7 +432,7 @@ class ManifestLoader:
|
|
432
432
|
return None
|
433
433
|
return t.read_text('utf-8')
|
434
434
|
|
435
|
-
MANIFESTS_FILE_NAME: ta.ClassVar[str] = '.manifests.json'
|
435
|
+
MANIFESTS_FILE_NAME: ta.ClassVar[str] = '.omlish-manifests.json'
|
436
436
|
|
437
437
|
@classmethod
|
438
438
|
def _read_package_raw_manifests(cls, package_name: str) -> ta.Optional[ta.Sequence[Manifest]]:
|
omlish/os/journald.py
CHANGED
@@ -79,7 +79,7 @@ SD_LOG_LEVEL_MAP: ta.Mapping[int, int] = {
|
|
79
79
|
}
|
80
80
|
|
81
81
|
|
82
|
-
class
|
82
|
+
class JournaldLoggingHandler(logging.Handler):
|
83
83
|
"""
|
84
84
|
TODO:
|
85
85
|
- fallback handler for when this barfs
|
@@ -148,7 +148,7 @@ class JournaldLogHandler(logging.Handler):
|
|
148
148
|
self.handleError(record)
|
149
149
|
|
150
150
|
|
151
|
-
def
|
151
|
+
def journald_logging_handler_factory(
|
152
152
|
*,
|
153
153
|
no_tty_check: bool = False,
|
154
154
|
no_fallback: bool = False,
|
@@ -158,6 +158,6 @@ def journald_log_handler_factory(
|
|
158
158
|
(no_tty_check or not sys.stderr.isatty()) and
|
159
159
|
(no_fallback or sd_try_libsystemd() is not None)
|
160
160
|
):
|
161
|
-
return
|
161
|
+
return JournaldLoggingHandler()
|
162
162
|
|
163
163
|
return logging.StreamHandler()
|