Skip to content

naneos.logger

Logging setup of the naneos package.

The package follows the library convention: every module logs to a logger below "naneos" and the package itself installs only a NullHandler, so nothing is printed unless the application configures logging. Two helpers make the common cases one call: enable_console_logging() and enable_file_logging().

CustomFormatter

Bases: Formatter

The naneos log line, optionally coloured by level for terminals.

Source code in src/naneos/logger.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class CustomFormatter(logging.Formatter):
    """The naneos log line, optionally coloured by level for terminals."""

    def __init__(self, terminal: bool = False, fmt: str | None = None) -> None:
        fmt = fmt or _FORMAT
        super().__init__(fmt=fmt)
        self._by_level: dict[int, logging.Formatter] = {}
        if terminal:
            self._by_level = {
                level: logging.Formatter(f"{color} {fmt} {_RESET}")
                for level, color in _COLORS.items()
            }

    def format(self, record: logging.LogRecord) -> str:
        formatter = self._by_level.get(record.levelno)
        if formatter is None:
            return super().format(record)
        return formatter.format(record)

enable_console_logging(level=logging.INFO, colored=True)

Print naneos log messages of at least level to stderr.

Calling it again replaces the previous console handler, so the output is never duplicated. Returns the "naneos" logger.

Source code in src/naneos/logger.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def enable_console_logging(level: int = logging.INFO, colored: bool = True) -> logging.Logger:
    """Print naneos log messages of at least `level` to stderr.

    Calling it again replaces the previous console handler, so the output is
    never duplicated. Returns the "naneos" logger.
    """
    root = logging.getLogger(ROOT_LOGGER_NAME)
    for handler in list(root.handlers):
        if isinstance(handler, _NaneosConsoleHandler):
            root.removeHandler(handler)

    handler = _NaneosConsoleHandler()
    handler.setLevel(level)
    handler.setFormatter(CustomFormatter(terminal=colored))
    root.addHandler(handler)
    _lower_level_to(root, level)
    return root

enable_file_logging(path, level=logging.INFO, max_bytes=0, backup_count=0)

Append naneos log messages of at least level to a file.

path may be a directory, in which case naneos-devices.log is created in it. Calling it again replaces the previous file handler. Returns the "naneos" logger.

The file grows without limit unless max_bytes is set: then it is moved to naneos-devices.log.1 (and so on, up to backup_count files) once it would exceed that size. A long-running application should set both.

Source code in src/naneos/logger.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def enable_file_logging(
    path: str | Path,
    level: int = logging.INFO,
    max_bytes: int = 0,
    backup_count: int = 0,
) -> logging.Logger:
    """Append naneos log messages of at least `level` to a file.

    `path` may be a directory, in which case naneos-devices.log is created in
    it. Calling it again replaces the previous file handler. Returns the
    "naneos" logger.

    The file grows without limit unless `max_bytes` is set: then it is moved to
    naneos-devices.log.1 (and so on, up to `backup_count` files) once it would
    exceed that size. A long-running application should set both.
    """
    path = Path(path).resolve()
    if path.is_dir():
        path = path / DEFAULT_LOG_FILE_NAME
    path.parent.mkdir(parents=True, exist_ok=True)

    root = logging.getLogger(ROOT_LOGGER_NAME)
    for handler in list(root.handlers):
        if isinstance(handler, _NaneosFileHandler):
            handler.close()
            root.removeHandler(handler)

    handler = _NaneosFileHandler(
        str(path), maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8"
    )
    handler.setLevel(level)
    handler.setFormatter(CustomFormatter(terminal=False))
    root.addHandler(handler)
    _lower_level_to(root, level)
    return root

get_naneos_logger(name, level=None)

The logger for a naneos module. Handlers and levels are configured by the application (or the enable_* helpers), not by the module.

Parameters:

Name Type Description Default
name str

Usually name of the calling module.

required
level int | None

Optional level for this one logger. Library modules leave it unset so that one setting on the "naneos" logger controls them all.

None
Source code in src/naneos/logger.py
76
77
78
79
80
81
82
83
84
85
86
87
88
def get_naneos_logger(name: str, level: int | None = None) -> logging.Logger:
    """The logger for a naneos module. Handlers and levels are configured by
    the application (or the enable_* helpers), not by the module.

    Args:
        name: Usually __name__ of the calling module.
        level: Optional level for this one logger. Library modules leave it
            unset so that one setting on the "naneos" logger controls them all.
    """
    logger = logging.getLogger(name)
    if level is not None:
        logger.setLevel(level)
    return logger

set_naneos_logger_save_path(path)

Deprecated alias of enable_file_logging(), kept for naneos-devices <= 1.1.x.

Source code in src/naneos/logger.py
147
148
149
def set_naneos_logger_save_path(path: str | Path) -> None:
    """Deprecated alias of enable_file_logging(), kept for naneos-devices <= 1.1.x."""
    enable_file_logging(path)