Logs and histories are read by many people, and often copied to tickets or emails. They must never contain passwords, tokens or other sensitive values. In this step, disk_watch.py gets the API token it will later use to send alerts, and Scrippy keeps it out of the logs and of the history.
Add the [alerting] section to /home/luiggi/.local/share/scrippy/conf/disk_watch.conf:
[log]
level = info
[filesystems]
mount_points = /, /home, /var
[thresholds]
warning = 80
critical = 90
[alerting]
token = D34DP4RR0T
#!/usr/bin/env python3
"""
--------------------------------------------------------------------------------
@author : Luiggi Vercotti
@date : 2026-10-08
@version : 0.6.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
0.4.0 2026-10-08 - Luiggi Vercotti - evo: Configuration file
0.5.0 2026-10-08 - Luiggi Vercotti - evo: Command line options
0.6.0 2026-10-08 - Luiggi Vercotti - evo: Alerting API token
--------------------------------------------------------------------------------
List of mandatory configuration parameters:
@conf:filesystems|mount_points|str|false
@conf:thresholds|warning|int|false
@conf:thresholds|critical|int|false
@conf:alerting|token|str|true
--------------------------------------------------------------------------------
List of execution options and argument parameters:
@args:mount-point|str|Mount points to check (default: from configuration)|+||exclude||false|false
@args:exclude|str|Mount points to skip|+||||false|false
@args:warning|int|Warning threshold in percent (default: from configuration)|1||||false|false
@args:critical|int|Critical threshold in percent (default: from configuration)|1||||false|false
@args:token|str|Alerting API token (default: from configuration)|1||||false|true
--------------------------------------------------------------------------------
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
Configuration:
- filesystems::mount_points: Comma separated list of mount points
- thresholds::warning: Warning threshold in percent
- thresholds::critical: Critical threshold in percent
- alerting::token: Alerting API token (secret)
"""
# ------------------------------------------------------------------------------
# Initialization of the environment
# ------------------------------------------------------------------------------
import sys
import shutil
import scrippy_core
from scrippy_core import logger
OK, WARNING, CRITICAL = 0, 1, 2
STATUS = {OK: "OK", WARNING: "WARNING", CRITICAL: "CRITICAL"}
# ------------------------------------------------------------------------------
# Definition of functions and classes
# ------------------------------------------------------------------------------
def get_mount_points(config, args):
if args.mount_point:
return args.mount_point
mount_points = [mp.strip() for mp in config.get("filesystems", "mount_points").split(",")]
return [mp for mp in mount_points if mp not in (args.exclude or [])]
def get_thresholds(config, args):
warning = args.warning if args.warning is not None else config.get("thresholds", "warning", "int")
critical = args.critical if args.critical is not None else config.get("thresholds", "critical", "int")
return warning, critical
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:
config = _context.config
args = _context.args
token = args.token or config.get("alerting", "token")
logger.debug(f"[+] Alerting API token: {token}")
warning, critical = get_thresholds(config, args)
logger.log_section("disk_watch", f"Thresholds: warning={warning}% critical={critical}%")
status = check(get_mount_points(config, args), warning, critical)
logger.info(f"[+] Status: {STATUS[status]}")
if status != OK:
sys.exit(status)
# ------------------------------------------------------------------------------
# Entry point
# ------------------------------------------------------------------------------
if __name__ == '__main__':
main()
What changed:
@conf:alerting|token|str|true declares the token key with its secret field set to true.@args:token|...|false|true declares the --token option with its secret field set to true.main() reads the token from the option, or from the configuration, and logs it in DEBUG level.Run the script in debug mode:
./disk_watch.py --debug --token 0p3nS3s4m3
[...]
[20261008 19:12:42] [DEBUG ] [alerting][token] = ******* [OK]
[...]
[20261008 19:12:42] [DEBUG ] [+] Alerting API token: *******
[...]
The values of the configuration key and of the option are replaced by *******, on the terminal and in the log file. The history is protected too:
./disk_watch.py --hist 1
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------------------------+------+
| Session | Start | End | Duration | Origin | Exec | Code | Params | Exit |
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------------------------+------+
| 1791447162.5065446_29299 | 08/10/2026 19:12:42 | 08/10/2026 19:12:42 | 0 sec | luiggi | luiggi | 0 | ['--debug', '--token', '*******'] | 0 |
+--------------------------+---------------------+---------------------+----------+--------+--------+------+-----------------------------------+------+
The Scrippy logger holds a vault of secret values. Every message is checked against the vault before being logged, and every occurrence of a secret value is replaced by *******, wherever it appears in the message.
The vault is filled automatically:
scrippy_core (Secrets registration (args)),Secrets registration (conf)).So the secrets are protected before your code runs, including in error messages.
A secret obtained at runtime, i.e: a session token returned by an API, can be added to the vault with logger.add_secret():
session_token = get_session_token()
logger.add_secret(session_token)
logger.info(f"[+] Session token: {session_token}") # [+] Session token: *******
ps). The configuration file can be protected by file permissions.chmod 600 disk_watch.conf.1, would redact every 1 of the logs.In the next step, disk_watch.py will write a report file, using the temporary workspace and the Scrippy directories.