2. Logging

In this step, disk_watch.py checks several mount points against a warning and a critical threshold, and uses log levels to report the status of each mount point.

The code

#!/usr/bin/env python3
"""
--------------------------------------------------------------------------------
  @author         : Luiggi Vercotti
  @date           : 2026-10-08
  @version        : 0.2.0
  @description    : Monitor filesystem usage

--------------------------------------------------------------------------------
  Update:
  0.1.0  2026-10-08 - Luiggi Vercotti - cre: Script creation
  0.2.0  2026-10-08 - Luiggi Vercotti - evo: Several mount points, log levels

--------------------------------------------------------------------------------
  Functioning:
  ---------------
    Checks the usage of each mount point against a warning and a critical
    threshold.
"""
# ------------------------------------------------------------------------------
#  Initialization of the environment
# ------------------------------------------------------------------------------
import shutil
import scrippy_core
from scrippy_core import logger

MOUNT_POINTS = ["/", "/home", "/var"]
WARNING_THRESHOLD = 80
CRITICAL_THRESHOLD = 90

# ------------------------------------------------------------------------------
#  Definition of functions and classes
# ------------------------------------------------------------------------------
def get_usage(mount_point):
  logger.debug(f"[+] Checking {mount_point}")
  usage = shutil.disk_usage(mount_point)
  return round(usage.used * 100 / usage.total, 1)

def check(mount_points, warning, critical):
  for mount_point in mount_points:
    usage = get_usage(mount_point)
    if usage >= critical:
      logger.error(f" '-> {mount_point}: {usage}% [CRITICAL]")
    elif usage >= warning:
      logger.warning(f" '-> {mount_point}: {usage}% [WARNING]")
    else:
      logger.info(f" '-> {mount_point}: {usage}% [OK]")

# ------------------------------------------------------------------------------
#  Main processing
# ------------------------------------------------------------------------------
def main():
  with scrippy_core.ScriptContext() as _context:
    logger.log_section("disk_watch", f"Thresholds: warning={WARNING_THRESHOLD}% critical={CRITICAL_THRESHOLD}%")
    check(MOUNT_POINTS, WARNING_THRESHOLD, CRITICAL_THRESHOLD)

# ------------------------------------------------------------------------------
#  Entry point
# ------------------------------------------------------------------------------
if __name__ == '__main__':
  main()
./disk_watch.py
[20261008 19:09:05] [INFO    ] [+] Secrets registration (args)
[20261008 19:09:05] [INFO    ] [+] No configuration file /home/luiggi/.local/share/scrippy/conf/disk_watch.conf
[20261008 19:09:05] [INFO    ] [+] Configuration check
[20261008 19:09:05] [INFO    ] [+] Secrets registration (conf)
[20261008 19:09:05] [INFO    ] [+] Opening history (retention=50)
[20261008 19:09:05] [INFO    ] [+] Using workspace: /home/luiggi/.local/share/scrippy/tmp/disk_watch_1791446945.094108_28564
[20261008 19:09:05] [INFO    ] --------------------------------------------------------------------------------
[20261008 19:09:05] [INFO    ] [disk_watch] Thresholds: warning=80% critical=90%
[20261008 19:09:05] [INFO    ] --------------------------------------------------------------------------------
[20261008 19:09:05] [INFO    ]  '-> /: 34.9% [OK]
[20261008 19:09:05] [INFO    ]  '-> /home: 61.2% [OK]
[20261008 19:09:05] [WARNING ]  '-> /var: 83.7% [WARNING]
[20261008 19:09:05] [INFO    ] [+] Workspace deletion: /home/luiggi/.local/share/scrippy/tmp/disk_watch_1791446945.094108_28564
[20261008 19:09:05] [INFO    ] [+] End: 0

The Scrippy logger

scrippy_core.logger is a standard Python logging.Logger: All the usual methods are available, from the least to the most severe:

Method Level Use it for
logger.debug() DEBUG Details useful to debug the script
logger.info() INFO The normal progress of the script
logger.warning() WARNING An unexpected situation that does not prevent the script from going on
logger.error() ERROR A failure of an operation
logger.critical() CRITICAL A failure that prevents the script from going on

Scrippy adds two methods to separate the parts of a log:

  • logger.log_line(level=logging.INFO) logs a line of 80 dashes.
  • logger.log_section(prefix, message, level=logging.INFO) logs [<prefix>] <message> between two lines of dashes.

On a terminal, each level has its own color. When the standard output is redirected to a file or a pipe, no color is used.

Tip: A log is never too verbose. Each function should log what it does and, when possible, the parameters it receives. The [+] and '-> prefixes used in this tutorial are a Scrippy convention, not a requirement.

Log levels

By default, the log level is INFO: The Checking ... debug messages are not displayed.

The --debug option

The --debug option forces the log level to DEBUG:

./disk_watch.py --debug
[...]
[20261008 19:09:05] [DEBUG   ] [+] Checking /
[20261008 19:09:05] [INFO    ]  '-> /: 34.9% [OK]
[20261008 19:09:05] [DEBUG   ] [+] Checking /home
[20261008 19:09:05] [INFO    ]  '-> /home: 61.2% [OK]
[20261008 19:09:05] [DEBUG   ] [+] Checking /var
[20261008 19:09:05] [WARNING ]  '-> /var: 83.7% [WARNING]
[...]

In DEBUG level, the stack trace of an unhandled error is also displayed (see Error handling).

Warning: The DEBUG level may display information that could prove to be a source of information leakage. It should not be used in production.

The log level can also be set in the configuration file of the script, as you will see in the Configuration file step. The --debug option has priority over the configuration file.

The --no-stdout option

The --no-stdout option disables the output to the terminal, except for the ERROR and CRITICAL messages. The log file is not affected. This is useful when the script is run by a scheduler such as cron:

./disk_watch.py --no-stdout

With the run above, nothing is displayed since no error occurred.

Log files

Each execution writes its own log file in the logdir directory, in a subdirectory named after the script:

/home/luiggi/.local/share/scrippy/log/disk_watch/disk_watch_1791446945.094108_28564.log

The log file name contains the session identifier of the execution (1791446945.094108_28564), presented in the next step.

The --log option

The --log option displays the log file of the last execution:

./disk_watch.py --log

Or the log file of the execution whose session identifier is passed as argument:

./disk_watch.py --log 1791446945.094108_28564

Note: Log files contain color codes. To read a log file directly, use a pager that understands them, such as less -R.

Note: The messages logged while importing scrippy_core, such as Secrets registration (args), and during the configuration check are displayed on the terminal only: The log file is opened right after the configuration check.

The --no-log-file option

The --no-log-file option prevents the creation of the log file and the recording of the execution in the history:

./disk_watch.py --no-log-file
[...]
[20261008 19:09:05] [WARNING ] [+] Option --no-log-file is set -> This session will not be logged nor recorded into history
[...]

--debug, --no-stdout and --no-log-file can be combined.

What's next

disk_watch.py reports the status of each mount point, but a monitoring tool or a scheduler can not read logs: It needs an exit status. In the next step, disk_watch.py will return one, and you will discover how Scrippy keeps track of every execution.