Compare commits
No commits in common. "3a45dbd5039aa4559ea38293952415332b795ac9" and "f595acc76c696317255fca9861d1940603f8d93b" have entirely different histories.
3a45dbd503
...
f595acc76c
|
|
@ -162,66 +162,6 @@ def test_implicit_mod_name_applied_for_child(
|
||||||
assert submod.log.logger in sub_logs
|
assert submod.log.logger in sub_logs
|
||||||
|
|
||||||
|
|
||||||
def test_io_custom_level_registered():
|
|
||||||
'''
|
|
||||||
The `IO`(21) level (registered via `add_log_level()` at
|
|
||||||
import, for `tractor.trionics._subproc`'s std-stream relay)
|
|
||||||
is fully wired and SHOWN BY DEFAULT at `info`-level consoles
|
|
||||||
since `21 >= INFO(20)`.
|
|
||||||
|
|
||||||
'''
|
|
||||||
import logging
|
|
||||||
assert log.CUSTOM_LEVELS.get('IO') == 21
|
|
||||||
assert logging.getLevelName(21) == 'IO'
|
|
||||||
assert log.STD_PALETTE.get('IO')
|
|
||||||
assert log.BOLD_PALETTE['bold'].get('IO')
|
|
||||||
|
|
||||||
iolog = log.get_logger('io_lvl_test')
|
|
||||||
assert callable(getattr(iolog, 'io', None))
|
|
||||||
# emit must not raise
|
|
||||||
iolog.io('hello from the IO level')
|
|
||||||
|
|
||||||
# 21 >= INFO(20) -> shown when console set to `info`
|
|
||||||
assert 21 >= logging.INFO
|
|
||||||
|
|
||||||
|
|
||||||
def test_add_log_level_pluggable():
|
|
||||||
'''
|
|
||||||
`add_log_level()` is the single pluggable entry-point: one
|
|
||||||
call wires `CUSTOM_LEVELS` + `addLevelName` + both palettes +
|
|
||||||
a same-named `StackLevelAdapter` emit method (so
|
|
||||||
`get_logger()`'s per-level audit passes).
|
|
||||||
|
|
||||||
'''
|
|
||||||
import logging
|
|
||||||
name: str = 'XLVL'
|
|
||||||
val: int = 19
|
|
||||||
try:
|
|
||||||
log.add_log_level(name, val, 'cyan')
|
|
||||||
|
|
||||||
assert log.CUSTOM_LEVELS[name] == val
|
|
||||||
assert logging.getLevelName(val) == name
|
|
||||||
assert log.STD_PALETTE[name] == 'cyan'
|
|
||||||
assert log.BOLD_PALETTE['bold'][name] == 'bold_cyan'
|
|
||||||
|
|
||||||
# the audit in `get_logger()` (asserts a method per
|
|
||||||
# `CUSTOM_LEVELS` entry) must still pass.
|
|
||||||
xlog = log.get_logger('xlvl_test')
|
|
||||||
emit = getattr(xlog, name.lower(), None)
|
|
||||||
assert callable(emit)
|
|
||||||
emit('hello from a plugged-in level')
|
|
||||||
|
|
||||||
finally:
|
|
||||||
# best-effort cleanup of our module-global mutations so
|
|
||||||
# later `get_logger()` audits don't see a half-removed
|
|
||||||
# level.
|
|
||||||
log.CUSTOM_LEVELS.pop(name, None)
|
|
||||||
log.STD_PALETTE.pop(name, None)
|
|
||||||
log.BOLD_PALETTE['bold'].pop(name, None)
|
|
||||||
if hasattr(log.StackLevelAdapter, name.lower()):
|
|
||||||
delattr(log.StackLevelAdapter, name.lower())
|
|
||||||
|
|
||||||
|
|
||||||
# TODO, moar tests against existing feats:
|
# TODO, moar tests against existing feats:
|
||||||
# ------ - ------
|
# ------ - ------
|
||||||
# - [ ] color settings?
|
# - [ ] color settings?
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ keys are caller-defined).
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
|
|
@ -98,9 +99,6 @@ import stat
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
from tractor.devx import _proctitle
|
|
||||||
|
|
||||||
# `/dev/shm` is the POSIX-shm filesystem on Linux + FreeBSD.
|
# `/dev/shm` is the POSIX-shm filesystem on Linux + FreeBSD.
|
||||||
# macOS uses `shm_open` syscalls without a fs-visible path,
|
# macOS uses `shm_open` syscalls without a fs-visible path,
|
||||||
# so the shm helpers refuse to run there.
|
# so the shm helpers refuse to run there.
|
||||||
|
|
@ -232,9 +230,9 @@ def _read_comm(pid: int) -> str:
|
||||||
# while `cmdline` for zombies often reads as empty.
|
# while `cmdline` for zombies often reads as empty.
|
||||||
_TRACTOR_PROC_CMDLINE_MARKERS: tuple[str, ...] = (
|
_TRACTOR_PROC_CMDLINE_MARKERS: tuple[str, ...] = (
|
||||||
'tractor._child',
|
'tractor._child',
|
||||||
_proctitle._def_prefix,
|
'tractor[',
|
||||||
)
|
)
|
||||||
_TRACTOR_PROC_COMM_MARKER: str = _proctitle._def_prefix
|
_TRACTOR_PROC_COMM_MARKER: str = 'tractor['
|
||||||
|
|
||||||
|
|
||||||
def _is_tractor_subactor(pid: int) -> bool:
|
def _is_tractor_subactor(pid: int) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,7 @@ except ImportError:
|
||||||
_stp = None
|
_stp = None
|
||||||
|
|
||||||
|
|
||||||
_def_prefix: str = '_subactor'
|
def set_actor_proctitle(actor: 'Actor') -> str | None:
|
||||||
|
|
||||||
|
|
||||||
def set_actor_proctitle(
|
|
||||||
actor: 'Actor',
|
|
||||||
prefix: str = _def_prefix,
|
|
||||||
) -> str | None:
|
|
||||||
'''
|
'''
|
||||||
Set the calling process's proc-title to identify it as a
|
Set the calling process's proc-title to identify it as a
|
||||||
tractor sub-actor.
|
tractor sub-actor.
|
||||||
|
|
@ -75,6 +69,6 @@ def set_actor_proctitle(
|
||||||
if _stp is None:
|
if _stp is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
title: str = f'{prefix}[{actor.aid.reprol()}]'
|
title: str = f'tractor[{actor.aid.reprol()}]'
|
||||||
_stp.setproctitle(title)
|
_stp.setproctitle(title)
|
||||||
return title
|
return title
|
||||||
|
|
|
||||||
|
|
@ -262,63 +262,6 @@ class StackLevelAdapter(LoggerAdapter):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_log_level(
|
|
||||||
name: str,
|
|
||||||
value: int,
|
|
||||||
color: str = 'white',
|
|
||||||
) -> None:
|
|
||||||
'''
|
|
||||||
Register a new custom log level with `tractor`'s logging
|
|
||||||
machinery in ONE call — the single pluggable entry-point that
|
|
||||||
keeps the (otherwise hand-synced) pieces consistent:
|
|
||||||
|
|
||||||
- `CUSTOM_LEVELS[name]` (drives the `stacklevel` bump in
|
|
||||||
`StackLevelAdapter.log()` + the `get_logger()` audit).
|
|
||||||
- `logging.addLevelName()` registration.
|
|
||||||
- `STD_PALETTE`/`BOLD_PALETTE` color entries (consumed when
|
|
||||||
`get_console_log()` builds its `ColoredFormatter`).
|
|
||||||
- a same-named (lowercase) emit method bound on
|
|
||||||
`StackLevelAdapter` so `log.<name>('msg')` works (and so
|
|
||||||
`get_logger()`'s per-level method audit passes).
|
|
||||||
|
|
||||||
Idempotent: re-registering an existing name is a no-op-ish
|
|
||||||
refresh (won't clobber an already-bound method).
|
|
||||||
|
|
||||||
'''
|
|
||||||
name_up: str = name.upper()
|
|
||||||
name_lo: str = name.lower()
|
|
||||||
|
|
||||||
CUSTOM_LEVELS[name_up] = value
|
|
||||||
logging.addLevelName(value, name_up)
|
|
||||||
STD_PALETTE[name_up] = color
|
|
||||||
BOLD_PALETTE['bold'][name_up] = f'bold_{color}'
|
|
||||||
|
|
||||||
if not hasattr(StackLevelAdapter, name_lo):
|
|
||||||
# bind via default-arg so `value` is captured (not
|
|
||||||
# late-bound); delegates to `.log()` exactly like the
|
|
||||||
# hand-written level methods above.
|
|
||||||
def _emit(
|
|
||||||
self,
|
|
||||||
msg: str,
|
|
||||||
*,
|
|
||||||
_level: int = value,
|
|
||||||
) -> None:
|
|
||||||
return self.log(_level, msg)
|
|
||||||
|
|
||||||
_emit.__name__ = name_lo
|
|
||||||
_emit.__qualname__ = f'StackLevelAdapter.{name_lo}'
|
|
||||||
setattr(StackLevelAdapter, name_lo, _emit)
|
|
||||||
|
|
||||||
|
|
||||||
# `IO`: child-subproc std-stream relay (see
|
|
||||||
# `tractor.trionics._subproc`). Value 21 sits just ABOVE
|
|
||||||
# `INFO`(20) so it's SHOWN BY DEFAULT at the usual `info`/`devx`
|
|
||||||
# console levels (a `runtime`(15) relay would be silently
|
|
||||||
# filtered) yet still distinctly labelled/colored + separately
|
|
||||||
# filterable.
|
|
||||||
add_log_level('IO', 21, 'purple')
|
|
||||||
|
|
||||||
|
|
||||||
# TODO IDEAs:
|
# TODO IDEAs:
|
||||||
# -[ ] move to `.devx.pformat`?
|
# -[ ] move to `.devx.pformat`?
|
||||||
# -[ ] do per task-name and actor-name color coding
|
# -[ ] do per task-name and actor-name color coding
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,6 @@ def _tractor_reap(args):
|
||||||
reap,
|
reap,
|
||||||
reap_shm,
|
reap_shm,
|
||||||
reap_uds,
|
reap_uds,
|
||||||
_TRACTOR_PROC_CMDLINE_MARKERS,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rc: int = 0
|
rc: int = 0
|
||||||
|
|
@ -501,8 +500,9 @@ def _tractor_reap(args):
|
||||||
else:
|
else:
|
||||||
pids = find_orphans()
|
pids = find_orphans()
|
||||||
mode = (
|
mode = (
|
||||||
f'orphans (PPid==1, intrinsic '
|
'orphans (PPid==1, intrinsic '
|
||||||
f'cmdline/comm match — {_TRACTOR_PROC_CMDLINE_MARKERS}'
|
'cmdline/comm match — `tractor[…]` or '
|
||||||
|
'`tractor._child`)'
|
||||||
)
|
)
|
||||||
|
|
||||||
if not pids:
|
if not pids:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue