MetricUtils: Logging & Telemetry#

class my.utils.MetricUtils.MetricUtils#

Methods that deal with logging, telemetry, and other measurement tasks.

Important

These methods are only usable if the optional metrics dependency is installed (pip install my-basis[metrics]). If you try to call them without it, an ImportError will be thrown.

I Logging#

Important

Remote telemetry is content-denying by default: Logfire scrubbing stays enabled, argument inspection and distributed trace propagation are off, and Python log export plus per-process system metrics require explicit opt-in. Configuration overrides use a closed allowlist, custom or unknown scrub behavior is rejected, and environment-derived service identities must be bounded machine identifiers. Application OTLP exporters accept local collectors (including the Podman host and an otel-collector sidecar) or the HTTPS <group-id>.gitlab-o11y.com endpoint; other destinations are rejected before providers change. A destination comes from LOGFIRE_TOKEN, OTEL_EXPORTER_OTLP_ENDPOINT, or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT; without one, applications continue with local logs and retry remote setup on the next call. Failures in optional Python-log, system-metric, or ASGI instrumentation remain local warnings and do not tear down an already-configured trace provider.

classmethod MetricUtils.setup_py_logging(logdir: Annotated[Path, PathType(path_type=dir)], is_dev: bool, package: str, logger: Logger | None = None, app: Any | None = None, maxsize: int = 67108864, maxcount: int = 1024) → Logger#

Configure Python file-based logging with rotation.

Parameters:
  • logdir – Directory for log files.

  • is_dev – If True, use DEBUG level; otherwise INFO.

  • package – Package name for logger identification.

  • logger – Existing logger to configure, or None to create new.

  • app – Optional ASGI app to register logger with.

  • maxsize – Maximum log file size in bytes (default: 64 MB).

  • maxcount – Maximum number of backup files (default: 1024).

Returns:

Configured Logger instance.

Examples

Attach a rotating file handler for a package:

>>> from pathlib import Path
>>> from my import ut
>>> logger = ut.setup_py_logging(Path('logs'), True, 'my-basis')
>>> logger.info('ready')
classmethod MetricUtils.setup_fire_logging(fire_token: str, package: str, logger: Logger, is_dev: bool = True, app: Any | None = None, export_logs: bool = False, system_metrics: bool = False, log_level: str | None = None, **kwargs: Any) → None#

Configure Logfire observability and logging.

Parameters:
  • fire_token – Logfire API token; an empty value falls back to LOGFIRE_TOKEN and permits an OTLP-only destination.

  • package – Package name for service identification.

  • logger – Logger to attach Logfire handler to.

  • is_dev – If True, use development mode with console output (default: True).

  • app – Optional ASGI app to instrument.

  • export_logs – Attach the Python logging handler for already-scrubbed event names.

  • system_metrics – Enable Logfire’s per-process system metrics instrumentation.

  • log_level – Stdlib level name (e.g. WARNING) for the exported log handler; when None, the handler floor stays DEBUG in dev and INFO otherwise.

  • **kwargs – Additional configuration options for Logfire.

Raises:

ValueError – If the service identity/destination is missing or a privacy control is weakened.

Examples

Configure Logfire against an existing logger:

>>> import logging
>>> from my import ut
>>> ut.setup_fire_logging(
...     fire_token='', package='my-basis', logger=logging.getLogger('my-basis'))
classmethod MetricUtils.get_package_name() → str#

Retrieve this utility’s distribution or source-project name.

Standard installed-package metadata is preferred. Editable installs often omit the import-to-distribution map, so their direct_url.json project root is matched against this module; a source checkout falls back to its nearest pyproject.toml. A standalone script without either kind of metadata retains the root import name.

Returns:

Canonical distribution/project name, or the root import name as a fallback.

Examples

Identify the distribution even from an editable checkout:

>>> from my import ut
>>> ut.get_package_name()
'my-basis'
static MetricUtils.setup_logging(logdir: Annotated[Path, PathType(path_type=dir)], is_dev: bool, fire_token: str, package: str = '', logger: Logger | None = None, app: Any | None = None, maxsize: int = 67108864, maxcount: int = 1024, export_logs: bool = False, system_metrics: bool = False, log_level: str | None = None, **fire_kwargs: Any) → Logger#

Configure comprehensive logging (Python file logging + Logfire).

Parameters:
  • logdir – Directory for log files.

  • is_dev – If True, use development mode with DEBUG level.

  • fire_token – Logfire API token (empty string to skip Logfire).

  • package – Package name (auto-detected if empty).

  • logger – Existing logger to configure, or None to create new.

  • app – Optional ASGI app to instrument.

  • maxsize – Maximum log file size in bytes (default: 64 MB).

  • maxcount – Maximum number of backup files (default: 1024).

  • export_logs – Export already-scrubbed Python log records through Logfire.

  • system_metrics – Enable per-process system metrics instrumentation.

  • log_level – Stdlib level name (e.g. WARNING) for the exported log handler; when None, the handler floor stays DEBUG in dev and INFO otherwise. Like the other options, only a package’s first configuration applies it.

  • **fire_kwargs – Additional Logfire configuration options.

Returns:

Configured Logger instance (cached per package).

Examples

One call wires both file logging and Logfire:

>>> from pathlib import Path
>>> from my import ut
>>> logger = ut.setup_logging(Path('logs'), True, fire_token='')
static MetricUtils.setup_warnings()#

Configure warning filters to suppress common deprecation warnings.

Filters out warnings for class-based config, config key changes, and pkg_resources deprecation. Only runs once per session.

II Metrics#

classmethod MetricUtils.setup_metrics(metrics: Annotated[Path, PathType(path_type=dir)], logger: Logger)#

Perform setup for Prometheus metrics, ensuring directory exists and is empty.

Parameters:
  • metrics – Directory for Prometheus multiprocess metrics.

  • logger – Logger for recording setup actions.

Raises:

AssertionError – If PROMETHEUS_MULTIPROC_DIR not set or mismatches metrics path.

Examples

Prepare the Prometheus multiprocess directory:

>>> import logging
>>> from pathlib import Path
>>> from my import ut
>>> metrics_dir = Path('/tmp/prometheus')  # must match $PROMETHEUS_MULTIPROC_DIR
>>> ut.setup_metrics(metrics_dir, logging.getLogger())
classmethod MetricUtils.measure_context(name: str, counter: dict[str, float])#

Context manager to measure execution time of a code block.

Timing is recorded even if the block raises, so a slow-then-crashing path still shows up in counter.

Parameters:
  • name – Metric name for recording.

  • counter – Dictionary counter to record elapsed time.

Yields:

None (timing measured around context block).

Examples

Accumulate elapsed milliseconds into a plain dict:

>>> from my import ut
>>> counter = {}
>>> with ut.measure_context('step', counter):
...     total = sum(range(1000))
>>> counter['step'] > 0
True
classmethod MetricUtils.monitor(*args: Any, **kwargs: Any) → Callable#

Create a Logfire instrumentation decorator for a function.

Parameters:
  • *args – Positional arguments for fire.instrument().

  • **kwargs – Keyword arguments for fire.instrument().

Returns:

Decorator that instruments function with Logfire monitoring.

Examples

Instrument a function with a Logfire span:

>>> from my import ut
>>> @ut.monitor('fetch-page')
... def fetch(url): ...