Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ce0872a
feat: add partition fail-safe, bounded recovery, collector health, ph…
bmfmancini Sep 22, 2026
01134db
fix test rule
bmfmancini Sep 22, 2026
10bb3d5
place the test rule button with the others
bmfmancini Sep 22, 2026
61cc05b
only preview 10 rules should be enough
bmfmancini Sep 22, 2026
01beef0
Add maintence supression options
bmfmancini Sep 22, 2026
46e0613
Change maint window frames from free text to datetime pickers
bmfmancini Sep 22, 2026
8c77253
be less restricitve on schedule options
bmfmancini Sep 22, 2026
01ad824
.
bmfmancini Sep 22, 2026
bd43459
.
bmfmancini Sep 22, 2026
bccfd52
add date time picker for global one time supression
bmfmancini Sep 22, 2026
13499b3
.
bmfmancini Sep 22, 2026
b757229
fix typing
bmfmancini Sep 22, 2026
856bfed
Merge remote-tracking branch 'origin/develop' into feat/alert-suppres…
bmfmancini Sep 23, 2026
a9c6b78
Host based alert settings
bmfmancini Sep 23, 2026
ec32aba
Fix page layout
bmfmancini Sep 23, 2026
7a6e0c7
restore multi select menu
bmfmancini Sep 23, 2026
4a6b131
remove redudant actions button
bmfmancini Sep 23, 2026
bc2351b
Merge remote-tracking branch 'origin/develop' into feature/device-ale…
bmfmancini Sep 23, 2026
986e4bb
add change log
bmfmancini Sep 23, 2026
7e8feac
add changelog
bmfmancini Sep 23, 2026
0d46ed9
Update locales
bmfmancini Sep 23, 2026
726c75b
fix: drop unsupported message argument from Pest toContain() in Devic…
bmfmancini Sep 23, 2026
6157a39
Allow exporting
bmfmancini Sep 23, 2026
28f83a6
Update device dropdown
bmfmancini Sep 23, 2026
254adfa
Use the cacto dropdown/update locales
bmfmancini Sep 23, 2026
c0c61f7
fix syntax
bmfmancini Sep 23, 2026
0f5d7a8
another attempt at the auto complete dropdown
bmfmancini Sep 23, 2026
82a0cc9
add missing commit
bmfmancini Sep 23, 2026
44f3141
Apply cacti dropdown
bmfmancini Sep 23, 2026
8191ead
reattaempt dropdown implimentation
bmfmancini Sep 23, 2026
7c517dc
rebuild locales
bmfmancini Sep 23, 2026
2aae15f
remove po files
bmfmancini Sep 23, 2026
189c405
restore the pi files
bmfmancini Sep 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

--- develop ---

* feature: Add Device Alert Rules for device-wide alert handling: administrators can pause a device's non-exempt alerts until a selected time or indefinitely, choose a priority threshold that always passes through device pauses and maintenance windows, and allow all device alerts during maintenance for critical devices

* feature: Add a fail-safe for partition maintenance: when the partition metadata for the syslog or syslog_removed table is invalid or incomplete, or a required partition cannot be created, all partition creation and retention pruning stops, the dMaxValue safety partition is never dropped, and the blocked condition with its remediation step is logged and shown on the Syslog Status page
* feature: Add bounded multi-day partition recovery: a new 'Partition Recovery Limit' setting caps how many missing partitions are created per table per poller run so large gaps heal over several cycles; retention pruning stays deferred until the future write horizon is restored, and each blocked run reports the remaining gap, the stop reason, and whether writes are accumulating in dMaxValue
* feature: Add collector health metrics to the Syslog Status tab: last received log timestamp, oldest unprocessed incoming message age, current incoming backlog, records processed in the latest run, and a warning when data looks stale or the backlog exceeds the new 'Collector Staleness' and 'Collector Backlog Threshold' settings; unavailable metrics read as Unavailable instead of invented values
Expand Down
2 changes: 1 addition & 1 deletion INFO
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

[info]
name = syslog
version = 4.4
version = 4.5
longname = Syslog Monitoring
author = The Cacti Group
email =
Expand Down
74 changes: 56 additions & 18 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4283,6 +4283,53 @@ function syslog_alert_suppression_record(array $alert, array $state): void {
syslog_db_execute_prepared('INSERT INTO syslog_alert_suppression (alert_id, scope_key, dedup_hash, last_sent) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE last_sent = VALUES(last_sent)', [$alert['id'], $state['scope_key'], $state['dedup_hash'], time()]);
}

/** Return whether this alert's configured maintenance window is active. */
function syslog_alert_maintenance_is_active(array $alert): bool {
$mode = $alert['maintenance_mode'] ?? 'inherit';
if ($mode === 'disabled') {
return false;
}
if ($mode === 'custom') {
return syslog_alert_datetime_window_is_active((string) ($alert['maintenance_datetime_start'] ?? ''), (string) ($alert['maintenance_datetime_end'] ?? ''))
|| syslog_alert_schedule_is_active(syslog_alert_maintenance_window((string) ($alert['maintenance_days'] ?? ''), (string) ($alert['maintenance_start'] ?? ''), (string) ($alert['maintenance_end'] ?? '')));
}

return syslog_alert_datetime_window_is_active((string) read_config_option('syslog_alert_maintenance_datetime_start'), (string) read_config_option('syslog_alert_maintenance_datetime_end'))
|| syslog_alert_schedule_is_active(syslog_alert_maintenance_window((string) read_config_option('syslog_alert_maintenance_days'), (string) read_config_option('syslog_alert_maintenance_start'), (string) read_config_option('syslog_alert_maintenance_end')));
}

/**
* Limit an alert query by active device-wide handling rules.
*
* A pass-through priority of Critical (2), for example, permits priorities
* Emergency through Critical even if the host is muted or in maintenance.
* A rule applies by hostname to every alert definition, not merely one rule.
*
* @return array{sql:string,params:array<int,int>}
*/
function syslog_device_rule_sql(bool $maintenance_active): array {
global $syslogdb_default, $syslog_incoming_config;
$host_field = $syslog_incoming_config['hostField'] ?? 'host';
$priority_field = $syslog_incoming_config['priorityField'] ?? 'priority_id';
$now = time();
$active_mute = "(dr.mute_mode = 'indefinite' OR (dr.mute_mode = 'until' AND dr.mute_until > ?))";
$pass_through = "(dr.pass_through_priority >= 0 AND COALESCE(`$priority_field`, 99) <= dr.pass_through_priority)";
$mute_filter = "\n\t\t\t\tAND NOT EXISTS (SELECT 1 FROM `$syslogdb_default`.`syslog_device_rule` AS dr WHERE dr.host = `$host_field` AND dr.enabled = 'on' AND NOT $pass_through AND $active_mute)";
if ($maintenance_active) {
// Normal maintenance still mutes every device. Only an explicit device
// exception may admit a record, so the absence of a device rule is not
// accidentally treated as an exception.
$maintenance_filter = "\n\t\t\t\tAND EXISTS (SELECT 1 FROM `$syslogdb_default`.`syslog_device_rule` AS dr WHERE dr.host = `$host_field` AND dr.enabled = 'on' AND (dr.allow_maintenance = 'on' OR $pass_through))";
} else {
$maintenance_filter = '';
}

return [
'sql' => $maintenance_filter . $mute_filter,
'params' => [$now]
];
}

function syslog_process_alerts($max_seq) {
global $syslogdb_default;

Expand All @@ -4309,22 +4356,7 @@ function syslog_process_alerts($max_seq) {

if (cacti_sizeof($alerts)) {
foreach ($alerts as $alert) {
$mode = $alert['maintenance_mode'] ?? 'inherit';
if ($mode === 'custom') {
$schedule = syslog_alert_maintenance_window((string) ($alert['maintenance_days'] ?? ''), (string) ($alert['maintenance_start'] ?? ''), (string) ($alert['maintenance_end'] ?? ''));
$dated_window = syslog_alert_datetime_window_is_active((string) ($alert['maintenance_datetime_start'] ?? ''), (string) ($alert['maintenance_datetime_end'] ?? ''));
} elseif ($mode === 'disabled') {
$schedule = '';
$dated_window = false;
} else {
$schedule = syslog_alert_maintenance_window((string) read_config_option('syslog_alert_maintenance_days'), (string) read_config_option('syslog_alert_maintenance_start'), (string) read_config_option('syslog_alert_maintenance_end'));
$dated_window = syslog_alert_datetime_window_is_active((string) read_config_option('syslog_alert_maintenance_datetime_start'), (string) read_config_option('syslog_alert_maintenance_datetime_end'));
}
if ($dated_window || syslog_alert_schedule_is_active($schedule)) {
syslog_debug(sprintf("Alert Rule '%s' is muted by a maintenance window", $alert['name']));

continue;
}
$maintenance_active = syslog_alert_maintenance_is_active($alert);
$sql = '';
$params = [];

Expand All @@ -4345,6 +4377,9 @@ function syslog_process_alerts($max_seq) {

$sql = $sql_data['sql'];
$params = $sql_data['params'];
$device_rule = syslog_device_rule_sql($maintenance_active);
$sql .= $device_rule['sql'];
$params = array_merge($params, $device_rule['params']);

if ($sql != '') {
if ($alert['level'] == '1') {
Expand Down Expand Up @@ -5777,7 +5812,7 @@ function alert_replace_variables($alert, $results, $hostname = '') {
function syslog_message_button($message, $device, $program, $facility, $severity, $received, $id = 0, $source = ''): string {
$details = compact('device', 'program', 'facility', 'severity', 'received');
$details['message'] = (string) $message;
$details['rules'] = syslog_message_rule_links($id, $source, $received);
$details['rules'] = syslog_message_rule_links($id, $source, $received, $device);
$text = title_trim((string) $message, 100);
return '<button type="button" class="syslogMessageOpen" aria-controls="syslog_message_details" aria-expanded="false" data-message="' .
html_escape(json_encode($details, JSON_INVALID_UTF8_SUBSTITUTE)) . '">' . html_escape($text) . '</button>';
Expand All @@ -5792,7 +5827,7 @@ function syslog_message_button($message, $device, $program, $facility, $severity
*
* @return array<string, string> Map of action name to rule editor URL.
*/
function syslog_message_rule_links($id, $source, $received): array {
function syslog_message_rule_links($id, $source, $received, $host = ''): array {
$links = [];
if ($source !== 'main' || !ctype_digit((string) $id) || (int) $id < 1) {
return $links;
Expand All @@ -5804,6 +5839,9 @@ function syslog_message_rule_links($id, $source, $received): array {
$links[$action] = $page . '?' . $query;
}
}
if ($host !== '' && api_plugin_user_realm_auth('syslog_device_rules.php')) {
$links['device'] = 'syslog_device_rules.php?' . http_build_query(['action' => 'edit', 'host' => $host]);
}
return $links;
}

Expand Down
4 changes: 2 additions & 2 deletions js/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ function syslogDashboardPanelById(panelId) {

/* ===================== Event wiring ===================== */

$(function() {
if (window.jQuery) window.jQuery(function() {
if (!document.getElementById('syslog_dashboard_grid')) {
return;
}
Expand Down Expand Up @@ -764,4 +764,4 @@ function syslogDashboardPrompt(name, accept) {
{text: syslogDashboard.text.cancel, click: function() { $(this).dialog('close'); }}
]
});
}
}
Loading
Loading