Skip to content

logging

logging

Logging utilities for the Anonymizer package.

Classes:

Name Description
LoggingConfig

Logging configuration with preset factories.

ProgressTracker

Log-based progress tracker for sequential record processing.

Functions:

Name Description
configure_logging

Set up logging for Anonymizer.

reapply_log_levels

Re-apply logger levels after third-party init may have overwritten them.

LoggingConfig(anonymizer_level='INFO', data_designer_level='WARNING') dataclass

Logging configuration with preset factories.

Methods:

Name Description
default

Anonymizer at INFO, Data Designer at WARNING.

verbose

Both Anonymizer and Data Designer at INFO.

debug

Anonymizer at DEBUG, Data Designer at INFO.

default() classmethod

Anonymizer at INFO, Data Designer at WARNING.

Source code in src/anonymizer/logging.py
@classmethod
def default(cls) -> LoggingConfig:
    """Anonymizer at INFO, Data Designer at WARNING."""
    return cls(anonymizer_level="INFO", data_designer_level="WARNING")

verbose() classmethod

Both Anonymizer and Data Designer at INFO.

Source code in src/anonymizer/logging.py
@classmethod
def verbose(cls) -> LoggingConfig:
    """Both Anonymizer and Data Designer at INFO."""
    return cls(anonymizer_level="INFO", data_designer_level="INFO")

debug() classmethod

Anonymizer at DEBUG, Data Designer at INFO.

Source code in src/anonymizer/logging.py
@classmethod
def debug(cls) -> LoggingConfig:
    """Anonymizer at DEBUG, Data Designer at INFO."""
    return cls(anonymizer_level="DEBUG", data_designer_level="INFO")

ProgressTracker(total, label, log_interval_percent=10)

Log-based progress tracker for sequential record processing.

Create a progress tracker.

Parameters:

Name Type Description Default
total int

Total number of records to process.

required
label str

Human-readable label for the progress messages.

required
log_interval_percent int

How often to log, as a percentage of total.

10

Methods:

Name Description
record_success

Record a successfully processed record and log progress if due.

record_failure

Record a failed record and log progress if due.

log_final

Emit a final progress line summarizing the run.

Source code in src/anonymizer/logging.py
def __init__(self, total: int, label: str, log_interval_percent: int = 10) -> None:
    """Create a progress tracker.

    Args:
        total: Total number of records to process.
        label: Human-readable label for the progress messages.
        log_interval_percent: How often to log, as a percentage of total.
    """
    self.total = total
    self.label = label
    self.completed = 0
    self.failed = 0

    interval_fraction = max(1, log_interval_percent) / 100.0
    self.log_interval = max(1, int(total * interval_fraction)) if total > 0 else 1
    self.next_log_at = self.log_interval

    self.start_time = time.perf_counter()
    self._enabled = total >= _PROGRESS_THRESHOLD

record_success()

Record a successfully processed record and log progress if due.

Source code in src/anonymizer/logging.py
def record_success(self) -> None:
    """Record a successfully processed record and log progress if due."""
    self._record(success=True)

record_failure()

Record a failed record and log progress if due.

Source code in src/anonymizer/logging.py
def record_failure(self) -> None:
    """Record a failed record and log progress if due."""
    self._record(success=False)

log_final()

Emit a final progress line summarizing the run.

Source code in src/anonymizer/logging.py
def log_final(self) -> None:
    """Emit a final progress line summarizing the run."""
    if self._enabled and self.completed > 0:
        self._log_progress()

configure_logging(config=None, *, verbose=False, enabled=True)

Set up logging for Anonymizer.

Parameters:

Name Type Description Default
config LoggingConfig | None

Logging preset. Defaults to LoggingConfig.default().

None
verbose bool

Deprecated convenience flag. True maps to LoggingConfig.verbose(). Ignored when config is provided.

False
enabled bool

Set to False to prevent Anonymizer from adding any log handlers. Useful when the caller manages logging independently.

True
Source code in src/anonymizer/logging.py
def configure_logging(
    config: LoggingConfig | None = None,
    *,
    verbose: bool = False,
    enabled: bool = True,
) -> None:
    """Set up logging for Anonymizer.

    Args:
        config: Logging preset. Defaults to ``LoggingConfig.default()``.
        verbose: Deprecated convenience flag. ``True`` maps to
            ``LoggingConfig.verbose()``. Ignored when *config* is provided.
        enabled: Set to ``False`` to prevent Anonymizer from adding any log
            handlers. Useful when the caller manages logging independently.
    """
    global _anonymizer_handler, _configured, _active_config
    _configured = True

    if not enabled:
        _active_config = None
        return

    if config is None:
        config = LoggingConfig.verbose() if verbose else LoggingConfig.default()

    _active_config = config

    anon_logger = logging.getLogger("anonymizer")
    dd_logger = logging.getLogger("data_designer")

    # Attach our handler to the anonymizer logger (not root) so we don't
    # clobber application-level logging configured via stdlib APIs.
    if _anonymizer_handler is not None and _anonymizer_handler in anon_logger.handlers:
        anon_logger.removeHandler(_anonymizer_handler)
    anon_logger.handlers = [h for h in anon_logger.handlers if type(h) is not logging.StreamHandler]

    _anonymizer_handler = logging.StreamHandler(sys.stderr)
    _anonymizer_handler.setFormatter(logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S"))
    anon_logger.addHandler(_anonymizer_handler)
    anon_logger.propagate = False
    anon_logger.setLevel(config.anonymizer_level)

    # DD logger gets its own handler so its messages are formatted consistently.
    dd_logger.handlers = [h for h in dd_logger.handlers if type(h) is not logging.StreamHandler]
    dd_handler = logging.StreamHandler(sys.stderr)
    dd_handler.setFormatter(logging.Formatter("[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S"))
    dd_logger.addHandler(dd_handler)
    dd_logger.propagate = False
    dd_logger.setLevel(config.data_designer_level)

    for name in _DEFAULT_NOISY_LOGGERS:
        logging.getLogger(name).setLevel(logging.WARNING)

reapply_log_levels()

Re-apply logger levels after third-party init may have overwritten them.

DataDesigner's _initialize_interface_runtime resets the data_designer logger level and noisy-logger suppression. Call this after creating a DataDesigner instance to restore the levels chosen by the user's LoggingConfig.

Source code in src/anonymizer/logging.py
def reapply_log_levels() -> None:
    """Re-apply logger levels after third-party init may have overwritten them.

    DataDesigner's ``_initialize_interface_runtime`` resets the
    ``data_designer`` logger level and noisy-logger suppression.
    Call this after creating a ``DataDesigner`` instance to restore
    the levels chosen by the user's ``LoggingConfig``.
    """
    if _active_config is None:
        return
    logging.getLogger("data_designer").setLevel(_active_config.data_designer_level)
    for name in _DEFAULT_NOISY_LOGGERS:
        logging.getLogger(name).setLevel(logging.WARNING)