Folder reorganize 1
This commit is contained in:
309
includes/alerts.php
Normal file
309
includes/alerts.php
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
/**
|
||||
* System-wide alerts include
|
||||
*
|
||||
* Include this file in data pages to display conditional alerts.
|
||||
* Expects $value array to be populated from items.php or shared endpoint.
|
||||
*
|
||||
* Usage: require __DIR__ . '/../includes/alerts.php';
|
||||
*/
|
||||
|
||||
$alerts = [];
|
||||
|
||||
// ============================================================================
|
||||
// Database Connection for Alerts (singleton)
|
||||
// ============================================================================
|
||||
function getAlertConnection() {
|
||||
static $connection = null;
|
||||
|
||||
if ($connection === null) {
|
||||
$connection = mysqli_connect('192.168.0.16', 'lasucaai', 'is413#dfslw', 'controls');
|
||||
if ($connection) {
|
||||
mysqli_set_charset($connection, 'utf8mb4');
|
||||
|
||||
// Create tables if not exists
|
||||
$createLogTable = "CREATE TABLE IF NOT EXISTS alert_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
alert_type VARCHAR(50) NOT NULL,
|
||||
alert_tag VARCHAR(100) NOT NULL,
|
||||
alert_value DECIMAL(18,4) NULL,
|
||||
threshold_value DECIMAL(18,4) NULL,
|
||||
alert_message VARCHAR(500) NOT NULL,
|
||||
source_page VARCHAR(255) NULL,
|
||||
logged_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_alert_type (alert_type),
|
||||
INDEX idx_alert_tag (alert_tag),
|
||||
INDEX idx_logged_at (logged_at)
|
||||
)";
|
||||
mysqli_query($connection, $createLogTable);
|
||||
|
||||
// Create throttle table to track last log time per alert
|
||||
$createThrottleTable = "CREATE TABLE IF NOT EXISTS alert_throttle (
|
||||
alert_key VARCHAR(150) PRIMARY KEY,
|
||||
last_logged DATETIME NOT NULL,
|
||||
INDEX idx_last_logged (last_logged)
|
||||
)";
|
||||
mysqli_query($connection, $createThrottleTable);
|
||||
|
||||
// Create condition state table to track duration
|
||||
$createStateTable = "CREATE TABLE IF NOT EXISTS alert_condition_state (
|
||||
alert_key VARCHAR(150) PRIMARY KEY,
|
||||
condition_started DATETIME NOT NULL,
|
||||
last_seen DATETIME NOT NULL,
|
||||
INDEX idx_last_seen (last_seen)
|
||||
)";
|
||||
mysqli_query($connection, $createStateTable);
|
||||
}
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Check if condition has persisted for required duration (in seconds)
|
||||
// Returns true if condition has been active for >= duration seconds
|
||||
// ============================================================================
|
||||
function checkAlertDuration($alertKey, $conditionMet, $durationSeconds = 0) {
|
||||
if ($durationSeconds <= 0) {
|
||||
// No duration requirement - trigger immediately
|
||||
return $conditionMet;
|
||||
}
|
||||
|
||||
$conn = getAlertConnection();
|
||||
if (!$conn) {
|
||||
return $conditionMet; // Fallback to immediate if no DB
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
if ($conditionMet) {
|
||||
// Condition is currently true - check/update state
|
||||
$stmt = mysqli_prepare($conn,
|
||||
"SELECT condition_started FROM alert_condition_state WHERE alert_key = ?"
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 's', $alertKey);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
if ($row) {
|
||||
// Condition already being tracked - update last_seen
|
||||
$updateStmt = mysqli_prepare($conn,
|
||||
"UPDATE alert_condition_state SET last_seen = ? WHERE alert_key = ?"
|
||||
);
|
||||
if ($updateStmt) {
|
||||
mysqli_stmt_bind_param($updateStmt, 'ss', $now, $alertKey);
|
||||
mysqli_stmt_execute($updateStmt);
|
||||
mysqli_stmt_close($updateStmt);
|
||||
}
|
||||
|
||||
// Check if duration has been met
|
||||
$started = strtotime($row['condition_started']);
|
||||
$elapsed = time() - $started;
|
||||
|
||||
return $elapsed >= $durationSeconds;
|
||||
} else {
|
||||
// First time seeing this condition - start tracking
|
||||
$insertStmt = mysqli_prepare($conn,
|
||||
"INSERT INTO alert_condition_state (alert_key, condition_started, last_seen)
|
||||
VALUES (?, ?, ?)"
|
||||
);
|
||||
if ($insertStmt) {
|
||||
mysqli_stmt_bind_param($insertStmt, 'sss', $alertKey, $now, $now);
|
||||
mysqli_stmt_execute($insertStmt);
|
||||
mysqli_stmt_close($insertStmt);
|
||||
}
|
||||
|
||||
return false; // Just started, duration not met yet
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Condition is false - clear the tracking state
|
||||
$deleteStmt = mysqli_prepare($conn,
|
||||
"DELETE FROM alert_condition_state WHERE alert_key = ?"
|
||||
);
|
||||
if ($deleteStmt) {
|
||||
mysqli_stmt_bind_param($deleteStmt, 's', $alertKey);
|
||||
mysqli_stmt_execute($deleteStmt);
|
||||
mysqli_stmt_close($deleteStmt);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $conditionMet;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Alert Logging Function (throttled to once per minute per alert)
|
||||
// ============================================================================
|
||||
function logAlert($alertType, $alertTag, $alertValue, $alertMessage, $threshold = null) {
|
||||
$conn = getAlertConnection();
|
||||
if (!$conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check throttle - only log once per minute per alert type+tag
|
||||
$alertKey = $alertType . ':' . $alertTag;
|
||||
$throttleCheck = mysqli_prepare($conn,
|
||||
"SELECT last_logged FROM alert_throttle
|
||||
WHERE alert_key = ? AND last_logged > DATE_SUB(NOW(), INTERVAL 1 MINUTE)"
|
||||
);
|
||||
|
||||
if ($throttleCheck) {
|
||||
mysqli_stmt_bind_param($throttleCheck, 's', $alertKey);
|
||||
mysqli_stmt_execute($throttleCheck);
|
||||
$result = mysqli_stmt_get_result($throttleCheck);
|
||||
$recentLog = mysqli_fetch_assoc($result);
|
||||
mysqli_stmt_close($throttleCheck);
|
||||
|
||||
if ($recentLog) {
|
||||
return; // Skip - already logged within last minute
|
||||
}
|
||||
}
|
||||
|
||||
// Log the alert
|
||||
$sourcePage = $_SERVER['PHP_SELF'] ?? 'unknown';
|
||||
|
||||
$stmt = mysqli_prepare($conn,
|
||||
"INSERT INTO alert_log (alert_type, alert_tag, alert_value, threshold_value, alert_message, source_page)
|
||||
VALUES (?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 'ssddss',
|
||||
$alertType,
|
||||
$alertTag,
|
||||
$alertValue,
|
||||
$threshold,
|
||||
$alertMessage,
|
||||
$sourcePage
|
||||
);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
// Update throttle timestamp
|
||||
$throttleUpdate = mysqli_prepare($conn,
|
||||
"INSERT INTO alert_throttle (alert_key, last_logged) VALUES (?, NOW())
|
||||
ON DUPLICATE KEY UPDATE last_logged = NOW()"
|
||||
);
|
||||
if ($throttleUpdate) {
|
||||
mysqli_stmt_bind_param($throttleUpdate, 's', $alertKey);
|
||||
mysqli_stmt_execute($throttleUpdate);
|
||||
mysqli_stmt_close($throttleUpdate);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Silent fail - logging should never break the page
|
||||
error_log('Alert logging failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Alert Definitions (Now managed via alerts-admin.php)
|
||||
// ============================================================================
|
||||
// All alerts are now loaded from the alert_definitions table below.
|
||||
// Use the admin panel at /alerts-admin.php to add, edit, or disable alerts.
|
||||
|
||||
// ============================================================================
|
||||
// Database-Driven Alerts (from alerts-admin.php)
|
||||
// ============================================================================
|
||||
$alertConn = getAlertConnection();
|
||||
if ($alertConn) {
|
||||
$defResult = mysqli_query($alertConn,
|
||||
"SELECT * FROM alert_definitions WHERE is_active = 1"
|
||||
);
|
||||
|
||||
if ($defResult) {
|
||||
while ($def = mysqli_fetch_assoc($defResult)) {
|
||||
$tagName = $def['tag_name'];
|
||||
$tagValue = $value[$tagName] ?? null;
|
||||
|
||||
if ($tagValue === null) {
|
||||
continue; // Tag not found in current data
|
||||
}
|
||||
|
||||
// Evaluate condition based on comparison operator
|
||||
$conditionMet = false;
|
||||
$threshold = floatval($def['threshold_value']);
|
||||
|
||||
switch ($def['comparison']) {
|
||||
case '<':
|
||||
$conditionMet = ($tagValue < $threshold);
|
||||
break;
|
||||
case '<=':
|
||||
$conditionMet = ($tagValue <= $threshold);
|
||||
break;
|
||||
case '>':
|
||||
$conditionMet = ($tagValue > $threshold);
|
||||
break;
|
||||
case '>=':
|
||||
$conditionMet = ($tagValue >= $threshold);
|
||||
break;
|
||||
case '=':
|
||||
$conditionMet = ($tagValue == $threshold);
|
||||
break;
|
||||
case '!=':
|
||||
$conditionMet = ($tagValue != $threshold);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check duration requirement
|
||||
$alertKey = 'db_' . $def['id'] . '_' . $tagName;
|
||||
$durationMet = checkAlertDuration($alertKey, $conditionMet, intval($def['duration_seconds']));
|
||||
|
||||
if ($durationMet) {
|
||||
// Build message from template
|
||||
$alertMessage = str_replace(
|
||||
['{value}', '{threshold}', '{tag}'],
|
||||
[$tagValue, $threshold, $tagName],
|
||||
$def['message_template']
|
||||
);
|
||||
|
||||
$alerts[] = [
|
||||
'type' => $def['alert_type'],
|
||||
'icon' => $def['icon'],
|
||||
'tag' => $tagName,
|
||||
'value' => $tagValue,
|
||||
'threshold' => $threshold,
|
||||
'display' => $def['display_alert'],
|
||||
'message' => htmlspecialchars($alertMessage, ENT_QUOTES, 'UTF-8')
|
||||
];
|
||||
|
||||
logAlert($def['alert_type'], $tagName, $tagValue, $alertMessage, $threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Render Alerts (info alerts are logged only, not displayed)
|
||||
// ============================================================================
|
||||
if (!empty($alerts)) {
|
||||
foreach ($alerts as $alert) {
|
||||
// Skip info alerts - they are logged but not displayed
|
||||
if ($alert['type'] === 'info') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip alerts with display=0 (database-driven alerts can disable display)
|
||||
if (isset($alert['display']) && !$alert['display']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$bgColor = '#c62828'; // danger (red)
|
||||
if ($alert['type'] === 'warning') {
|
||||
$bgColor = '#f57c00'; // warning (orange)
|
||||
}
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td colspan="4" style="background: ' . $bgColor . '; color: white; text-align: center; font-weight: bold; padding: 10px;">';
|
||||
echo $alert['icon'] . ' ' . $alert['message'];
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user