A monitoring tool or a scheduler does not read logs: It reads the exit status of the script. In this step, disk_watch.py returns the exit status expected by monitoring tools, and you will discover the execution history that Scrippy keeps for every script.
#!/usr/bin/env python3
"""
--------------------------------------------------------------------------------
@author : Luiggi Vercotti
@date : 2026-10-08
@version : 0.3.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
0.3.0 2026-10-08 - Luiggi Vercotti - evo: Monitoring exit status
--------------------------------------------------------------------------------
Functioning:
---------------
Checks the usage of each mount point against a warning and a critical
threshold and exits with a monitoring compatible exit status:
0: OK, 1: WARNING, 2: CRITICAL
"""
# ------------------------------------------------------------------------------
# Initialization of the environment
# ------------------------------------------------------------------------------
import sys
import shutil
import scrippy_core
from scrippy_core import logger
MOUNT_POINTS = ["/", "/home", "/var"]
WARNING_THRESHOLD = 80
CRITICAL_THRESHOLD = 90
OK, WARNING, CRITICAL = 0, 1, 2
STATUS = {OK: "OK", WARNING: "WARNING", CRITICAL: "CRITICAL"}
# ------------------------------------------------------------------------------
# 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):
worst = OK
for mount_point in mount_points:
usage = get_usage(mount_point)
if usage >= critical:
logger.error(f" '-> {mount_point}: {usage}% [CRITICAL]")
status = CRITICAL
elif usage >= warning:
logger.warning(f" '-> {mount_point}: {usage}% [WARNING]")
status = WARNING
else:
logger.info(f" '-> {mount_point}: {usage}% [OK]")
status = OK
worst = max(worst, status)
return worst
# ------------------------------------------------------------------------------
# Main processing
# ------------------------------------------------------------------------------
def main():
with scrippy_core.ScriptContext(retention=100) as _context:
logger.log_section("disk_watch", f"Thresholds: warning={WARNING_THRESHOLD}% critical={CRITICAL_THRESHOLD}%")
status = check(MOUNT_POINTS, WARNING_THRESHOLD, CRITICAL_THRESHOLD)
logger.info(f"[+] Status: {STATUS[status]}")
if status != OK:
sys.exit(status)
# ------------------------------------------------------------------------------
# Entry point
# ------------------------------------------------------------------------------
if __name__ == '__main__':
main()
What changed:
check() returns the worst status found: OK (0), WARNING (1) or CRITICAL (2).main() exits with this status using sys.exit().retention=100 (see Retention).When all mount points are below the warning threshold, the script ends normally with the exit status 0:
[...]
[20261008 19:09:52] [INFO ] [+] Status: OK
[20261008 19:09:52] [INFO ] [+] Workspace deletion: /home/luiggi/.local/share/scrippy/tmp/disk_watch_1791446992.1042228_28699
[20261008 19:09:52] [INFO ] [+] End: 0
When a mount point reaches the warning threshold, the script exits with the status 1:
[...]
[20261008 19:09:52] [WARNING ] '-> /var: 83.7% [WARNING]
[20261008 19:09:52] [INFO ] [+] Status: WARNING
[20261008 19:09:52] [INFO ] [+] Workspace deletion: /home/luiggi/.local/share/scrippy/tmp/disk_watch_1791446992.257132_28708
[20261008 19:09:52] [INFO ] [+] End: 1 (SystemExit)
[20261008 19:09:52] [CRITICAL] [SystemExit]: 1
echo $?
1
sys.exit() raises a SystemExit exception. The execution context catches it, records the exit status in the history (End: 1 (SystemExit)), logs it as a CRITICAL message and lets the script exit with the requested status. sys.exit() and sys.exit(0) are considered as a successful end: Nothing is logged and the exit status is 0.
Note: Any unhandled error also ends the script with a non-zero exit status. This is detailed in the Error handling step.
Each execution of a Scrippy script is recorded in its execution history, a SQLite3 database stored in the histdir directory and named after the script:
/home/luiggi/.local/share/scrippy/hist/disk_watch.db
--hist optionThe --hist option displays the last 10 executions, from the most recent to the oldest:
./disk_watch.py --hist
10 last executions of disk_watch.py
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------+------------+
| Session | Start | End | Duration | Origin | Exec | Code | Params | Exit |
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------+------------+
| 1791446992.257132_28708 | 08/10/2026 19:09:52 | 08/10/2026 19:09:52 | 0 sec | luiggi | luiggi | 1 | [] | SystemExit |
| 1791446992.1042228_28699 | 08/10/2026 19:09:52 | 08/10/2026 19:09:52 | 0 sec | luiggi | luiggi | 0 | [] | 0 |
| 1791446945.3269963_28568 | 08/10/2026 19:09:05 | 08/10/2026 19:09:05 | 0 sec | luiggi | luiggi | 0 | ['--no-stdout'] | 0 |
| 1791446945.2166913_28565 | 08/10/2026 19:09:05 | 08/10/2026 19:09:05 | 0 sec | luiggi | luiggi | 0 | ['--debug'] | 0 |
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------+------------+
The number of executions to display can be passed to the option:
./disk_watch.py --hist 2
The history columns are:
| Column | Content |
|---|---|
Session |
The session identifier of the execution |
Start |
The start date of the execution |
End |
The end date of the execution (None while the execution is running, or if it has been killed) |
Duration |
The duration of the execution (i.e: 1 min 12 sec) |
Origin |
The user who initiated the execution (the original user in case of sudo) |
Exec |
The user who actually ran the script (i.e: root in case of sudo) |
Code |
The exit status of the execution |
Params |
The options and arguments passed to the script, secret values being redacted |
Exit |
The name of the error if the execution did not end correctly (i.e: SystemExit, FileNotFoundError), 0 otherwise |
Note: The executions run with the --no-log-file option are not recorded. Neither are the executions that stop before the history is opened: Invalid header, invalid configuration file, unauthorized user or concurrent execution refused. These errors are only displayed on the terminal.
Each execution is identified by a unique session identifier, made of the start time of the execution (a Unix timestamp) and of the process identifier (PID):
1791446992.257132_28708
'---------------'-----'
timestamp PID
The session identifier links the history, the log file and the workspace of an execution. To read the log of the execution that ended in WARNING above:
./disk_watch.py --log 1791446992.257132_28708
By default, the history keeps the 50 most recent executions. The retention parameter of the execution context changes this value:
with scrippy_core.ScriptContext(retention=100) as _context:
The history is purged at the start of each execution: Only the retention most recent previous executions are kept, then the current execution is added.
Note: The retention only applies to the history. Log files are never deleted by Scrippy: Use a tool such as logrotate or a scheduled find -delete to purge the logdir directory.
The mount points and the thresholds are hard coded: Changing them requires to modify the script. In the next step, they will move to a configuration file.