Hemdal allows you to monitor hosts and services by running periodic checks and transitioning through defined states based on the command result.
Alert Structure
An alert is configured with the following properties:
id: A unique identifier string (e.g. UUID) for the alert process.name: A human-readable name describing what is being monitored.enabled: Boolean flag (trueby default). Whenfalse, the alert is in:disabledstate and performs no checks.check_in_sec: Interval in seconds between checks while in the:normal(healthy) state (default:60).recheck_in_sec: Interval in seconds between retries when a check fails (default:5).broken_recheck_in_sec: Interval in seconds between checks once confirmed:broken(default:30).retries: Number of consecutive failures in:failingstate before transitioning to:broken(default:3).command_args: A list of string arguments passed to the executed command (default:[]).host: The host configuration on which the command will be executed (seeHemdal.Config.Host).command: The command to execute (seeHemdal.Config.Command).notifiers: A list of notifiers to dispatch notifications to upon state transitions (seeHemdal.Config.Notifier).
State Machine Lifecycle
Each alert runs as an independent state machine with four possible states:
disabled: The alert is inactive. It does not perform checks until re-enabled.normal: The check succeeds (OK). Checked everycheck_in_secseconds.failing: The check returned an error or warning (WARN/FAIL/UNKNOWN). Retried everyrecheck_in_secseconds for up toretriestimes.broken: The alert failed all retries and is confirmed broken. Checked everybroken_recheck_in_secseconds until recovery.
Configuration Examples
1. Elixir Environment Backend (Hemdal.Config.Backend.Env)
In your config/config.exs or runtime configuration:
import Config
config :hemdal, :config_module, Hemdal.Config.Backend.Env
config :hemdal, Hemdal.Config, [
[
id: "36c16e85-7221-4021-8d6d-89f38a6d136c",
name: "Disk Space Check",
enabled: true,
check_in_sec: 60,
recheck_in_sec: 5,
broken_recheck_in_sec: 30,
retries: 3,
host: [
id: "ec8fff22-41c2-4245-8a7b-5157d40c33a7",
name: "localhost",
module: Hemdal.Host.Local,
max_workers: 2
],
command: [
name: "check_disk",
type: "line",
command: "df -h / | awk 'NR==2 {print $5}' | sed 's/%//' | awk '{if ($1 > 90) print \"[\\\"FAIL\\\", \\\"Disk full: \"$1\"%\\\"]\"; else print \"[\\\"OK\\\", \\\"Disk usage: \"$1\"%\\\"]\"}'",
decode: true
],
notifiers: [
[
module: Hemdal.Notifier.Slack,
token: "https://hooks.slack.com/services/YOUR_SLACK_WEBHOOK",
username: "Hemdal Bot",
log_level: "warn"
]
]
]
]2. JSON Backend (Hemdal.Config.Backend.Json)
Configure file paths in config/config.exs:
import Config
config :hemdal, :config_module, Hemdal.Config.Backend.Json
config :hemdal, Hemdal.Config,
hosts_file: "config/hosts.json",
alerts_file: "config/alerts.json"In config/hosts.json:
[
{
"id": "2a8572d4-ceb3-4200-8b29-dd1f21b50e54",
"name": "127.0.0.1",
"module": "Hemdal.Host.Local",
"max_workers": 2
}
]In config/alerts.json:
[
{
"id": "52d13d6d-f217-4152-965d-cf5f488ceac4",
"name": "HTTP Health Check",
"enabled": true,
"host_id": "2a8572d4-ceb3-4200-8b29-dd1f21b50e54",
"check_in_sec": 30,
"recheck_in_sec": 5,
"broken_recheck_in_sec": 15,
"retries": 2,
"command": {
"name": "curl_health",
"type": "line",
"command": "curl -s -f http://localhost:4000/health && echo '[\"OK\", \"healthy\"]' || echo '[\"FAIL\", \"unhealthy\"]'"
}
}
]Command Types
line: A single command line executed via the host handler.script: A multi-line script written to a temporary file on the host, executed, and cleaned up automatically.shell: An interactive shell session allowing real-time bidirectional data piping.
Command Output Formats
When decode: true (default), Hemdal parses the output as JSON. The command can output:
- A JSON array:
["OK", "All systems operational"]or["FAIL", "High CPU usage"] - A JSON map:
{"status": "OK", "message": "Healthy", "custom_metric": 42} - A JSON string status:
"OK"or"FAIL"
Statuses recognized by Hemdal are "OK", "WARN", "FAIL", and "UNKNOWN".
Exit code 0 maps to :ok, exit code 1 maps to WARN, and exit code 2 maps to FAIL.
Managing Alerts Programmatically
# Retrieve all running alerts and their current statuses
Hemdal.get_all_alerts()
# Reload configuration from backend (starts new alerts, updates existing, and stops deleted ones)
Hemdal.reload_all()
# Manually start a specific alert by ID from backend configuration
Hemdal.start_alert!("36c16e85-7221-4021-8d6d-89f38a6d136c")
# Stop an alert
Hemdal.Check.stop("36c16e85-7221-4021-8d6d-89f38a6d136c")