Example #1
0
function output_rrd_data($start_time, $force = FALSE)
{
    global $start, $max_run_duration, $config, $debug, $get_memory, $memory_used;
    global $rrdtool_pipe, $rrdtool_read_pipe;
    include_once $config['base_path'] . '/lib/rrd.php';
    $boost_poller_status = read_config_option('boost_poller_status');
    $rrd_updates = 0;
    /* implement process lock control for boost */
    if (!db_fetch_cell("SELECT GET_LOCK('poller_boost', 1)")) {
        if ($debug) {
            cacti_log('DEBUG: Found lock, so another boost process is running');
        }
        return -1;
    }
    /* detect a process that has overrun it's warning time */
    if (substr_count($boost_poller_status, 'running')) {
        $status_array = explode(':', $boost_poller_status);
        if (!empty($status_array[1])) {
            $previous_start_time = strtotime($status_array[1]);
            /* if the runtime was exceeded, allow the next process to run */
            if ($previous_start_time + $max_run_duration < $start_time) {
                cacti_log('WARNING: Detected Poller Boost Overrun, Possible Boost Poller Crash', FALSE, 'BOOST SVR');
            }
        }
    }
    /* if the poller is not running, or has never run, start */
    /* mark the boost server as running */
    db_execute("REPLACE INTO settings (name, value) VALUES ('boost_poller_status', 'running - start time:" . date('Y-m-d G:i:s') . "')");
    $current_time = date('Y-m-d G:i:s', $start_time);
    $rrdtool_pipe = rrd_init();
    $rrdtool_read_pipe = rrd_init();
    $runtime_exceeded = false;
    /* let's set and track memory usage will we */
    if (!function_exists('memory_get_peak_usage')) {
        $get_memory = true;
        $memory_used = memory_get_usage();
    } else {
        $get_memory = false;
    }
    $delayed_inserts = db_fetch_row("SHOW STATUS LIKE 'Not_flushed_delayed_rows'");
    while ($delayed_inserts['Value']) {
        cacti_log('BOOST WAIT: Waiting 1s for delayed inserts are made', true, 'SYSTEM');
        usleep(1000000);
        $delayed_inserts = db_fetch_row("SHOW STATUS LIKE 'Not_flushed_delayed_rows'");
    }
    /* split poller_output_boost */
    $archive_table = 'poller_output_boost_arch_' . time();
    db_execute("RENAME TABLE poller_output_boost TO {$archive_table}");
    db_execute("CREATE TABLE poller_output_boost LIKE {$archive_table}");
    $more_arch_tables = db_fetch_assoc("SELECT table_name AS name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema=SCHEMA()\n\t\tAND table_name LIKE 'poller_output_boost_arch_%'\n\t\tAND table_name!='{$archive_table}'\n\t\tAND table_rows>0;");
    if (count($more_arch_tables)) {
        foreach ($more_arch_tables as $table) {
            $table_name = $table['name'];
            db_execute("INSERT INTO {$archive_table} SELECT * FROM {$table_name}");
            db_execute("TRUNCATE TABLE {$table_name}");
        }
    }
    if (!strlen($archive_table)) {
        cacti_log('ERROR: Failed to retrieve archive table name');
        return -1;
    }
    while (1) {
        $rows = db_fetch_cell("SELECT count(*) FROM {$archive_table}");
        if ($rows > 0) {
            $rrd_updates += boost_process_poller_output(FALSE, '', $current_time);
            if ($get_memory) {
                $cur_memory = memory_get_usage();
                if ($cur_memory > $memory_used) {
                    $memory_used = $cur_memory;
                }
            }
        } else {
            break;
        }
        if (time() - $start > $max_run_duration && !$runtime_exceeded) {
            cacti_log('WARNING: RRD On Demand Updater Exceeded Runtime Limits. Continuing to Process!!!');
            $runtime_exceeded = true;
        }
    }
    /* tell the main poller that we are done */
    db_execute("REPLACE INTO settings (name, value) VALUES ('boost_poller_status', 'complete - end time:" . date('Y-m-d G:i:s') . "')");
    /* log memory usage */
    if (function_exists('memory_get_peak_usage')) {
        db_execute("REPLACE INTO settings (name, value) VALUES ('boost_peak_memory', '" . memory_get_peak_usage() . "')");
    } else {
        db_execute("REPLACE INTO settings (name, value) VALUES ('boost_peak_memory', '" . $memory_used . "')");
    }
    rrd_close($rrdtool_pipe);
    rrd_close($rrdtool_read_pipe);
    /* cleanup  - remove empty arch tables */
    $tables = db_fetch_assoc("SELECT table_name AS name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema=SCHEMA()\n\t\tAND table_name LIKE 'poller_output_boost_arch_%'\n\t\tAND table_rows=0;");
    if (count($tables)) {
        foreach ($tables as $table) {
            db_execute('DROP TABLE ' . $table['name']);
        }
    }
    db_execute("SELECT RELEASE_LOCK('poller_boost');");
    return $rrd_updates;
}
Example #2
0
function boost_process_poller_output($use_server = FALSE, $local_data_id = "")
{
    global $config, $boost_sock, $boost_timeout, $debug, $get_memory, $memory_used;
    global $rrdtool_pipe, $rrdtool_read_pipe;
    include_once $config["library_path"] . "/rrd.php";
    /* suppress warnings */
    if (defined("E_DEPRECATED")) {
        error_reporting(E_ALL ^ E_DEPRECATED);
    } else {
        error_reporting(E_ALL);
    }
    /* install the boost error handler */
    set_error_handler("boost_error_handler");
    /* load system variables needed */
    $log_verbosity = read_config_option("log_verbosity");
    $upd_string_len = read_config_option("boost_rrd_update_string_length");
    /* tiny SQL where addendum for boost */
    if (strlen($local_data_id)) {
        /* we can simplify the delete process if only one local_data_id */
        $single_local_data_id = TRUE;
        $orig_local_data_id = $local_data_id;
        /* aquire lock in order to prevent race conditions */
        while (!db_fetch_cell("SELECT GET_LOCK('boost.single_ds.{$local_data_id}', 1)")) {
            usleep(50000);
        }
    } else {
        $single_local_data_id = FALSE;
        $poller_interval = read_config_option("poller_interval");
        $rrd_update_interval = read_config_option("boost_rrd_update_interval");
        $data_ids_to_get = read_config_option("boost_rrd_update_max_records_per_select");
        $archive_table = boost_get_arch_table_name();
        if ($archive_table === FALSE) {
            cacti_log("Failed to determine archive table", FALSE, "BOOST");
            return 0;
        }
    }
    /* get the records */
    if ($single_local_data_id) {
        $query_string = "";
        $arch_tables = db_fetch_assoc("\tSELECT table_name AS name\r\n\t\t\t\t\t\tFROM information_schema.tables\r\n\t\t\t\t\t\t\tWHERE table_schema=SCHEMA()\r\n\t\t\t\t\t\t\tAND table_name LIKE 'poller_output_boost_arch_%'\r\n\t\t\t\t\t\t\tAND table_rows>0;\r\n\t\t\t\t\t\t");
        if (count($arch_tables)) {
            foreach ($arch_tables as $table) {
                if (strlen($query_string)) {
                    $query_string .= " UNION ";
                }
                $query_string .= " ( SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM " . $table["name"] . " WHERE local_data_id='{$local_data_id}' ) ";
            }
        }
        if (strlen($query_string)) {
            $query_string .= " UNION ";
        }
        $timestamp = time();
        $query_string .= " ( SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM poller_output_boost WHERE local_data_id='{$local_data_id}' AND time < FROM_UNIXTIME('{$timestamp}') ) ";
        $query_string .= "  ORDER BY local_data_id ASC, timestamp ASC, rrd_name ASC ";
    } else {
        $query_string = "SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM {$archive_table} FORCE INDEX (PRIMARY)\r\n\t\t\t\tORDER BY local_data_id ASC, time ASC, rrd_name ASC\r\n\t\t\t\tLIMIT {$data_ids_to_get} ";
    }
    boost_timer("get_records", BOOST_TIMER_START);
    $results = db_fetch_assoc($query_string);
    boost_timer("get_records", BOOST_TIMER_END);
    /* log memory */
    if ($get_memory) {
        $cur_memory = memory_get_usage();
        if ($cur_memory > $memory_used) {
            $memory_used = $cur_memory;
        }
    }
    if ($single_local_data_id && ($debug || $log_verbosity >= POLLER_VERBOSITY_MEDIUM)) {
        cacti_log("NOTE: Updating Local Data ID:'{$local_data_id}', Total of '" . sizeof($results) . "' Updates to Process", FALSE, "BOOST");
    }
    if (sizeof($results) > 0) {
        /* open the boost socket connection if applicable */
        if (read_config_option("boost_server_enable") == "on" && $local_data_id != "" && $use_server) {
            $boost_timeout = read_config_option("boost_server_timeout");
            $boost_sock = boost_server_connect();
            if ($boost_sock < 0) {
                /* restore original error handler */
                restore_error_handler();
                return 0;
            }
        }
        /* create an array keyed off of each .rrd file */
        $local_data_id = -1;
        $time = -1;
        $outbuf = "";
        $last_update = -1;
        $last_item = array("local_data_id" => -1, "timestamp" => -1, "rrd_name" => "");
        /* we are going to blow away all record if ok */
        $vals_in_buffer = 0;
        /* cut last DS (likely to be incomplete due to LIMIT)*/
        if (!$single_local_data_id) {
            reset($results);
            $first_ds = $results[key($results)];
            $first_ds = intval($first_ds["local_data_id"]);
            end($results);
            $last_ds = $results[key($results)];
            $last_ds = intval($last_ds["local_data_id"]);
            reset($results);
            if ($first_ds == $last_ds) {
                if (sizeof($results) == $data_ids_to_get) {
                    cacti_log("FALURE: Current LIMIT ({$data_ids_to_get}) is too low to run multiple DS RRD writes, consider raising it", FALSE, "BOOST");
                }
                restore_error_handler();
                return boost_process_poller_output($use_server, $first_ds);
            }
        }
        boost_timer("results_cycle", BOOST_TIMER_START);
        /* go through each poller_output_boost entries and process */
        foreach ($results as $item) {
            $item["timestamp"] = trim($item["timestamp"]);
            if ($single_local_data_id && $last_item["local_data_id"] == $item["local_data_id"] && $last_item["timestamp"] == $item["timestamp"] && strcmp($last_item["rrd_name"], $item["rrd_name"]) == 0) {
                continue;
            }
            if (!$single_local_data_id && $first_ds != $last_ds && $last_ds == $item["local_data_id"]) {
                /* we faced last and possibly incomplete DS, bail out */
                break;
            }
            /* if the local_data_id changes, we need to flush the buffer */
            if ($local_data_id != $item["local_data_id"]) {
                /* update the rrd for the previous local_data_id */
                if ($vals_in_buffer) {
                    if ($debug || $log_verbosity >= POLLER_VERBOSITY_MEDIUM) {
                        cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST");
                    }
                    boost_timer("rrdupdate", BOOST_TIMER_START);
                    $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe);
                    boost_timer("rrdupdate", BOOST_TIMER_END);
                    $outbuf = "";
                    $vals_in_buffer = 0;
                    /* check return status for delete operation */
                    if (trim($return_value) != "OK") {
                        cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST");
                    }
                }
                /* reset the rrd file path and templates, assume non multi output */
                boost_timer("rrd_filename_and_template", BOOST_TIMER_START);
                $rrd_data = boost_get_rrd_filename_and_template($item["local_data_id"]);
                $rrd_tmpl = $rrd_data["rrd_template"];
                $rrd_path = $rrd_data["rrd_path"];
                boost_timer("rrd_filename_and_template", BOOST_TIMER_END);
                $pipe = is_resource($rrdtool_read_pipe) || is_array($rrdtool_read_pipe) ? $rrdtool_read_pipe : $rrdtool_pipe;
                boost_timer("rrd_lastupdate", BOOST_TIMER_START);
                $last_update = boost_rrdtool_get_last_update_time($rrd_path, $pipe);
                boost_timer("rrd_lastupdate", BOOST_TIMER_END);
                $local_data_id = $item["local_data_id"];
                $time = $item["timestamp"];
                $initial_time = $time;
                $outbuf = " " . $time;
                $multi_vals_set = FALSE;
            }
            /* don't generate error messages if the RRD has already been updated */
            if ($time <= $last_update) {
                cacti_log("WARNING: Stale Poller Data Found! Item Time:'" . $time . "', RRD Time:'" . $last_update . "' Ignoring Value!", FALSE, "BOOST");
                $value = 'DNP';
            } else {
                $value = trim($item["output"]);
            }
            if ($time != $item["timestamp"]) {
                if (strlen($outbuf) > $upd_string_len) {
                    if ($log_verbosity >= POLLER_VERBOSITY_MEDIUM) {
                        cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST");
                    }
                    boost_timer("rrdupdate", BOOST_TIMER_START);
                    $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe);
                    boost_timer("rrdupdate", BOOST_TIMER_END);
                    $outbuf = "";
                    $vals_in_buffer = 0;
                    /* check return status for delete operation */
                    if (trim($return_value) != "OK") {
                        cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST");
                    }
                }
                $outbuf .= " " . $item["timestamp"];
                $time = $item["timestamp"];
            }
            /* single one value output */
            if (strcmp($value, 'DNP') == 0) {
                /* continue, bad time */
            } elseif (is_numeric($value) || strcmp($value, "U") == 0) {
                $outbuf .= ":" . $value;
                $vals_in_buffer++;
            } elseif (function_exists("is_hexadecimal") && is_hexadecimal($value)) {
                $outbuf .= ":" . hexdec($value);
                $vals_in_buffer++;
            } elseif (strlen($value)) {
                /* break out multiple value output to an array */
                $values = explode(" ", $value);
                if (!$multi_vals_set) {
                    $rrd_field_names = array_rekey(db_fetch_assoc("SELECT\r\n\t\t\t\t\t\tdata_template_rrd.data_source_name,\r\n\t\t\t\t\t\tdata_input_fields.data_name\r\n\t\t\t\t\t\tFROM (data_template_rrd,data_input_fields)\r\n\t\t\t\t\t\tWHERE data_template_rrd.data_input_field_id=data_input_fields.id\r\n\t\t\t\t\t\tAND data_template_rrd.local_data_id=" . $item["local_data_id"]), "data_name", "data_source_name");
                    $rrd_tmpl = "";
                }
                $first_tmpl = 1;
                $multi_ok = FALSE;
                for ($i = 0; $i < count($values); $i++) {
                    if (preg_match("/^([a-zA-Z0-9_\\.-]+):([eE0-9\\+\\.-]+)\$/", $values[$i], $matches)) {
                        if (isset($rrd_field_names[$matches[1]])) {
                            $multi_ok = TRUE;
                            if ($log_verbosity == POLLER_VERBOSITY_DEBUG) {
                                cacti_log("Parsed MULTI output field '" . $matches[0] . "' [map " . $matches[1] . "->" . $rrd_field_names[$matches[1]] . "]", FALSE, "BOOST");
                            }
                            if (!$multi_vals_set) {
                                if (!$first_tmpl) {
                                    $rrd_tmpl .= ":";
                                }
                                $rrd_tmpl .= $rrd_field_names[$matches[1]];
                                $first_tmpl = 0;
                            }
                            if (is_numeric($matches[2]) || $matches[2] == "U") {
                                $outbuf .= ":" . $matches[2];
                            } elseif (function_exists("is_hexadecimal") && is_hexadecimal($matches[2])) {
                                $outbuf .= ":" . hexdec($matches[2]);
                            } else {
                                $outbuf .= ":U";
                            }
                        }
                    }
                }
                /* we only want to process the template and gather the fields once */
                $multi_vals_set = TRUE;
                if ($multi_ok) {
                    $vals_in_buffer++;
                }
            } else {
                cacti_log("WARNING: Local Data Id [" . $item["local_data_id"] . "] Contains an empty value", FALSE, "BOOST");
            }
        }
        /* process the last rrdupdate if applicable */
        if ($vals_in_buffer) {
            if ($log_verbosity >= POLLER_VERBOSITY_MEDIUM) {
                cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST");
            }
            boost_timer("rrdupdate", BOOST_TIMER_START);
            $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe);
            boost_timer("rrdupdate", BOOST_TIMER_END);
            /* check return status for delete operation */
            if (trim($return_value) != "OK") {
                cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST");
            }
        }
        boost_timer("results_cycle", BOOST_TIMER_END);
        /* remove the entries from the table */
        boost_timer("delete", BOOST_TIMER_START);
        if ($single_local_data_id) {
            $tables = db_fetch_assoc("SELECT table_name AS name\r\n\t\t\t\t\t\tFROM information_schema.tables\r\n\t\t\t\t\t\tWHERE table_schema=SCHEMA()\r\n\t\t\t\t\t\tAND ( table_name LIKE 'poller_output_boost_arch_%' OR table_name LIKE 'poller_output_boost' )\r\n\t\t\t\t\t\tAND table_rows>0;\r\n\t\t\t\t\t\t");
            if (count($tables)) {
                foreach ($tables as $table) {
                    db_execute("DELETE FROM " . $table["name"] . " WHERE local_data_id='{$local_data_id}' AND time < FROM_UNIXTIME('{$timestamp}')");
                }
            }
        } else {
            db_execute("DELETE FROM {$archive_table} WHERE local_data_id BETWEEN '{$first_ds}' AND '" . ($last_ds - 1) . "'");
        }
        boost_timer("delete", BOOST_TIMER_END);
        /* close the boost server connection, if applicable */
        if (read_config_option("boost_server_enable") == "on" && $local_data_id != "" && $use_server) {
            boost_server_disconnect($boost_sock);
        }
    }
    if ($single_local_data_id) {
        db_execute("SELECT RELEASE_LOCK('boost.single_ds.{$orig_local_data_id}')");
    }
    /* restore original error handler */
    restore_error_handler();
    return sizeof($results);
}
Example #3
0
function get_current_value($rra, $ds, $cdef = 0)
{
    global $config;
    /* get the information to populate into the rrd files */
    if (function_exists("boost_check_correct_enabled") && boost_check_correct_enabled()) {
        boost_process_poller_output(TRUE, $rra);
    }
    $last_time_entry = thold_rrd_last($rra);
    // This should fix and 'did you really mean month 899 errors', this is because your RRD has not polled yet
    if ($last_time_entry == -1) {
        $last_time_entry = time();
    }
    $data_template_data = db_fetch_row("SELECT * FROM data_template_data WHERE local_data_id={$rra}");
    $step = $data_template_data['rrd_step'];
    // Round down to the nearest 100
    $last_time_entry = intval($last_time_entry / 100) * 100 - $step;
    $last_needed = $last_time_entry + $step;
    $result = rrdtool_function_fetch($rra, trim($last_time_entry), trim($last_needed));
    // Return Blank if the data source is not found (Newly created?)
    if (!isset($result['data_source_names'])) {
        return '';
    }
    $idx = array_search($ds, $result['data_source_names']);
    // Return Blank if the value was not found (Cache Cleared?)
    if (!isset($result['values'][$idx][0])) {
        return '';
    }
    $value = $result['values'][$idx][0];
    if ($cdef != 0) {
        $value = thold_build_cdef($cdef, $value, $rra, $ds);
    }
    return round($value, 4);
}