Skip to content

Instantly share code, notes, and snippets.

@miken32
Created May 14, 2023 18:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miken32/832d8bfb8aad7391b08d28e7440c96b9 to your computer and use it in GitHub Desktop.
Save miken32/832d8bfb8aad7391b08d28e7440c96b9 to your computer and use it in GitHub Desktop.
PHP parsing for Nagios/Icinga threshold values
/**
* Return a normalized threshold value (floats are converted to ints)
*
* @param string $thresh The threshold specification
* @return string The normalized threshold
* @throws Exception In case of invalid format
*/
function parse_threshold(string $thresh): string
{
if (preg_match("/^[0-9]+$/", $thresh)) {
verbose("Threshold $thresh is an integer", 3);
return $thresh;
}
if (preg_match("/^([0-9]+)\.[0-9]+$/", $thresh, $matches)) {
verbose("Threshold $thresh is a float, returning integer", 3);
return $matches[1];
}
if (preg_match("/^(@?(?:[0-9]+|~))(?:\\.[0-9]+)?(?::(?:([0-9]+)(?:\\.[0-9]+)?)?)?$/", $thresh, $matches)) {
verbose("Threshold $thresh is a range '$matches[1]' to '$matches[2]'", 3);
if (count($matches) !== 3) {
return $matches[1];
}
if ($matches[1] === "~" || $matches[1] < $matches[2]) {
return "$matches[1]:$matches[2]";
}
}
throw new Exception("Invalid threshold format $thresh");
}
/**
* Checks to see if a value should trigger an alert based on a given threshold
* The threshold specification looks like [@][start:][end]
* 'start:end' means to alert if value is *outside* of the range
* 'start:' means end is infinity, effectively alert if below start
* 'end' means start is negative infinity, effectively alert if value is above end
* '~:end' is the same as omitting start
* a leading '@' means to invert the above definitions
*
* @see https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT
* @see https://icinga.com/docs/icinga-2/2.11/doc/05-service-monitoring/#threshold-ranges
* @param string $thresh The threshold specification
* @param string|int $val The numeric value to compare against
* @return bool Whether or not an alert should be raised
*/
function compare_threshold(string $thresh, string|int $val): bool
{
verbose("Evaluating '$thresh' with '$val'", 2);
$inverse = false;
$start = null;
$end = null;
if (str_starts_with($thresh, "@")) {
$inverse = true;
$thresh = trim($thresh, "@");
}
if (!str_contains($thresh, ":")) {
$end = (int)$thresh;
} else {
$vals = explode(":", $thresh);
$start = $vals[0] === "~" ? -INF : (int)$vals[0];
$end = $vals[1] === "" ? INF : (int)$vals[1];
}
return $inverse
? $val <= $end && (is_null($start) || $val >= $start)
: $val > $end || (!is_null($start) && $val < $start);
}
/**
* Output debug data
* @param string $message The message to output to stderr
* @param int $level The verbosity level
*/
function verbose(string $message, int $level = 1): void
{
global $verbose;
if ($verbose >= $level) {
file_put_contents("php://stderr", "$message\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment