Source code for banff._common.src.diagnostics

"""# Diagnostics utilities.

## Available Diagnostics

This package facilitates diagnostics of Python packages.
It defines a class for each type of diagnostic supported.
A list of `available_diagnostics` classes is available.

## SystemStats

For convenience, the `SystemStats` class (context manager) can be used to invoke
all available diagnostics using only a single class.

## Enabling and Disabling Diagnostics

By default, diagnostics are disabled.
All diagnostics classes are derived from `GensysDiagnostics`, which implements the class methods
- `.enable_global()`   enable the diagnostic globally
- `.disable_global()`  disable the diagnostic globally
Use them to turn individual diagnostics on or off.
    for example, `.diagnotics.MemoryUsage.enable_global()`

For convenience, functions `enable_all()` and `disable_all()` can be used to
enable or disable all `available_diagnostics` classes, respectively.
- Exception: `SystemStats` is enabled, since it's just a wrapper for other diagnostics classes.

### Diagnostic Enablement Caveats
To allow a global flag for enabling and disable diagnostics classes, each class
maintains a class variable, `._enabled_global`.  When `False`, all instances of the class
will be disabled (all methods return immediately).
To simplificy implementation, once instantiated a disabled instance cannot be enabled.
"""

from ..diagnostics.memory_usage import MemoryUsage
from ..diagnostics.time_measurement import ExecTimer
from .gensys_diagnostics import (
    GensysDiagnostics,
    default_log_level,
)

available_diagnostics = [
    ExecTimer, # Time Measurement
    MemoryUsage, # Memory Usage
]

def set_enabled_global_all(state):
    """Set global enabled state for all diagnostics.

    `state=True`  - enable all diagnostics classes
    `state=False` - disable all diagnostics classes
    """
    for d in available_diagnostics:
        if state:
            d.enable_global()
        else:
            d.disable_global()

[docs] def enable_all(): """Enable all diagnostics classes.""" set_enabled_global_all(True)
[docs] def disable_all(): """Disable all diagnostics classes.""" set_enabled_global_all(False)
[docs] class SystemStats(GensysDiagnostics): _enabled_global=True # enabled by default, since it's just a wrapper for other classes """Convenience class (context manager) calls a set of diagnostics context managers. """ def __init__(self, name, logger=None, log_level=default_log_level): super().__init__() if self.is_disabled(): return self.name = name self.logger = logger self.log_level = log_level self.MemoryUsage = MemoryUsage( name=self.name, logger=self.logger, log_level=self.log_level, ) self.timer = ExecTimer( name=self.name, logger=self.logger, log_level=self.log_level, ) def __enter__(self): if self.is_disabled(): return # start time AFTER analyzing memory: don't time RAM measurements self.MemoryUsage.__enter__() self.timer.__enter__() def __exit__(self, exc_type, exc_value, traceback): if self.is_disabled(): return # stop timer BEFORE analyzing memory: don't time RAM measurements self.timer.__exit__(exc_type=exc_type, exc_value=exc_value, traceback=traceback) self.MemoryUsage.__exit__(exc_type=exc_type, exc_value=exc_value, traceback=traceback)