spacr.logging_util¶
Package-scope Python logging setup for spacr.
Central configuration for every spacr subsystem — core pipelines,
I/O, measure, utilities, and the Qt GUI all funnel through the same
rotating file handler at ~/.spacr/logs/spacr.log.
Two ways to opt in:
Automatic — the Qt GUI calls
setup_logging()at launch, so once you runspacr-qtthe log file is populated for the life of the session.Manual — for headless scripts and notebooks:
from spacr.logging_util import setup_logging, get_logger setup_logging() # once, at program start LOG = get_logger(__name__) # in every module that logs LOG.info("started")
The log level can be overridden by SPACR_LOG_LEVEL in the env
(DEBUG, INFO, WARNING, …). enable_debug() and
disable_debug() are convenience toggles for interactive use.
Third-party libraries that spam INFO records during a spacr pipeline
(torch, cellpose, matplotlib, PIL, urllib3, botocore, tensorflow,
asyncio) are pinned to WARNING so the log stays useful. Add more to
QUIET_LOGGERS if a new dependency starts spamming.
- Public API:
setup_logging(level=INFO, log_file=None) — call once early. get_logger(name) — module-scoped logger. enable_debug() — crank spacr.* to DEBUG. disable_debug() — revert to session level. log_dir() — folder holding the log. log_path() — absolute log file path.
Classes¶
Pass only records whose level is in an explicitly enabled set. |
|
Context manager that logs the elapsed wall-clock for a block. |
Functions¶
|
Re-gate the live handlers from the Preferences switches. |
|
Console levels are a subset of what the file records. |
|
Revert every |
|
Remove spaCR's function trace and restore prior profile hooks. |
|
Turn off all timing logs — the decorators become pass-through. |
|
Crank every |
|
Trace every spaCR Python function and method at DEBUG level. |
|
Turn on the |
|
Return whether spaCR function-level DEBUG tracing is active. |
|
Return a spacr-scoped |
|
Return the folder where spacr log files live. |
|
Return the absolute path of the rotating log file. |
|
Keep only the five switchable levels, discarding anything else. |
|
Only log timings that exceed |
|
Install the rotating file handler on the root logger. |
|
Wrap every public function in |
|
Decorator that logs wall-clock time for every call to |
Module Contents¶
- class spacr.logging_util.LevelSetFilter(levels: Iterable[int] = ())[source]¶
Bases:
logging.FilterPass only records whose level is in an explicitly enabled set.
setLevelis a threshold: enabling DEBUG necessarily enables everything above it. The preference this serves is a set of independent switches, where DEBUG on with INFO off is a legitimate choice, so the gate has to be membership rather than comparison.The set is mutable in place so a live handler can be re-gated from the Preferences dialog without being torn down and rebuilt, which would race against any thread logging at that moment.
- Parameters:
levels – the
logginglevel numbers to pass. Empty – the default – passes NOTHING, which is deliberate: a filter that let everything through until configured would leak records during the window before Preferences applies its choice.
Create an independently switchable logging-level filter.
- Parameters:
levels – exact numeric levels to pass; an empty iterable passes no records.
- filter(record: logging.LogRecord) bool[source]¶
Return whether record has one of the enabled exact levels.
- Parameters:
record – logging record presented by a handler.
- Returns:
Trueonly whenrecord.levelnois enabled.
- class spacr.logging_util.Timer(label: str, logger: str = 'spacr.timing', level: int = logging.INFO)[source]¶
Context manager that logs the elapsed wall-clock for a block.
Example:
from spacr.logging_util import Timer with Timer("preprocess field"): do_work() # -> logs "preprocess field took 12.3 ms"
Nested Timers work fine — each logs its own block independently.
- Parameters:
label – human-readable name shown in the log line.
logger – name of the logger to write to (default
"spacr.timing").level – logging level for the line (default INFO).
- Variables:
elapsed_ms – filled on exit; None while still running.
Create an idle timer with its logging destination.
- Parameters:
label – human-readable operation name included in timing records.
logger – logger name that receives completed timings.
level – logging level used for completed timings.
- __enter__() Timer[source]¶
Start or restart timing and clear any previous duration.
- Returns:
this timer, with
elapsed_msunset while it runs.
- __exit__(exc_type, exc, tb) None[source]¶
Finish one active interval without suppressing body exceptions.
- Parameters:
exc_type – exception type raised by the block, when present.
exc – exception instance raised by the block, when present.
tb – traceback raised by the block, when present.
- Returns:
Noneso any body exception continues to propagate.
- spacr.logging_util.apply_level_policy(file_levels: Iterable[int], console_levels: Iterable[int] = ()) tuple[source]¶
Re-gate the live handlers from the Preferences switches.
- Parameters:
file_levels – levels written to the log files.
console_levels – levels echoed to the in-app console; silently clamped to a subset of
file_levels.
- Returns:
(file_levels, console_levels)as actually applied.
- spacr.logging_util.clamp_console_to_file(console: Iterable[int], file_levels: Iterable[int]) frozenset[source]¶
Console levels are a subset of what the file records.
A level the log file discards cannot reach the console, because the console is fed from the same records. Showing a user a line they will not find in the log file they are about to attach to a bug report is worse than not showing it.
- Parameters:
console – numeric logging levels requested for the console.
file_levels – numeric logging levels the log file records; only levels in both sets are kept.
- spacr.logging_util.disable_debug() None[source]¶
Revert every
spacr.*logger to the level chosen at setup.Inverse of
enable_debug().
- spacr.logging_util.disable_function_trace() None[source]¶
Remove spaCR’s function trace and restore prior profile hooks.
- spacr.logging_util.disable_timing() None[source]¶
Turn off all timing logs — the decorators become pass-through.
- spacr.logging_util.enable_debug() None[source]¶
Crank every
spacr.*logger to DEBUG.Useful when debugging interactively:
>>> from spacr.logging_util import enable_debug >>> enable_debug()
Third-party loggers listed in
QUIET_LOGGERSare left at WARNING to keep the log readable.
- spacr.logging_util.enable_function_trace() None[source]¶
Trace every spaCR Python function and method at DEBUG level.
The hook is installed for the calling thread, all future Python threads, and—on Python 3.12+—threads that already exist. Calls outside the spaCR package are ignored. Repeated calls are idempotent.
This is intentionally verbose and has measurable overhead. With it installed, the Home screen took 7.4 s to become usable, against 4.0-4.2 s without it. Nothing in the GUI installs it, and the Verbose logging preference does not either. Normal operation has no profile hook installed.
- spacr.logging_util.enable_timing() None[source]¶
Turn on the
@timeddecorator +Timercontext manager.Enabled by default. Call this after
disable_timing()to re-enable timing logs at runtime.
- spacr.logging_util.function_trace_enabled() bool[source]¶
Return whether spaCR function-level DEBUG tracing is active.
The trace is controlled by
enable_function_trace()anddisable_function_trace(). The GUI’s Verbose logging preference does not install it. It never records arguments or return values, which avoids copying large arrays and keeps API keys or filesystem metadata out of the diagnostic log.
- spacr.logging_util.get_logger(name: str) logging.Logger[source]¶
Return a spacr-scoped
logging.Logger.Idiomatic usage from any module:
from spacr.logging_util import get_logger LOG = get_logger(__name__)
- Parameters:
name – logger name — typically
__name__so the log stream shows which module the record came from.
- spacr.logging_util.log_dir() pathlib.Path[source]¶
Return the folder where spacr log files live.
SPACR_LOG_DIRoverrides the default, which is useful for portable installs, read-only home directories and test/embedding hosts.- Returns:
the configured directory, otherwise
~/.spacr/logs.
- spacr.logging_util.log_path() pathlib.Path[source]¶
Return the absolute path of the rotating log file.
Uses whatever was passed to
setup_logging()last, or the default underlog_dir()when never set.
- spacr.logging_util.normalise_levels(levels: Iterable[int]) frozenset[source]¶
Keep only the five switchable levels, discarding anything else.
- Parameters:
levels – numeric logging levels (anything
int()accepts); values other than DEBUG, INFO, WARNING, ERROR and CRITICAL are dropped.
- spacr.logging_util.set_timing_threshold_ms(ms: int) None[source]¶
Only log timings that exceed
msmilliseconds.Defaults to 5 ms (env-overridable via
SPACR_TIME_THRESHOLD_MS). Setting to 0 logs every call.- Parameters:
ms – threshold in milliseconds, converted with
int(); negative values are clamped to 0.
- spacr.logging_util.setup_logging(level: int | None = None, log_file: pathlib.Path | None = None, stream: bool = False, quiet: Iterable[str] = QUIET_LOGGERS) pathlib.Path[source]¶
Install the rotating file handler on the root logger.
Idempotent — subsequent calls only re-apply the level, they don’t stack additional handlers. Honours the
SPACR_LOG_LEVELenvironment variable whenlevelis not given.- Parameters:
level – minimum record level for the log file. Defaults to
SPACR_LOG_LEVELenv var (any ofDEBUG/INFO/…) orlogging.INFO.log_file – override for where the file lands. Defaults to
log_path().stream – also attach a StreamHandler to stderr — handy for headless / CI runs where the log file isn’t inspected.
quiet – iterable of logger names to pin at WARNING. Defaults to
QUIET_LOGGERS.
- Returns:
the resolved log-file path.
- spacr.logging_util.time_module(module, exclude: tuple = ()) int[source]¶
Wrap every public function in
modulewithtimed().Idempotent — functions that already carry
__spacr_timed__are skipped. Handy during ad-hoc profiling; not recommended for production imports because it slows every call by ~1 µs.Example:
import spacr.core from spacr.logging_util import time_module time_module(spacr.core) # Every public function on spacr.core now logs its timing.
- Parameters:
module – the module object to wrap.
exclude – iterable of function names to skip.
- Returns:
how many functions were wrapped.
- spacr.logging_util.timed(fn: TimingCallable | None = None, *, name: str | None = None, level: int = logging.INFO) TimingCallable[source]¶
Decorator that logs wall-clock time for every call to
fn.Usable as
@timedor@timed(name="…", level=DEBUG):@timed def preprocess_generate_masks(settings): ... @timed(name="cellpose.batch", level=logging.DEBUG) def _run_batch(...): ...
Log line format:
func_name took 1234.5 ms. The logger name isspacr.timingunless the wrapped function’s module starts withspacr., in which case that module’s logger is reused so timings interleave with the function’s own log records.- Parameters:
fn – the function to wrap (when used as
@timed).name – override the label used in the log line.
level – logging level for the “took Xms” line.
Nested helpers¶
- timed._decorate(inner: TimingCallable) TimingCallable¶
Wrap
innerwith the selected label, logger, and timing marks.spacr/logging_util.py:1041
- timed._decorate._wrapped(*args, **kwargs)¶
Call
innerand log qualifying elapsed time, even on error.spacr/logging_util.py:1048