From 5be452db173ebf6f349cc58d134e1b9552572963 Mon Sep 17 00:00:00 2001 From: Gary Snider <75227981+gsnider2195@users.noreply.github.com> Date: Tue, 5 May 2026 15:59:39 -0700 Subject: [PATCH 1/2] The pyntc rotating file handler is now opt-in via the `PYNTC_LOG_FILE` environment variable. When unset, no log file is created. When set, its value is used as the log file path, and the handler is registered only once per logger to avoid duplicate entries on repeated `get_log` calls. --- docs/user/lib_getting_started.md | 17 +++++++++++++++++ pyntc/log.py | 14 +++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/user/lib_getting_started.md b/docs/user/lib_getting_started.md index 66aad79a..8d45927d 100644 --- a/docs/user/lib_getting_started.md +++ b/docs/user/lib_getting_started.md @@ -342,6 +342,23 @@ Full workflow example: >>> ``` +# Logging + +pyntc reads several environment variables to configure logging. None of them are required; all are read at runtime. + +| Variable | Description | +| --- | --- | +| `PYNTC_LOG_LEVEL` | Log level for the `pyntc` logger (e.g. `debug`, `info`, `warning`). Defaults to `info`. | +| `PYNTC_DEBUG` | When set to any non-empty value, forces the log level to `DEBUG` and switches to a more verbose log format. | +| `PYNTC_LOG_FILE` | Path to a file that pyntc should log to. When set, a `RotatingFileHandler` (2000 byte rotation) is attached to the logger using this path. When unset, no file handler is attached; log records still propagate to the root logger configured by `logging.basicConfig` (called from `pyntc.log.init` during device initialization) or by the calling application. | + +Example: + +```bash +export PYNTC_LOG_FILE=/var/log/pyntc.log +export PYNTC_LOG_LEVEL=debug +``` + #### Cisco IOS Install Mode Option New in 0.15 there is support for [Install Mode](https://content.cisco.com/chapter.sjs?uri=/searchable/chapter/c/en/us/td/docs/switches/lan/Denali_16-1/ConfigExamples_Technotes/Config_Examples/Misc/qos/m_install_vs_bundle.html.xml) upgrades. To execute this there is an option (defaults to False) to run install mode. **file_copy must be executed before install_os** diff --git a/pyntc/log.py b/pyntc/log.py index 13c57744..0fd0a566 100644 --- a/pyntc/log.py +++ b/pyntc/log.py @@ -17,6 +17,10 @@ def get_log(name=None): """Get log namespace and creates logger and rotating file handler. + A :class:`RotatingFileHandler` is attached if the ``PYNTC_LOG_FILE`` + environment variable is set, in which case its value is used as the log + file path. + Args: name (str, optional): Sublogger name. Defaults to None. @@ -24,10 +28,14 @@ def get_log(name=None): (logger): Return a logger instance in the :data:`APP` namespace. """ logger_name = f"{APP}.{name}" if name else APP - # file handler - handler = RotatingFileHandler(f"{logger_name}.log", maxBytes=2000) _logger = logging.getLogger(logger_name) - _logger.addHandler(handler) + + log_file = os.environ.get("PYNTC_LOG_FILE") + if log_file and not any( + isinstance(h, RotatingFileHandler) and getattr(h, "baseFilename", None) == os.path.abspath(log_file) + for h in _logger.handlers + ): + _logger.addHandler(RotatingFileHandler(log_file, maxBytes=2000)) return _logger From e163ec18256712bdd88c002e8ff62bdc4e191324 Mon Sep 17 00:00:00 2001 From: Gary Snider <75227981+gsnider2195@users.noreply.github.com> Date: Tue, 5 May 2026 16:01:00 -0700 Subject: [PATCH 2/2] changelog --- changes/383.changed | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/383.changed diff --git a/changes/383.changed b/changes/383.changed new file mode 100644 index 00000000..a5816568 --- /dev/null +++ b/changes/383.changed @@ -0,0 +1 @@ +The pyntc rotating file handler is now opt-in via the `PYNTC_LOG_FILE` environment variable. When unset, no log file is created. When set, its value is used as the log file path, and the handler is registered only once per logger to avoid duplicate entries on repeated `get_log` calls.