'> '> '>
'>
action * label, used for the bulk-actions * dropdown. * @global array $item_rows Default number of rows per page from * Cacti settings. * @global array $thold_classes Reserved/declared for parity with * other functions in this file; not used * directly here. * @global array $thold_states Threshold state option list used by * the filter form. */ function tholds() { global $config, $device_actions, $item_rows, $thold_classes, $thold_states; $default_status = read_config_option('thold_filter_default'); if (!is_numeric($default_status)) { set_config_option('thold_filter_default', '-1'); $default_status = '-1'; } // ================= input validation and session storage ================= $filters = [ 'rows' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'page' => [ 'filter' => FILTER_VALIDATE_INT, 'default' => '1' ], 'rfilter' => [ 'filter' => FILTER_VALIDATE_IS_REGEX, 'pageset' => true, 'default' => '' ], 'sort_column' => [ 'filter' => FILTER_CALLBACK, 'default' => 'name_cache', 'options' => ['options' => 'sanitize_thold_sort_string'] ], 'sort_direction' => [ 'filter' => FILTER_CALLBACK, 'default' => 'ASC', 'options' => ['options' => 'sanitize_search_string'] ], 'data_template_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'thold_template_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'host_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'site_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'state' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => $default_status ] ]; validate_store_request_vars($filters, 'sess_thold'); // ================= input validation ================= // if the number of rows is -1, set it to the default if (get_request_var('rows') == -1) { $rows = intval(read_config_option('num_rows_table')); } else { $rows = intval(get_request_var('rows')); } html_start_box(__('Threshold Status', 'thold'), '100%', false, '3', 'center', ''); form_thold_filter(); html_end_box(); $sql_order = get_order_string(); $sql_limit = ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; $sql_order = str_replace('ORDER BY ', '', $sql_order); if (get_request_var('sort_column') == 'severity') { $sql_order = thold_severity_sql() . ' ' . (get_request_var('sort_direction') == 'DESC' ? 'DESC' : 'ASC'); } $sql_where = '(h.status = 3'; $statefilter = thold_get_state_filter(get_request_var('state')); if (get_request_var('rfilter') != '') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'td.name_cache ' . thold_rlike_clause(get_request_var('rfilter')); } if (get_request_var('data_template_id') != '-1') { $sql_where .= ($sql_where == '' ? '(' : ' AND') . ' td.data_template_id = ' . get_request_var('data_template_id'); } if (!isempty_request_var('thold_template_id')) { if (get_request_var('thold_template_id') > 0) { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . '(td.thold_template_id = ' . get_request_var('thold_template_id') . ' AND td.template_enabled = "on")'; } elseif (get_request_var('thold_template_id') == '-2') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . '(td.template_enabled != "on")'; } } if (get_request_var('host_id') != '-1') { $sql_where .= ($sql_where == '' ? '(' : ' AND') . ' td.host_id = ' . get_request_var('host_id'); } if ($statefilter != '') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . $statefilter; } if (get_request_var('site_id') == '-1') { // Show all items } elseif (get_request_var('site_id') == '0') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.site_id IS NULL'; } elseif (!isempty_request_var('site_id')) { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.site_id = ' . get_request_var('site_id'); } if ($sql_where != '') { $sql_where .= ')'; } $tholds = get_allowed_thresholds($sql_where, $sql_order, $sql_limit, $total_rows); $nav = html_nav_bar('thold_graph.php?action=thold', MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 13, 'Thresholds', 'page', 'main'); print $nav; html_start_box('', '100%', false, '3', 'center', ''); $display_text = [ 'nosort' => [ 'display' => __('Actions', 'thold'), 'sort' => '', 'align' => 'left' ], 'name_cache' => [ 'display' => __('Name', 'thold'), 'sort' => 'ASC', 'align' => 'left' ], 'severity' => [ 'display' => __('Status', 'thold'), 'sort' => 'ASC', 'align' => 'left', 'tip' => __('The current threshold status. Click a status pill to filter the list to that status.', 'thold') ], 'external_id' => [ 'display' => __('External ID', 'thold'), 'sort' => 'ASC', 'align' => 'left' ], 'nosort99' => [ 'display' => __('Enabled', 'thold'), 'align' => 'right' ], 'id' => [ 'display' => __('ID', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'nosort6' => [ 'display' => __('Ack Detail', 'thold'), 'align' => 'center' ], 'thold_type' => [ 'display' => __('Type', 'thold'), 'sort' => 'ASC', 'tip' => __('The Threshold Type. For Baseline Types: [TIP] refers to the Time In the Past with MIN, MAX, AVG, and LAST from no more than a day in time from that period. [AOT] refers to the Average over the entire Time period. If there is a colon followed by MIN, MAX, AVG, LAST, the Value came from that Consolidation Function.', 'thold'), 'align' => 'right' ], 'flastread' => [ 'display' => __('Current', 'thold'), 'sort' => 'ASC', 'align' => 'right', 'tip' => __('The last measured value for the Data Source', 'thold') ], 'nosort4' => [ 'display' => __('High', 'thold'), 'sort' => 'ASC', 'align' => 'right', 'tip' => __('The High Warning / Alert values. NOTE: Baseline values are a percent, all other values are display values that may be modified by a cdef.', 'thold') ], 'nosort5' => [ 'display' => __('Low', 'thold'), 'sort' => 'ASC', 'align' => 'right', 'tip' => __('The Low Warning / Alert values. NOTE: Baseline values are a percent, all other values are display values that may be modified by a cdef.', 'thold') ], 'nosort2' => [ 'display' => __('Trigger', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'nosort3' => [ 'display' => __('Duration', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'repeat_alert' => [ 'display' => __('Repeat', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'thold_alert' => [ 'display' => __('Triggered', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'instate' => [ 'display' => __('In State', 'thold'), 'sort' => 'DESC', 'align' => 'right', 'tip' => __('The amount of time that has passed since the Threshold either Breached or was Triggered', 'thold') ], 'acknowledgment' => [ 'display' => __('Ack Required', 'thold'), 'sort' => 'ASC', 'align' => 'right', 'tip' => __('Acknowledgment required for this Threshold', 'thold') ] ]; html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false, 'thold_graph.php?action=thold'); $c = 0; if (cacti_sizeof($tholds)) { foreach ($tholds as $thold_data) { $step = db_fetch_cell_prepared('SELECT rrd_step FROM data_template_data WHERE local_data_id = ?', [$thold_data['local_data_id']]); include($config['base_path'] . '/plugins/thold/includes/arrays.php'); $c++; $alertstat = __('No', 'thold'); $bgcolor = 'green'; $severity = get_thold_severity($thold_data); switch($severity) { case THOLD_SEVERITY_DISABLED: $bgcolor = 'grey'; break; case THOLD_SEVERITY_NORMAL: $bgcolor = 'green'; break; case THOLD_SEVERITY_ALERT: $bgcolor = 'red'; break; case THOLD_SEVERITY_WARNING: $bgcolor = 'warning'; break; case THOLD_SEVERITY_BASELINE: $bgcolor = 'orange'; break; case THOLD_SEVERITY_NOTICE: $bgcolor = 'yellow'; break; case THOLD_SEVERITY_ACKREQ: $bgcolor = 'purple'; break; } if ($thold_data['thold_type'] == 0) { if ($thold_data['thold_alert'] != 0) { $alertstat = __('Yes', 'thold'); } } elseif ($thold_data['thold_type'] == 2) { if ($thold_data['thold_alert'] != 0) { $alertstat = __('Yes', 'thold'); } } else { if ($thold_data['bl_alert'] == 1) { $alertstat = __('baseline-LOW', 'thold'); } elseif ($thold_data['bl_alert'] == 2) { $alertstat = __('baseline-HIGH', 'thold'); } } print ""; $baseu = db_fetch_cell_prepared('SELECT base_value FROM graph_templates_graph WHERE local_graph_id = ?', [$thold_data['local_graph_id']]); if ($thold_data['data_type'] == 2) { $suffix = false; } else { $suffix = true; } $show_units = ($thold_data['show_units'] ? true : false); $units_suffix = $thold_data['units_suffix']; $decimals = $thold_data['decimals']; if (empty($baseu)) { cacti_log('WARNING: Graph Template for local_graph_id ' . $thold_data['local_graph_id'] . ' has been removed!'); $baseu = 1024; } // Check is the graph item has a cdef and modify the output thold_modify_values_by_cdef($thold_data); $actions_url = ''; if (api_user_realm_auth('thold.php')) { $actions_url .= ''; } if (api_user_realm_auth('thold.php')) { if ($thold_data['thold_per_enabled'] == 'on') { $actions_url .= ''; } elseif ((($thold_data['template_enabled'] == 'on' && $thold_data['thold_enabled'] == 'on') || $thold_data['template_enabled'] != 'on') && $thold_data['thold_per_enabled'] == '') { $actions_url .= ''; } else { $actions_url .= ''; } } thold_get_cached_name($thold_data); $actions_url .= ""; $actions_url .= ""; if (api_user_realm_auth('thold.php')) { if ($thold_data['acknowledgment'] == 'on') { $actions_url .= ""; if ($thold_data['reset_ack'] == 'on') { $actions_url .= ""; } } elseif ($thold_data['thold_alert'] > 0 && $thold_data['reset_ack'] == 'on') { $actions_url .= ""; } } $data = [ 'thold_data' => $thold_data, 'actions_url' => $actions_url ]; $data = api_plugin_hook_function('thold_graph_actions_url', $data); if (isset($data['actions_url'])) { $actions_url = $data['actions_url']; } if ($thold_data['reset_ack'] == 'on' || $thold_data['persist_ack'] == 'on') { $acks = db_fetch_assoc_prepared('SELECT * FROM plugin_thold_log WHERE type = 99 AND threshold_id = ? LIMIT 5', [$thold_data['id']]); if (cacti_sizeof($acks)) { $table = ''; foreach ($acks as $a) { $parts = explode('Additional Comments:', $a['description']); if (isset($parts[1])) { $comment = trim($parts[1], '" '); } else { $comment = __('Comment Not Found', 'thold'); } $table .= ''; } $details = '' . __('Ack History', 'thold') . ''; } else { $details = ''; } } else { $details = ''; } form_selectable_cell($actions_url, $thold_data['id'], '', 'left'); form_selectable_cell($thold_data['name_cache'] != '' ? filter_value($thold_data['name_cache'], get_request_var('rfilter')) : __('No name set', 'thold'), $thold_data['id'], '', 'left'); form_selectable_cell(" 101, 'orange' => 102, 'warning' => 103, 'yellow' => 104, 'green' => 105, 'purple' => 106, 'grey' => 107][$bgcolor] . "' tabindex='0' role='button'>" . html_escape($thold_states[$bgcolor]['display']) . '', $thold_data['id'], '', 'left'); form_selectable_cell($thold_data['external_id'], $thold_data['id'], '', 'left'); if ((($thold_data['template_enabled'] == 'on' && $thold_data['thold_enabled'] == 'on') || $thold_data['template_enabled'] != 'on') && $thold_data['thold_per_enabled'] == 'on') { $enabled = __('Yes', 'thold'); } elseif ($thold_data['template_enabled'] == 'on' && $thold_data['thold_enabled'] == 'off' && $thold_data['thold_per_enabled'] == '') { $enabled = __('No [Template:Thold]', 'thold'); } elseif ($thold_data['template_enabled'] == 'on' && $thold_data['thold_enabled'] == 'off') { $enabled = __('No [Template]', 'thold'); } else { $enabled = __('No [Thold]', 'thold'); } form_selectable_cell($enabled, $thold_data['id'], '', 'right'); form_selectable_cell($thold_data['id'], $thold_data['id'], '', 'right'); form_selectable_cell($details, $thold_data['id'], '', 'center'); if ($thold_data['thold_type'] != 1) { form_selectable_cell($thold_types[$thold_data['thold_type']], $thold_data['id'], '', 'right'); } else { $bl_type = get_bl_type($thold_data['bl_type'], $thold_data['bl_cf']); form_selectable_cell($bl_type, $thold_data['id'], '', 'right'); } form_selectable_cell(thold_format_number($thold_data['lastread'], $decimals, $baseu, $suffix, $show_units, $units_suffix), $thold_data['id'], '', 'right'); switch($thold_data['thold_type']) { case 0: form_selectable_cell(thold_format_number($thold_data['thold_warning_hi'], $decimals, $baseu, $suffix, $show_units, $units_suffix) . ' / ' . thold_format_number($thold_data['thold_hi'], $decimals, $baseu, $suffix, $show_units, $units_suffix), $thold_data['id'], '', 'right'); form_selectable_cell(thold_format_number($thold_data['thold_warning_low'], $decimals, $baseu, $suffix, $show_units, $units_suffix) . ' / ' . thold_format_number($thold_data['thold_low'], $decimals, $baseu, $suffix, $show_units, $units_suffix), $thold_data['id'], '', 'right'); form_selectable_cell('' . plugin_thold_duration_convert($thold_data['local_data_id'], $thold_data['thold_fail_trigger'], 'alert') . '', $thold_data['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $thold_data['id'], '', 'right'); break; case 1: $hi = thold_format_number($thold_data['thold_hi'], $decimals, $baseu, $suffix, $show_units, $units_suffix); $hi_var = thold_format_number($thold_data['bl_pct_up'], $decimals, $baseu, $suffix, $show_units, $units_suffix); $low = thold_format_number($thold_data['thold_low'], $decimals, $baseu, $suffix, $show_units, $units_suffix); $low_var = thold_format_number($thold_data['bl_pct_down'], $decimals, $baseu, $suffix, $show_units, $units_suffix); if ($thold_data['bl_type'] == 0 || $thold_data['bl_type'] == 2) { $suffix = ' %'; } else { $suffix = ''; } form_selectable_cell($hi != '' ? $hi . ' [ ' . $hi_var . " $suffix ]" : '-', $thold_data['id'], '', 'right'); form_selectable_cell($low != '' ? $low . ' [ ' . $low_var . " $suffix ]" : '-', $thold_data['id'], '', 'right'); form_selectable_cell('' . plugin_thold_duration_convert($thold_data['local_data_id'], $thold_data['bl_fail_trigger'], 'alert') . '', $thold_data['id'], '', 'right'); form_selectable_cell($timearray[$thold_data['bl_ref_time_range'] / $thold_data['rrd_step']], $thold_data['id'], '', 'right'); break; case 2: form_selectable_cell(thold_format_number($thold_data['time_warning_hi'], $decimals, $baseu, $suffix, $show_units, $units_suffix) . ' / ' . thold_format_number($thold_data['time_hi'], $decimals, $baseu, $suffix, $show_units, $units_suffix), $thold_data['id'], '', 'right'); form_selectable_cell(thold_format_number($thold_data['time_warning_low'], $decimals, $baseu, $suffix, $show_units, $units_suffix) . ' / ' . thold_format_number($thold_data['time_low'], $decimals, $baseu, $suffix, $show_units, $units_suffix), $thold_data['id'], '', 'right'); form_selectable_cell('' . __('%d Triggers', $thold_data['time_fail_trigger'], 'thold') . '', $thold_data['id'], '', 'right'); form_selectable_cell('' . plugin_thold_duration_convert($thold_data['local_data_id'], $thold_data['time_fail_length'], 'time') . '', $thold_data['id'], '', 'right'); break; default: form_selectable_cell('- / -', $thold_data['id'], '', 'right'); form_selectable_cell('- / -', $thold_data['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $thold_data['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $thold_data['id'], '', 'right'); } form_selectable_cell(($thold_data['repeat_alert'] == '' ? '' : plugin_thold_duration_convert($thold_data['local_data_id'], $thold_data['repeat_alert'], 'repeat')), $thold_data['id'], '', 'right'); form_selectable_cell($alertstat, $thold_data['id'], '', 'right'); // The time since this threshold was triggered form_selectable_cell('' . get_time_since_last_event($thold_data) . '', $thold_data['id'], '', 'right'); form_selectable_cell(($thold_data['acknowledgment'] == '' ? __('No', 'thold') : __('Yes', 'thold')), $thold_data['id'], '', 'right ' . ($thold_data['acknowledgment'] == '' ? '' : 'tholdAckCol')); form_end_row(); } } else { print ''; } html_end_box(false); if (cacti_sizeof($tholds)) { print $nav; } print '
'; thold_legend(); print '
'; // thold_display_rusage(); } /** * Builds a clickable status "pill" for a device-status-list row, using a * CSS class derived from the host's disabled flag, current status, and * (when a per-host failure-count override is set) whether its * consecutive down-event count has reached that threshold. The pill's * data-state maps to the Device Status filter so clicking it filters the * list to that status. * * @param array &$host The host record to build the status pill for. * * @return string The status pill markup. * * @global array $thold_host_states Map of status/state key => display * info (including 'class') used to pick * the pill's colour class. */ function thold_device_status_pill(&$host) { global $thold_host_states; $status = $host['status']; if ($host['disabled']) { $key = 'disabled'; } elseif ($host['thold_failure_count'] > 0 && $status != HOST_RECOVERING && $host['status_event_count'] >= $host['thold_failure_count']) { $key = HOST_DOWN; } elseif (isset($thold_host_states[$status])) { $key = $status; } else { $key = HOST_UNKNOWN; } // Each state maps to its matching Device Status filter (host_status) value. $state_map = [ HOST_DOWN => '1', HOST_RECOVERING => '2', HOST_UP => '3', HOST_UNKNOWN => '0', HOST_ERROR => '4', 'disabled' => '-2' ]; $state = isset($state_map[$key]) ? $state_map[$key] : '-1'; return "" . html_escape(get_uncolored_device_status($host)) . ''; } /** * Determines a human-readable status label for a host (Disabled, Down, * Recovering, Up, Error, or Unknown), applying the same per-host * failure-count override logic as thold_device_status_pill() but * without any HTML/color output. * * @param array &$host The host record to determine the status label * for. * * @return string The human-readable, translated status label. */ function get_uncolored_device_status(&$host) { $disabled = $host['disabled']; $status = $host['status']; if ($disabled) { return __('Disabled', 'thold'); } else { if ($host['thold_failure_count'] > 0 && $host['status'] != HOST_RECOVERING) { if ($host['status_event_count'] >= $host['thold_failure_count']) { return __('Down', 'thold'); } } switch ($status) { case HOST_DOWN: return __('Down', 'thold'); break; case HOST_RECOVERING: return __('Recovering', 'thold'); break; case HOST_UP: return __('Up', 'thold'); break; case HOST_ERROR: return __('Error', 'thold'); break; default: return __('Unknown', 'thold'); break; } } } /** * Renders the device status list view: validates/stores this view's * filter request variables, displays the host filter form, then * displays a filtered, sorted, paginated table of hosts with their * current up/down/recovering status. Called from this script's main * request-dispatch switch when action=hoststat. * * @return void * * @global array $config Cacti global configuration array. * @global array $device_actions Map of drp_action value => action * label, used for the bulk-actions * dropdown. * @global array $item_rows Default number of rows per page from * Cacti settings. */ function hosts() { global $config, $device_actions, $item_rows; // ================= input validation and session storage ================= $filters = [ 'rows' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'page' => [ 'filter' => FILTER_VALIDATE_INT, 'default' => '1' ], 'rfilter' => [ 'filter' => FILTER_VALIDATE_IS_REGEX, 'pageset' => true, 'default' => '' ], 'sort_column' => [ 'filter' => FILTER_CALLBACK, 'default' => 'description', 'options' => ['options' => 'sanitize_thold_sort_string'] ], 'sort_direction' => [ 'filter' => FILTER_CALLBACK, 'default' => 'ASC', 'options' => ['options' => 'sanitize_search_string'] ], 'site_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'host_template_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'host_status' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-4' ] ]; validate_store_request_vars($filters, 'sess_thold_hstatus'); // ================= input validation ================= // if the number of rows is -1, set it to the default if (get_request_var('rows') == -1) { $rows = read_config_option('num_rows_table'); } else { $rows = get_request_var('rows'); } html_start_box(__('Device Status', 'thold'), '100%', false, '3', 'center', ''); form_host_filter(); html_end_box(); // form the 'where' clause for our main sql query $sql_where = ''; if (get_request_var('rfilter') != '') { $sql_where .= " (h.deleted = '' AND (h.hostname " . thold_rlike_clause(get_request_var('rfilter')) . ' OR h.description ' . thold_rlike_clause(get_request_var('rfilter')) . ')'; } if (get_request_var('host_status') == '-1') { // Show all items } elseif (get_request_var('host_status') == '-2') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . "h.disabled = 'on'"; } elseif (get_request_var('host_status') == '-3') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . "h.disabled = ''"; } elseif (get_request_var('host_status') == '-4') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . "(h.status != '3' OR h.disabled = 'on')"; } elseif (get_request_var('host_status') == '-5') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . '(h.availability_method = 0)'; } else { // Match the exact state-classification rules used by thold_device_status_pill(): // a per-host failure-count override (status_event_count >= thold_failure_count, excluding // Recovering) reclassifies the device as Down, so the Down filter includes those hosts and // the Up/Unknown/Error filters exclude them. $override_down = 'h.thold_failure_count > 0 AND h.status != ' . HOST_RECOVERING . ' AND h.status_event_count >= h.thold_failure_count'; if (get_request_var('host_status') == HOST_DOWN) { $status_clause = '(h.status = ' . HOST_DOWN . " OR ($override_down))"; } elseif (get_request_var('host_status') == HOST_RECOVERING) { $status_clause = 'h.status = ' . HOST_RECOVERING; } else { $status_clause = 'h.status = ' . get_request_var('host_status') . " AND NOT ($override_down)"; } $sql_where .= ($sql_where == '' ? '(' : ' AND ') . "(h.availability_method != 0 AND h.disabled = '' AND $status_clause)"; } if (get_request_var('host_template_id') == '-1') { // Show all items } elseif (get_request_var('host_template_id') == '0') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.host_template_id = 0'; } elseif (!isempty_request_var('host_template_id')) { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.host_template_id = ' . get_request_var('host_template_id'); } if (get_request_var('site_id') == '-1') { // Show all items } elseif (get_request_var('site_id') == '0') { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.site_id = 0'; } elseif (!isempty_request_var('site_id')) { $sql_where .= ($sql_where == '' ? '(' : ' AND ') . 'h.site_id = ' . get_request_var('site_id'); } $sql_where .= ($sql_where != '' ? ')' : ''); $sql_order = get_order_string(); $sql_limit = ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; $sql_order = str_replace('ORDER BY ', '', $sql_order); $hosts = thold_get_allowed_devices($sql_where, $sql_order, $sql_limit, $total_rows); $nav = html_nav_bar('thold_graph.php?action=hoststat', MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 12, __('Devices', 'thold'), 'page', 'main'); print $nav; html_start_box('', '100%', false, '3', 'center', ''); $display_text = [ 'nosort' => [ 'display' => __('Actions', 'thold'), 'align' => 'left', 'sort' => '', 'tip' => __('Hover over icons for help', 'thold') ], 'description' => [ 'display' => __('Description', 'thold'), 'align' => 'left', 'sort' => 'ASC', 'tip' => __('A description for the Device', 'thold') ], 'id' => [ 'display' => __('ID', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('A Cacti unique identifier for the Device', 'thold') ], 'graphs' => [ 'display' => __('Graphs', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The number of Graphs for this Device', 'thold') ], 'data_sources' => [ 'display' => __('Data Sources', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The number of Data Sources for this Device', 'thold') ], 'status' => [ 'display' => __('Status', 'thold'), 'align' => 'center', 'sort' => 'ASC', 'tip' => __('The status for this Device as of the last time it was polled', 'thold') ], 'instate' => [ 'display' => __('In State', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The last time Cacti found an issue with this Device. It can be higher than the Uptime for the Device, if it was rebooted between Cacti polling cycles', 'thold') ], 'snmp_sysUpTimeInstance' => [ 'display' => __('Uptime', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The official uptime of the Device as reported by SNMP', 'thold') ], 'hostname' => [ 'display' => __('Hostname', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The official hostname for this Device', 'thold') ], 'cur_time' => [ 'display' => __('Current (ms)', 'thold'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The current response time for the Cacti Availability check', 'thold') ], 'avg_time' => [ 'display' => __('Average (ms)', 'thold'), 'align' => 'right', 'sort' => 'DESC', 'tip' => __('The average response time for the Cacti Availability check', 'thold') ], 'availability' => [ 'display' => __('Availability', 'thold'), 'align' => 'right', 'sort' => 'ASC', 'tip' => __('The overall Availability of this Device since the last counter reset in Cacti', 'thold') ] ]; html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false, 'thold_graph.php?action=hoststat'); if (cacti_sizeof($hosts)) { foreach ($hosts as $host) { if ($host['disabled'] == '' && ($host['status'] == HOST_RECOVERING || $host['status'] == HOST_UP) && ($host['availability_method'] != AVAIL_NONE && $host['availability_method'] != AVAIL_PING)) { $snmp_uptime = $host['snmp_sysUpTimeInstance']; $days = intval($snmp_uptime / (60 * 60 * 24 * 100)); $remainder = $snmp_uptime % (60 * 60 * 24 * 100); $hours = intval($remainder / (60 * 60 * 100)); $remainder = $remainder % (60 * 60 * 100); $minutes = intval($remainder / (60 * 100)); $uptime = $days . 'd:' . substr('00' . $hours, -2) . 'h:' . substr('00' . $minutes, -2) . 'm'; } else { $uptime = __('N/A', 'thold'); } if ($host['availability_method'] != 0) { print ""; $actions_url = ''; if (api_user_realm_auth('host.php')) { $actions_url .= ''; } $actions_url .= ""; form_selectable_cell($actions_url, $host['id'], '', 'left'); form_selectable_cell(filter_value($host['description'], get_request_var('rfilter')), $host['id'], '', 'left'); form_selectable_cell(number_format_i18n($host['id'], -1), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n($host['graphs'], -1), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n($host['data_sources'], -1), $host['id'], '', 'right'); form_selectable_cell(thold_device_status_pill($host), $host['id'], '', 'center'); form_selectable_cell(get_timeinstate($host), $host['id'], '', 'right'); form_selectable_cell($uptime, $host['id'], '', 'right'); form_selectable_cell(filter_value($host['hostname'], get_request_var('rfilter')), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n(($host['cur_time']), 2), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n(($host['avg_time']), 2), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n($host['availability'], 2), $host['id'], '', 'right'); } else { print ""; $actions_url = ''; if (api_user_realm_auth('host.php')) { $actions_url .= ''; } $actions_url .= ""; form_selectable_cell($actions_url, $host['id'], '', 'left'); form_selectable_cell(filter_value($host['description'], get_request_var('rfilter')), $host['id'], '', 'left'); form_selectable_cell(number_format_i18n($host['id'], -1), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n($host['graphs'], -1), $host['id'], '', 'right'); form_selectable_cell(number_format_i18n($host['data_sources'], -1), $host['id'], '', 'right'); form_selectable_cell("" . __esc('Not Monitored', 'thold') . '', $host['id'], '', 'center'); form_selectable_cell(__('N/A', 'thold'), $host['id'], '', 'right'); form_selectable_cell($uptime, $host['id'], '', 'right'); form_selectable_cell(filter_value($host['hostname'], get_request_var('rfilter')), $host['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $host['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $host['id'], '', 'right'); form_selectable_cell(__('N/A', 'thold'), $host['id'], '', 'right'); } form_end_row(); } } else { print ''; } html_end_box(false); if (cacti_sizeof($hosts)) { print $nav; } print '
'; host_legend(); print '
'; // thold_display_rusage(); } /** * Renders the search/site filter form controls for the device status * list view. * * @return void * * @global array $item_rows Rows-per-page option list used to populate * the rows dropdown. * @global array $config Cacti global configuration array (declared * but not used directly here). */ function form_host_filter() { global $item_rows, $config; ?> [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'page' => [ 'filter' => FILTER_VALIDATE_INT, 'default' => '1' ], 'rfilter' => [ 'filter' => FILTER_VALIDATE_IS_REGEX, 'pageset' => true, 'default' => '' ], 'sort_column' => [ 'filter' => FILTER_CALLBACK, 'default' => 'time', 'options' => ['options' => 'sanitize_thold_sort_string'] ], 'sort_direction' => [ 'filter' => FILTER_CALLBACK, 'default' => 'DESC', 'options' => ['options' => 'sanitize_search_string'] ], 'threshold_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'thold_template_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'host_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'site_id' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ], 'status' => [ 'filter' => FILTER_VALIDATE_INT, 'pageset' => true, 'default' => '-1' ] ]; validate_store_request_vars($filters, 'sess_thold_log'); // ================= input validation ================= } /** * Exports the current filtered threshold log entries (up to 100000 * rows) as a downloaded CSV file. Called from this script's main * request-dispatch switch when action=logexport. * * @return void */ function thold_export_log() { $sql_where = ''; thold_validate_log_vars(); if (get_request_var('host_id') == '-1') { // Show all items } elseif (get_request_var('host_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.id IS NULL'; } elseif (!isempty_request_var('host_id')) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.host_id=' . get_request_var('host_id'); } if (get_request_var('site_id') == '-1') { // Show all items } elseif (get_request_var('site_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.site_id IS NULL'; } elseif (!isempty_request_var('site_id')) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.site_id=' . get_request_var('site_id'); } if (get_request_var('threshold_id') == '-1') { // Show all items } elseif (get_request_var('threshold_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' td.id IS NULL'; } elseif (get_request_var('threshold_id') > 0) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' td.id=' . get_request_var('threshold_id'); } // thold template id filter if (!isempty_request_var('thold_template_id')) { if (get_request_var('thold_template_id') > 0) { $sql_where .= ($sql_where == '' ? '' : ' AND ') . '(td.thold_template_id = ' . get_request_var('thold_template_id') . ' AND td.template_enabled = "on")'; } elseif (get_request_var('thold_template_id') == '-2') { $sql_where .= ($sql_where == '' ? '' : ' AND ') . '(td.template_enabled != "on")'; } } if (get_request_var('status') != '-1') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.status=' . get_request_var('status'); } if (get_request_var('rfilter') != '') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.description ' . thold_rlike_clause(get_request_var('rfilter')); } $sql_order = ''; $total_rows = 0; $logs = get_allowed_threshold_logs($sql_where, $sql_order, 100000, $total_rows); if (sizeof($logs)) { $columns = array_keys($logs[0]); header('Content-type: application/csv'); header('Content-Disposition: attachment; filename=thold_log_export.csv'); print implode(',', $columns) . PHP_EOL; foreach ($logs as $log) { print implode(',', array_values($log)) . PHP_EOL; } } else { raise_message('norows', __('No Export Rows Found.', 'thold'), MESSAGE_LEVEL_ERROR); header('Location: thold_graph.php?action=log'); exit; } } /** * Renders the main threshold log list page: validates/stores this * view's filter request variables, displays the log filter form, then * displays a filtered, sorted, paginated table of threshold log * entries. Called from this script's main request-dispatch switch when * action=log. * * @return void * * @global array $config Cacti global configuration * array. * @global array $item_rows Default number of rows per page * from Cacti settings. * @global array $thold_log_states Log status option list used by * the filter form. * @global array $thold_status Reserved/declared for parity with * other functions in this file; not * used directly here. * @global array $thold_types Map of log entry type id => label, * used to render each log row's * type column ('Acknowledgment' * added here for type 99). * @global int $thold_log_retention Reserved/declared for parity with * other functions in this file; not * used directly here. */ function thold_show_log() { global $config, $item_rows, $thold_log_states, $thold_status, $thold_types, $thold_log_retention; thold_validate_log_vars(); // if the number of rows is -1, set it to the default if (get_request_var('rows') == -1) { $rows = read_config_option('num_rows_table'); } else { $rows = get_request_var('rows'); } $days = read_config_option('thold_log_storage'); if (empty($days)) { set_config_option('thold_log_storage', '31'); $days = 31; } $days = __('%d Days', $days, 'thold'); html_start_box(__('Threshold Log for [ %s ]', $days, 'thold'), '100%', false, '3', 'center', ''); form_thold_log_filter(); html_end_box(); $sql_where = ''; if (get_request_var('host_id') == '-1') { // Show all items } elseif (get_request_var('host_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.id IS NULL'; } elseif (!isempty_request_var('host_id')) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.host_id = ' . get_request_var('host_id'); } if (get_request_var('site_id') == '-1') { // Show all items } elseif (get_request_var('site_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.site_id IS NULL'; } elseif (!isempty_request_var('site_id')) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' h.site_id = ' . get_request_var('site_id'); } if (get_request_var('threshold_id') == '-1') { // Show all items } elseif (get_request_var('threshold_id') == '0') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' td.id IS NULL'; } elseif (get_request_var('threshold_id') > 0) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' td.id = ' . get_request_var('threshold_id'); } // thold template id filter if (!isempty_request_var('thold_template_id')) { if (get_request_var('thold_template_id') > 0) { $sql_where .= ($sql_where == '' ? '' : ' AND ') . '(td.thold_template_id = ' . get_request_var('thold_template_id') . ' AND td.template_enabled = "on")'; } elseif (get_request_var('thold_template_id') == '-2') { $sql_where .= ($sql_where == '' ? '' : ' AND ') . '(td.template_enabled != "on")'; } } if (get_request_var('status') != '-1') { if (get_request_var('status') == 2) { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.status IN (2,8)'; } else { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.status = ' . get_request_var('status'); } } if (get_request_var('rfilter') != '') { $sql_where .= ($sql_where == '' ? '' : ' AND') . ' tl.description ' . thold_rlike_clause(get_request_var('rfilter')); } $sql_order = get_order_string(); $sql_limit = ($rows * (intval(get_request_var('page')) - 1)) . ',' . $rows; $sql_order = str_replace('ORDER BY ', '', $sql_order); $logs = get_allowed_threshold_logs($sql_where, $sql_order, $sql_limit, $total_rows); $nav = html_nav_bar('thold_graph.php?action=log', MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 9, __('Log Entries', 'thold'), 'page', 'main'); print $nav; html_start_box('', '100%', false, '3', 'center', ''); $display_text = [ 'hdescription' => [ 'display' => __('Device', 'thold'), 'sort' => 'ASC', 'align' => 'left' ], 'time' => [ 'display' => __('Time', 'thold'), 'sort' => 'ASC', 'align' => 'left' ], 'type' => [ 'display' => __('Type', 'thold'), 'sort' => 'DESC', 'align' => 'left' ], 'status' => [ 'display' => __('Status', 'thold'), 'sort' => '', 'align' => 'left' ], 'description' => [ 'display' => __('Event Description', 'thold'), 'sort' => 'ASC', 'align' => 'left' ], 'threshold_value' => [ 'display' => __('Alert Value', 'thold'), 'sort' => 'ASC', 'align' => 'right' ], 'current' => [ 'display' => __('Measured Value', 'thold'), 'sort' => 'ASC', 'align' => 'right' ] ]; html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false, 'thold_graph.php?action=log'); $thold_types[99] = __('Acknowledgment', 'thold'); if (cacti_sizeof($logs)) { foreach ($logs as $l) { if ($l['status'] == 8) { $l['status'] = 2; } $baseu = db_fetch_cell_prepared('SELECT base_value FROM graph_templates_graph WHERE local_graph_id = ?', [$l['local_graph_id']]); $data_type = db_fetch_cell_prepared('SELECT data_type FROM thold_data WHERE id = ?', [$l['threshold_id']]); if ($data_type == 2) { $suffix = false; } else { $suffix = true; } $show_units = (db_fetch_cell_prepared('SELECT show_units FROM thold_data WHERE id = ?', [$l['threshold_id']]) ? true : false); $units_suffix = db_fetch_cell_prepared('SELECT units_suffix FROM thold_data WHERE id = ?', [$l['threshold_id']]); $decimals = db_fetch_cell_prepared('SELECT decimals FROM thold_data WHERE id = ?', [$l['threshold_id']]); if (empty($baseu)) { cacti_log('WARNING: Graph Template for local_graph_id ' . $l['local_graph_id'] . ' has been removed!'); $baseu = 1024; } print ""; form_selectable_cell($l['hdescription'], $l['id'], '', 'left'); form_selectable_cell(date('Y-m-d H:i:s', $l['time']), $l['id'], '', 'left'); form_selectable_cell($thold_types[$l['type']], $l['id'], '', 'left'); form_selectable_cell("" . html_escape($thold_log_states[$l['status']]['display_short']) . '', $l['id'], '', 'left'); form_selectable_cell((strlen($l['description']) ? filter_value($l['description'], get_request_var('rfilter')) : __('Restoral Event', 'thold')), $l['id'], '', 'left tholdLog'); form_selectable_cell($l['threshold_value'] != '' ? thold_format_number($l['threshold_value'], $decimals, $baseu, $suffix, $show_units, $units_suffix) : __('N/A', 'thold'), $l['id'], '', 'right'); form_selectable_cell($l['current'] != '' ? thold_format_number($l['current'], $decimals, $baseu, $suffix, $show_units, $units_suffix) : __('N/A', 'thold'), $l['id'], '', 'right'); form_end_row(); } } else { print ''; } html_end_box(false); if (cacti_sizeof($logs)) { print $nav; } print '
'; log_legend(); print '
'; } /** * Renders the search/site/status/host/template filter form controls for * the threshold log list view. * * @return void * * @global array $item_rows Rows-per-page option list used to * populate the rows dropdown. * @global array $thold_log_states Log status option list used to * populate the status dropdown. * @global array $config Cacti global configuration array * (declared but not used directly * here). */ function form_thold_log_filter() { global $item_rows, $thold_log_states, $config; ?>
' . __('Acknowledgement Message', 'thold') . ' ' . __('Date', 'thold') . '
' . $comment . ' ' . date('Y-m-d H:i:s', $a['time']) . '
' . __('No Thresholds', 'thold') . '
' . __('No Devices', 'thold') . '
'> '> '>
'>
' . __('No Threshold Logs Found', 'thold') . '
'> '> '> '>