= POLLER_VERBOSITY_DEBUG) { // define all error types $errortype = [ E_ERROR => 'Error', E_WARNING => 'Warning', E_PARSE => 'Parsing Error', E_NOTICE => 'Notice', E_CORE_ERROR => 'Core Error', E_CORE_WARNING => 'Core Warning', E_COMPILE_ERROR => 'Compile Error', E_COMPILE_WARNING => 'Compile Warning', E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', E_RECOVERABLE_ERROR => 'Catchable Fatal Error' ]; // create an error string for the log $err = "ERRNO:'" . $errno . "' TYPE:'" . $errortype[$errno] . "' MESSAGE:'" . $errmsg . "' IN FILE:'" . $filename . "' LINE NO:'" . $linenum . "'"; // let's ignore some lesser issues if (substr_count($errmsg, 'date_default_timezone')) { return false; } if (substr_count($errmsg, 'Only variables')) { return false; } // log the error to the Cacti log cacti_log('PROGERR: ' . $err, false, 'DSDEBUG'); return false; } return true; } function dsdebug_poller_output(array &$rrd_update_array) : void { // suppress warnings if (defined('E_DEPRECATED')) { error_reporting(E_ALL ^ E_DEPRECATED); } else { error_reporting(E_ALL); } // install the dsstats error handler set_error_handler('dsdebug_error_handler'); // do not make any calculations unless enabled $checks = db_fetch_assoc('SELECT * FROM data_debug WHERE `done` = 0'); if (cacti_sizeof($checks)) { if (cacti_sizeof($rrd_update_array)) { foreach ($checks as $c) { foreach ($rrd_update_array as $item) { if ($c['datasource'] == $item['local_data_id']) { if (isset($item['times'][key($item['times'])])) { $c['info'] = cacti_unserialize($c['info']); $c['info']['last_result'] = $item['times'][key($item['times'])]; $c['info'] = serialize($c['info']); db_execute_prepared('UPDATE data_debug SET `info` = ? WHERE `id` = ?', [$c['info'], $c['id']]); } } } } } } // restore original error handler restore_error_handler(); } function dsdebug_poller_bottom() : bool { global $start; // install the dsstats error handler set_error_handler('dsdebug_error_handler'); // take time and log performance data $start = microtime(true); if (!db_table_exists('data_debug')) { return true; } $checks = db_fetch_assoc('SELECT * FROM data_debug WHERE `done` = 0'); if (!empty($checks)) { clearstatcache(); $total_issues = 0; foreach ($checks as $c) { $c['issue'] = []; $info = cacti_unserialize($c['info']); $dtd = db_fetch_row_prepared('SELECT * FROM data_template_data WHERE local_data_id = ?', [$c['datasource']]); if (!isset($dtd['local_data_id'])) { $c['issue'][] = __('Data Source ID %s does not exist', $c['datasource']); $c['done'] = 1; $total_issues++; } else { if (read_config_option('boost_rrd_update_enable') == 'on') { boost_process_poller_output($c['datasource']); } $real_path = str_replace('', CACTI_PATH_RRA, $dtd['data_source_path']); // rrd_folder_writable $info['rrd_folder_writable'] = (is_resource_writable(dirname($real_path) . '/') ? 1 : 0); // rrd_exists $info['rrd_exists'] = (file_exists($real_path) ? 1 : 0); // rrd_writable $info['rrd_writable'] = (is_resource_writable($real_path) ? 1 : 0); // active $info['active'] = $dtd['active']; // owner if (CACTI_SERVER_OS == 'win32') { $info['owner'] = ''; } else { $o = posix_getpwuid(fileowner($real_path)); $o = $o['name']; $g = posix_getgrgid(filegroup($real_path)); $g = $g['name']; $info['owner'] = $o . ':' . $g; } // poller_runas $info['runas_poller'] = get_running_user(); // convert_name $info['convert_name'] = (!str_contains('|', get_data_source_title($c['datasource'])) ? 1 : 0); // last_result (processed by hook) if (is_array($info['last_result']) && !empty($info['last_result']) && $info['valid_data'] == '') { $info['valid_data'] = 1; foreach ($info['last_result'] as $l) { if ($l == 'U') { cacti_log('Bad Data Found for Data Source ID ' . $c['datasource'], false, 'DSDEBUG'); $info['valid_data'] = 0; $total_issues++; } } } $rrdinfo = rrdtool_function_info($c['datasource']); if (cacti_sizeof($rrdinfo)) { $comp = rrdtool_cacti_compare($c['datasource'], $rrdinfo); $info['rrd_match'] = (!cacti_sizeof($comp) ? 1 : 0); $info['rrd_match_array'] = $comp; $info['rrd_info'] = $rrdinfo; // rra_timestamp if ($info['rra_timestamp'] != '' && isset($rrdinfo['last_update']) && $info['rra_timestamp'] != $rrdinfo['last_update']) { $info['rra_timestamp2'] = $rrdinfo['last_update']; } if (isset($rrdinfo['last_update']) && $info['rra_timestamp'] == '') { $info['rra_timestamp'] = $rrdinfo['last_update']; } $c['done'] = 1; $f = []; foreach ($info as $k => $v) { if ($v === '') { $c['done'] = 0; $f[] = $k; } } if ($c['started'] < time() - ($dtd['rrd_step'] * 5)) { $c['done'] = 1; $c['issue'][] = __('Debug not completed after 5 pollings'); $c['issue'][] = __('Failed fields: ') . implode(', ', $f); $total_issues++; } // Try to determine issue // Not set as Active // Log permanent fails first if ($info['active'] != 'on') { $c['issue'][] = __('Data Source is not set as Active'); $c['done'] = 1; $total_issues++; } // File Permissions if ((!$info['rrd_exists'] || !$info['rrd_writable']) && !$info['rrd_folder_writable']) { $c['issue'][] = __('RRDfile Folder (rra) is not writable by Poller. Folder owner: %s. Poller runs as: %s', $info['owner'], $info['runas_poller']); $c['done'] = 1; $total_issues++; } elseif (!$info['rrd_writable']) { $c['issue'][] = __('RRDfile is not writable by Poller. RRDfile owner: %s. Poller runs as %s', $info['owner'], $info['runas_poller']); $c['done'] = 1; $total_issues++; } // For errors that only appear after so many errors next if ($c['done'] == 1) { if ($info['rrd_match'] == 0) { $c['issue'][] = __('RRDfile does not match Data Source'); $total_issues++; } if ($info['rra_timestamp2'] == '') { $c['issue'][] = __('RRDfile not updated after polling'); $total_issues++; } if (is_array($info['last_result']) && !empty($info['last_result'])) { foreach ($info['last_result'] as $k => $l) { if ($l == 'U') { $c['issue'][] = __('Data Source returned Bad Results for ' . $k); $total_issues++; } } } elseif ($info['last_result'] == '') { $c['issue'][] = __('Data Source was not polled'); $total_issues++; } if ($c['issue'] == '') { $c['issue'][] = __('No issues found'); } } } else { $c['issue'][] = __('RRDfile not created yet'); $total_issues++; } $info = serialize($info); db_execute_prepared('UPDATE data_debug SET `done` = ?, `info` = ?, `issue` = ? WHERE id = ?', [$c['done'], $info, trim(implode("\n", $c['issue'])), $c['id']]); } } log_dsdebug_statistics('poller', cacti_sizeof($checks), $total_issues); } restore_error_handler(); return true; } function dsdebug_run_repair(int $id) : bool { $check = db_fetch_row_prepared('SELECT * FROM data_debug WHERE datasource = ?', [$id]); if (cacti_sizeof($check)) { $check['info'] = cacti_unserialize($check['info']); if (isset($check['info']['rrd_match_array']['tune'])) { $path = get_data_source_path($id, true); if (is_writable($path)) { $rrdtool_path = read_config_option('path_rrdtool'); $failures = 0; $failure_data = ''; foreach ($check['info']['rrd_match_array']['tune'] as $options) { $command = $rrdtool_path . ' tune ' . $options; $output = rrdtool_execute('tune ' . $options, false, RRDTOOL_OUTPUT_RETURN_STDERR); if ($output == '') { cacti_log("RRDfile repair command succeeded for DS[$id] Command[$command]", false, 'DSDEBUG'); } else { cacti_log("ERROR: RRDfile repair command failed for DS[$id] Command[$command] Output[$output]", false, 'DSDEBUG'); $failures++; } } if ($failures == 0) { return true; } } else { cacti_log("ERROR: RRDfile Repair Command Failed for DS[$id] Output[Unable to write RRDfile]", false, 'DSDEBUG'); } } else { cacti_log("ERROR: RRDfile Repair Command Could not be run for DS[$id] Output[No tune recommendation found]", false, 'DSDEBUG'); } } else { cacti_log("ERROR: RRDfile Repair Command Could not be run for DS[$id] Output[No Data Source debug information found]", false, 'DSDEBUG'); } return false; }