";
}
/**
* Render wrapper header for names view table.
*
* @return string
*/
function renderHeaderNames(): string {
return "
";
}
/**
* Render wrapper header for icon tile view.
*
* @return string
*/
function renderHeaderTiles(): string {
return renderHeaderDefault();
}
/**
* Render wrapper header for advanced tile view.
*
* @return string
*/
function renderHeaderTilesadt(): string {
return renderHeaderDefault();
}
/**
* Event key => short label and status CSS class for the Events column pills.
*
* @return array
*/
function monitorEventMeta(): array {
return [
'down' => ['label' => __('Down', 'monitor'), 'class' => 'deviceDown'],
'recovering' => ['label' => __('Recovering', 'monitor'), 'class' => 'deviceRecovering'],
'triggered' => ['label' => __('Triggered', 'monitor'), 'class' => 'deviceThreshold'],
'down_ma' => ['label' => __('Down (M/A)', 'monitor'), 'class' => 'deviceDownMuted'],
'triggered_ma' => ['label' => __('Triggered (M/A)', 'monitor'), 'class' => 'deviceThresholdMuted'],
'warn_ping' => ['label' => __('Warn Ping', 'monitor'), 'class' => 'deviceWarning'],
'alert_ping' => ['label' => __('Alert Ping', 'monitor'), 'class' => 'deviceAlert'],
'failed_svc' => ['label' => __('Failed Svc', 'monitor'), 'class' => 'deviceServiceCheck'],
];
}
/**
* Resolve every active event on a host for the Events column (a device can have
* several, e.g. Down and Triggered). Uses the preserved raw availability status
* plus the triggered-thold, failing-servcheck and session mute sets.
*
* @param array $host Host row data.
*
* @return array List of active event keys.
*/
function monitorHostEvents(array $host): array {
global $thold_hosts, $servcheck_hosts;
$raw = isset($host['raw_status']) ? (int) $host['raw_status'] : (int) $host['status'];
$muted = isset($_SESSION['monitor_muted_hosts']) && in_array($host['id'], $_SESSION['monitor_muted_hosts'], true);
$events = [];
if ($raw == 1) {
$events[] = $muted ? 'down_ma' : 'down';
} elseif ($raw == 2) {
$events[] = 'recovering';
}
if (isset($thold_hosts) && array_key_exists($host['id'], $thold_hosts)) {
$events[] = $muted ? 'triggered_ma' : 'triggered';
}
if ($raw == 3) {
if (!empty($host['monitor_alert']) && $host['cur_time'] > $host['monitor_alert']) {
$events[] = 'alert_ping';
} elseif (!empty($host['monitor_warn']) && $host['cur_time'] > $host['monitor_warn']) {
$events[] = 'warn_ping';
}
}
// A failing service check is additive and independent of ping availability:
// monitorEventFilterSql('failed_svc') matches the host regardless of its Up/
// Down state, so a Down+Failed-Svc host must still get the Failed Svc pill.
if (isset($servcheck_hosts) && array_key_exists($host['id'], $servcheck_hosts)) {
$events[] = 'failed_svc';
}
return $events;
}
/**
* Render header and sortable column bar for list view.
*
* @param int $total_rows Total rows matching active filters.
* @param int $rows Page row limit.
*
* @return string
*/
function renderHeaderList(int $total_rows = 0, int $rows = 0): string {
$display_text = [
'nosort_actions' => [
'display' => __('Actions', 'monitor'),
'align' => 'left',
'tip' => __('Open the device detail panels', 'monitor')
],
'description' => [
'display' => __('Description', 'monitor'),
'sort' => 'ASC',
'align' => 'left',
'tip' => __('Device description as set on the Devices page', 'monitor')
],
'location' => [
'display' => __('Location', 'monitor'),
'sort' => 'ASC',
'align' => 'left',
'tip' => __('Physical location recorded for the device', 'monitor')
],
'site_name' => [
'display' => __('Site', 'monitor'),
'sort' => 'ASC',
'align' => 'left',
'tip' => __('Site the device is assigned to', 'monitor')
],
'id' => [
'display' => __('ID', 'monitor'),
'sort' => 'ASC',
'align' => 'left',
'tip' => __('Cacti internal device id', 'monitor')
],
'monitor_criticality' => [
'display' => __('Criticality', 'monitor'),
'sort' => 'ASC',
'align' => 'left',
'tip' => __('Monitoring criticality assigned to the device', 'monitor')
],
'nosort_events' => [
'display' => __('Events', 'monitor'),
'align' => 'center',
'tip' => __('Active events on the device (Down, Triggered, Warn/Alert Ping, Failed Svc, ...); click a pill to add or remove that event from the Events filter', 'monitor')
],
'nosort_tholds' => [
'display' => __('Thresholds', 'monitor'),
'align' => 'center',
'tip' => __('Breached / Triggered / Total thresholds (thold plugin) on the device; click to toggle the Triggered event filter', 'monitor')
],
'nosort_servchecks' => [
'display' => __('Service Checks', 'monitor'),
'align' => 'center',
'tip' => __('Failed / Total service checks (servcheck plugin) for the device; click to toggle the Failed Svc event filter', 'monitor')
],
'monitor_warn' => [
'display' => __('Warning', 'monitor'),
'sort' => 'DESC',
'align' => 'left',
'tip' => __('Ping latency Warning / Alert thresholds (ms) configured for this device; a notification is raised when the response time crosses them', 'monitor')
],
'monitor_text' => [
'display' => __('Admin', 'monitor'),
'sort' => 'ASC',
'tip' => __('Administrative monitor message shown while the device is Down or Recovering', 'monitor'),
'align' => 'left'
],
'availability' => [
'display' => __('Availability', 'monitor'),
'sort' => 'DESC',
'align' => 'right',
'tip' => __('Percentage of successful availability checks over the retained history', 'monitor')
],
'avg_time' => [
'display' => __('Averages', 'monitor'),
'sort' => 'DESC',
'align' => 'right',
'tip' => __('Current / average ping response time in milliseconds', 'monitor')
],
'instate' => [
'display' => __('Length in Status', 'monitor'),
'sort' => 'ASC',
'align' => 'right',
'tip' => __('How long the device has been in its current status', 'monitor')
],
'status_fail_date' => [
'display' => __('Last Fail', 'monitor'),
'sort' => 'DESC',
'align' => 'right',
'tip' => __('Date and time the device last failed its availability check', 'monitor')
],
];
// Hide the Thresholds / Service Checks columns when their plugin is absent.
if (!api_plugin_is_enabled('thold')) {
unset($display_text['nosort_tholds']);
}
if (!api_plugin_is_enabled('servcheck') || !api_plugin_user_realm_auth('servcheck_test.php')) {
unset($display_text['nosort_servchecks']);
}
ob_start();
$nav = html_nav_bar('monitor.php?rfilter=' . rawurlencode(get_request_var('rfilter')), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');
html_start_box(__('Monitored Devices', 'monitor'), '100%', false, 3, 'center', '');
print $nav;
html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Indicate whether grouped section headers are suppressed for list view.
*
* @return bool
*/
function renderSuppressgroupsList(): bool {
return true;
}
/**
* Render wrapper footer for default/tile monitor views.
*
* @return string
*/
function renderFooterDefault(): string {
return '';
}
/**
* Render footer row for names view including trailing empty cells.
*
* @return string
*/
function renderFooterNames(): string {
$col = 7 - $_SESSION['names'];
if ($col == 0) {
return '
';
} else {
return '
| ';
}
}
/**
* Render wrapper footer for icon tile view.
*
* @return string
*/
function renderFooterTiles(): string {
return renderFooterDefault();
}
/**
* Render wrapper footer for advanced tile view.
*
* @return string
*/
function renderFooterTilesadt(): string {
return renderFooterDefault();
}
/**
* Render list view footer and bottom pager.
*
* @param int $total_rows Total rows matching active filters.
* @param int $rows Page row limit.
*
* @return string
*/
function renderFooterList(int $total_rows, int $rows): string {
ob_start();
html_end_box(false);
if ($total_rows > 0) {
$nav = html_nav_bar('monitor.php?rfilter=' . rawurlencode(get_request_var('rfilter')), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices'), 'page', 'main');
print $nav;
}
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Render one host row in list view.
*
* @param array $host Host row data.
*
* @return string
*/
function renderHostList(array $host): string {
global $criticalities, $iclasses, $thold_counts, $servcheck_counts, $config;
if ($host['status'] < 2 || $host['status'] == 5) {
$dt = get_timeinstate($host);
} elseif (strtotime($host['status_rec_date']) > 192800) {
$dt = get_timeinstate($host);
} else {
$dt = __('Never', 'monitor');
}
if ($host['status'] < 3 || $host['status'] == 5) {
$host_admin = $host['monitor_text'];
} else {
$host_admin = '';
}
$crit_level = isset($host['monitor_criticality']) ? (int) $host['monitor_criticality'] : 0;
if ($crit_level > 0) {
$host_crit = "
" . html_escape($criticalities[$crit_level]) . '';
} else {
$host_crit = "
" . __esc('Not Set', 'monitor') . '';
}
// Events column: a short pill for every active event (a device can have
// several, e.g. Down + Triggered); each pill toggles that event in the
// multi-select filter. A muted 'None' pill is shown when the device is clean.
$event_keys = monitorHostEvents($host);
if (cacti_sizeof($event_keys)) {
$meta = monitorEventMeta();
$pills = [];
foreach ($event_keys as $ekey) {
if (isset($meta[$ekey])) {
$pills[] = "
" . html_escape($meta[$ekey]['label']) . '';
}
}
$events_cell = implode(' ', $pills);
} else {
$events_cell = "
" . __esc('None', 'monitor') . '';
}
// Thresholds pill: breached / triggered / total (thold plugin); a muted
// 'Not Set' pill is shown when the device has no thresholds. Clicking toggles
// the Triggered event.
if (isset($thold_counts[$host['id']]) && $thold_counts[$host['id']]['total'] > 0) {
$tc = $thold_counts[$host['id']];
$tcls = ($tc['triggered'] > 0 || $tc['breached'] > 0) ? 'deviceThreshold' : 'monitorPillMuted';
$thold_cell = "
" . $tc['breached'] . ' / ' . $tc['triggered'] . ' / ' . $tc['total'] . '';
} else {
$thold_cell = "
" . __esc('Not Set', 'monitor') . '';
}
// Service checks pill: failed / total (servcheck plugin); a muted 'Not Set'
// pill is shown when the device has no service checks. Clicking toggles the
// Failed Svc event.
if (isset($servcheck_counts[$host['id']]) && $servcheck_counts[$host['id']]['total'] > 0) {
$sc = $servcheck_counts[$host['id']];
$scls = ($sc['failed'] > 0) ? 'deviceServiceCheck' : 'monitorPillMuted';
$servcheck_cell = "
" . $sc['failed'] . ' / ' . $sc['total'] . '';
} else {
$servcheck_cell = "
" . __esc('Not Set', 'monitor') . '';
}
if ($host['availability_method'] > 0) {
$host_avg = __('%d ms', $host['cur_time'], 'monitor') . ' / ' . __('%d ms', $host['avg_time'], 'monitor');
} else {
$host_avg = __('N/A', 'monitor');
}
if (isset($host['monitor_warn']) && ($host['monitor_warn'] > 0 || $host['monitor_alert'] > 0)) {
$host_warn = __('%0.2d ms', $host['monitor_warn'], 'monitor') . ' / ' . __('%0.2d ms', $host['monitor_alert'], 'monitor');
} else {
$host_warn = '';
}
if (strtotime($host['status_fail_date']) < 86400) {
$host['status_fail_date'] = __('Never', 'monitor');
}
$host_datefail = $host['status_fail_date'];
ob_start();
print "
";
$actions = "";
$actions .= "";
if (api_plugin_user_realm_auth('host.php')) {
$actions .= "";
}
form_selectable_cell($actions, $host['id'], '1%', 'left');
form_selectable_cell($host['description'], $host['id'], '', 'left');
form_selectable_cell($host['location'], $host['id'], '', 'left');
form_selectable_cell($host['site_name'], $host['id'], '', 'left');
form_selectable_cell($host['id'], $host['id'], '', 'left');
form_selectable_cell($host_crit, $host['id'], '', 'left');
form_selectable_cell($events_cell, $host['id'], '', 'center');
if (api_plugin_is_enabled('thold')) {
form_selectable_cell($thold_cell, $host['id'], '', 'center');
}
if (api_plugin_is_enabled('servcheck') && api_plugin_user_realm_auth('servcheck_test.php')) {
form_selectable_cell($servcheck_cell, $host['id'], '', 'center');
}
form_selectable_cell($host_warn, $host['id'], '', 'left');
form_selectable_cell($host_admin, $host['id'], '', 'white-space:pre-wrap;text-align:left');
form_selectable_cell(round($host['availability'], 2) . ' %', $host['id'], '', 'right');
form_selectable_cell($host_avg, $host['id'], '', 'right');
form_selectable_cell($dt, $host['id'], '', 'right');
form_selectable_cell($host_datefail, $host['id'], '', 'right');
form_end_row();
$result = ob_get_contents();
ob_end_clean();
return $result;
}
/**
* Render one host cell in names view grid.
*
* @param array $host Host row data.
*
* @return string
*/
function renderHostNames(array $host): string {
$fclass = get_request_var('size');
$result = '';
$maxlen = getMonitorTrimLength(100);
if ($_SESSION['names'] == 0) {
$result .= '
';
}
if ($host['status'] <= 2 || $host['status'] == 5) {
$result .= "| " . title_trim(html_escape($host['description']), $maxlen) . ' | ';
} else {
$result .= "" . title_trim(html_escape($host['description']), $maxlen) . ' | ';
}
$_SESSION['names']++;
if ($_SESSION['names'] > 7) {
$result .= '
';
$_SESSION['names'] = 0;
}
return $result;
}
/**
* Render one host icon tile.
*
* @param array $host Host row data.
*
* @return string
*/
function renderHostTiles(array $host): string {
$class = getStatusIcon($host['status'], $host['monitor_icon']);
$fclass = get_request_var('size');
return "
";
}
/**
* Render one advanced host tile including time-in-state/uptime text.
*
* @param array $host Host row data.
*
* @return string
*/
function renderHostTilesadt(array $host): string {
$tis = '';
$class = getStatusIcon($host['status'], $host['monitor_icon']);
$fclass = get_request_var('size');
$name = title_trim(html_escape($host['description']), 40);
if ($host['status'] < 2 || $host['status'] == 5) {
$tis = get_timeinstate($host);
return "
";
} else {
$tis = get_uptime($host);
return "
";
}
}
/**
* Apply monitor trim setting to a computed source field length.
*
* @param int $fieldlen Initial field length.
*
* @return int
*/
function getMonitorTrimLength(int $fieldlen): int {
global $maxchars;
if (get_request_var('view') == 'default' || get_request_var('view') == 'names') {
$maxlen = $maxchars;
if (get_request_var('trim') < 0) {
$maxlen = 4000;
} elseif (get_request_var('trim') > 0) {
$maxlen = get_request_var('trim');
}
if ($fieldlen > $maxlen) {
$fieldlen = $maxlen;
}
}
return $fieldlen;
}