logger

The logger package provides otto’s logging infrastructure including custom levels and formatters.

otto’s logger accessor.

'otto' is a plain logging.Logger (no subclass). otto modules emit via get_otto_logger() / logging.getLogger(__name__); child loggers propagate to 'otto', where the CLI attaches handlers (see otto.logger.management). Configuring/replacing handlers is up to the application — otto-the-library only emits (and otto.logger attaches a NullHandler).

otto.logger.logger.get_otto_logger(name: str | None = None) Logger

Return the 'otto' logger (or the 'otto.<name>' child).

Register short level-name aliases (WARN, CRIT) with the logging system.

Log formatters: multiline splitter and Rich-markup renderer.

otto.logger.formatters.format_log_time(dt: datetime) Text

Format a datetime as a bracketed [ YYYY-MM-DD HH:MM:SS.mmm ] Rich Text.

class otto.logger.formatters.MultilineFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

Bases: Formatter

logging.Formatter that formats each line of a multiline message separately.

Prevents leading continuation lines from being emitted without the log prefix (timestamp/level), keeping log files and console output parseable.

format(record: LogRecord) str

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class otto.logger.formatters.RichFormatter(fmt: str = '{asctime} [{levelname:^7}] {message}', style: '%' | '{' = '{', **kwargs: Any)

Bases: MultilineFormatter

MultilineFormatter for the log file handler that controls Rich markup.

The console handler uses rich.logging.RichHandler directly; this formatter is attached to the file handler. When rich is True, markup is rendered to ANSI escape sequences via an internal capture console; when rich is False (the default), ANSI is stripped so log files stay plain.

format(record: LogRecord) str

Render Rich markup in the record, then delegate to MultilineFormatter.

property rich : bool

True when Rich ANSI output is enabled; False strips ANSI sequences.

Per-command / per-host logging disposition.

LogMode decides where a host’s command I/O is recorded — independent of the log level (INFO vs DEBUG), which stays native to the logger.info/ logger.debug call. See docs/superpowers/specs/2026-06-28-three-sink-logging-design.md.

class otto.logger.mode.LogMode(value)

Bases: Enum

Disposition of a host’s command echo/output across the log sinks.

  • NORMAL — logged at the call’s level, shown everywhere.

  • QUIET — suppressed from the console + console.log, kept in verbose.log.

  • NEVER — redacted from every sink at every level, including session diagnostics.

LogMode governs command I/O only; logger.warning/logger.error and other non-command records are never suppressed by it.

NORMAL = 'normal'
QUIET = 'quiet'
NEVER = 'never'
property rank : int

Restrictiveness rank, ascending NORMAL (0), QUIET (1), NEVER (2).

otto.logger.mode.effective_mode(*modes: LogMode) LogMode

Return the most restrictive of modes (NORMAL when called with none).