From b1f400ac0d4fe3593f5c89959af3122a3e5f3381 Mon Sep 17 00:00:00 2001 From: fbsanchez Date: Thu, 17 Nov 2016 17:31:09 +0100 Subject: [PATCH] SLA algorythm 2.0 --- pandora_console/include/functions_db.php | 388 ++++++++++ .../include/functions_reporting.php | 695 ++++++++++++++++++ 2 files changed, 1083 insertions(+) diff --git a/pandora_console/include/functions_db.php b/pandora_console/include/functions_db.php index 7c686842b4..76e82712ca 100644 --- a/pandora_console/include/functions_db.php +++ b/pandora_console/include/functions_db.php @@ -466,6 +466,394 @@ function db_get_all_rows_sql($sql, $search_history_db = false, $cache = true, $d } } + + + +/** + * + * Returns the time the module is in unknown status (by events) + * + * @param int $id_agente_modulo module to check + * @param int $tstart begin of search + * @param int $tend end of search + * + */ +function db_get_module_ranges_unknown($id_agente_modulo, $tstart = false, $tend = false) { + global $config; + + if (!isset($id_agente_modulo)) { + return false; + } + + if ((!isset($tstart)) || ($tstart === false)) { + // Return data from the begining + $tstart = 0; + } + + if ((!isset($tend)) || ($tend === false)) { + // Return data until now + $tend = time(); + } + + if ($tstart > $tend) { + return false; + } + + + // Retrieve going unknown events in range + $query = "SELECT utimestamp,event_type FROM tevento WHERE id_agentmodule = " . $id_agente_modulo; + $query .= " AND event_type like 'going_%' "; + $query .= " AND utimestamp >= $tstart AND utimestamp <= $tend "; + $query .= " ORDER BY utimestamp ASC"; + + $events = db_get_all_rows_sql($query); + + if (! is_array($events)){ + return false; + } + + $last_status = 0; // normal + $return = array(); + $i=0; + foreach ($events as $event) { + switch ($event["event_type"]) { + case "going_up_critical": + case "going_up_warning": + case "going_up_normal": { + if ($last_status == 1) { + $return[$i]["time_to"] = $event["utimestamp"]; + $i++; + $last_status = 0; + } + break; + } + case "going_unknown":{ + if ($last_status == 0){ + $return[$i] = array(); + $return[$i]["time_from"] = $event["utimestamp"]; + $last_status = 1; + } + break; + } + } + } + + return $return; +} + + +/** + * Uncompresses and returns the data of a given id_agent_module + * + * @param int $id_agente_modulo id_agente_modulo + * @param utimestamp $tstart Begin of the catch + * @param utimestamp $tend End of the catch + * @param int $interval Size of slice (default-> module_interval) + * + * @return hash with the data uncompressed in blocks of module_interval + * false in case of empty result + * + * Note: All "unknown" data are marked as NULL + * Warning: Be careful with the amount of data, check your RAM size available + * + */ +function db_uncompress_module_data($id_agente_modulo, $tstart = false, $tend = false) { + global $config; + + if (!isset($id_agente_modulo)) { + return false; + } + + if ((!isset($tstart)) || ($tstart === false)) { + // Return data from the begining + $tstart = 0; + } + + if ((!isset($tend)) || ($tend === false)) { + // Return data until now + $tend = time(); + } + + if ($tstart > $tend) { + return false; + } + + + $search_historydb = false; + $table = "tagente_datos"; + + $module = modules_get_agentmodule($id_agente_modulo); + if ($module === false){ + // module not exists + return false; + } + $module_type = $module['id_tipo_modulo']; + $module_type_str = modules_get_type_name ($module_type); + if (strstr ($module_type_str, 'string') !== false) { + $table = "tagente_datos_string"; + } + + + // Get first available utimestamp in active DB + $query = " SELECT utimestamp, datos FROM $table "; + $query .= " WHERE id_agente_modulo=$id_agente_modulo AND utimestamp < $tstart"; + $query .= " ORDER BY utimestamp DESC LIMIT 1"; + + + $ret = db_get_all_rows_sql( $query , $search_historydb); + + if ( ( $ret === false ) || (( isset($ret[0]["utimestamp"]) && ($ret[0]["utimestamp"] > $tstart )))) { + // Value older than first retrieved from active DB + $search_historydb = true; + + $ret = db_get_all_rows_sql( $query , $search_historydb); + } + else { + $first_data["utimestamp"] = $ret[0]["utimestamp"]; + $first_data["datos"] = $ret[0]["datos"]; + } + + if ( ( $ret === false ) || (( isset($ret[0]["utimestamp"]) && ($ret[0]["utimestamp"] > $tstart )))) { + // No previous data. -> not init + // Avoid false unknown status + $first_data["utimestamp"] = time(); + $first_data["datos"] = false; + } + else { + $first_data["utimestamp"] = $ret[0]["utimestamp"]; + $first_data["datos"] = $ret[0]["datos"]; + } + + $query = " SELECT utimestamp, datos FROM $table "; + $query .= " WHERE id_agente_modulo=$id_agente_modulo AND utimestamp >= $tstart AND utimestamp <= $tend"; + $query .= " ORDER BY utimestamp ASC"; + + // Retrieve all data from module in given range + $raw_data = db_get_all_rows_sql($query, $search_historydb); + + if (($raw_data === false) && ($ret === false)) { + // No data + return false; + } + + // Retrieve going unknown events in range + $unknown_events = db_get_module_ranges_unknown($id_agente_modulo, $tstart, $tend); + + // Retrieve module_interval to build the template + $module_interval = modules_get_interval ($id_agente_modulo); + $slice_size = $module_interval; + + // We'll return a bidimensional array + // Structure returned: schema: + // + // uncompressed_data => + // pool_id (int) + // utimestamp (start of current slice) + // data + // array + // utimestamp + // datos + + $return = array(); + + // Point current_timestamp to begin of the set and initialize flags + $current_timestamp = $tstart; + $last_inserted_value = $first_data["datos"]; + $last_timestamp = $first_data["utimestamp"]; + $data_found = 0; + + // Build template + $pool_id = 0; + $now = time(); + + $in_unknown_status = 0; + if (is_array($unknown_events)) { + $current_unknown = array_shift($unknown_events); + } + while ( $current_timestamp < $tend ) { + $expected_data_generated = 0; + + $return[$pool_id]["data"] = array(); + $tmp_data = array(); + $data_found = 0; + + if (is_array($unknown_events)) { + $i = 0; + while ($current_timestamp >= $unknown_events[$i]["time_to"] ) { + // Skip unknown events in past + array_splice($unknown_events, $i,1); + $i++; + if (!isset($unknown_events[$i])) { + break; + } + } + if (isset($current_unknown)) { + + // check if recovered from unknown status + if(is_array($unknown_events) && isset($current_unknown)) { + if ( (($current_timestamp+$slice_size) > $current_unknown["time_to"]) + && ($current_timestamp < $current_unknown["time_to"]) + && ($in_unknown_status == 1) ) { + // Recovered from unknown + + if ( ($current_unknown["time_to"] > $current_timestamp) + && ($expected_data_generated == 0) ) { + // also add the "expected" data + $tmp_data["utimestamp"] = $current_timestamp; + if ($in_unknown_status == 1) { + $tmp_data["datos"] = null; + } + else { + $tmp_data["datos"] = $last_inserted_value; + } + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + $expected_data_generated = 1; + } + + + $tmp_data["utimestamp"] = $current_unknown["time_to"]; + $tmp_data["datos"] = $last_inserted_value; + // debug purpose + //$tmp_data["obs"] = "event recovery data"; + + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + $data_found = 1; + $in_unknown_status = 0; + } + + if ( (($current_timestamp+$slice_size) > $current_unknown["time_from"]) + && (($current_timestamp+$slice_size) < $current_unknown["time_to"]) + && ($in_unknown_status == 0) ) { + // Add unknown state detected + + if ( $current_unknown["time_from"] < ($current_timestamp+$slice_size)) { + if ( ($current_unknown["time_from"] > $current_timestamp) + && ($expected_data_generated == 0) ) { + // also add the "expected" data + $tmp_data["utimestamp"] = $current_timestamp; + if ($in_unknown_status == 1) { + $tmp_data["datos"] = null; + } + else { + $tmp_data["datos"] = $last_inserted_value; + } + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + $expected_data_generated = 1; + } + + $tmp_data["utimestamp"] = $current_unknown["time_from"]; + $tmp_data["datos"] = null; + // debug purpose + //$tmp_data["obs"] = "event data"; + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + $data_found = 1; + } + $in_unknown_status = 1; + } + + if ( ($in_unknown_status == 0) && ($current_timestamp >= $current_unknown["time_to"]) ) { + $current_unknown = array_shift($unknown_events); + } + } + } // unknown events handle + } + + // Search for data + $i=0; + if (is_array($raw_data)) { + foreach ($raw_data as $data) { + if ( ($data["utimestamp"] >= $current_timestamp) + && ($data["utimestamp"] < ($current_timestamp+$slice_size)) ) { + // Data in block, push in, and remove from $raw_data (processed) + + if ( ($data["utimestamp"] > $current_timestamp) + && ($expected_data_generated == 0) ) { + // also add the "expected" data + $tmp_data["utimestamp"] = $current_timestamp; + if ($in_unknown_status == 1) { + $tmp_data["datos"] = null; + } + else { + $tmp_data["datos"] = $last_inserted_value; + } + //$tmp_data["obs"] = "expected data"; + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + $expected_data_generated = 1; + } + + $tmp_data["utimestamp"] = intval($data["utimestamp"]); + $tmp_data["datos"] = $data["datos"]; + // debug purpose + //$tmp_data["obs"] = "real data"; + + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + + $last_inserted_value = $data["datos"]; + $last_timestamp = intval($data["utimestamp"]); + + unset($raw_data[$i]); + $data_found = 1; + $in_unknown_status = 0; + } + elseif ($data["utimestamp"] > ($current_timestamp+$slice_size)) { + // Data in future, stop searching new ones + break; + } + } + $i++; + } + + if ($data_found == 0) { + // No data found, lug the last_value until SECONDS_1DAY + 2*modules_get_interval + // UNKNOWN! + + if (($current_timestamp > $now) || (($current_timestamp - $last_timestamp) > (SECONDS_1DAY + 2*$module_interval))) { + if (isset($last_inserted_value)) { + // unhandled unknown status control + $unhandled_time_unknown = $current_timestamp - (SECONDS_1DAY + 2*$module_interval) - $last_timestamp; + if ($unhandled_time_unknown > 0) { + // unhandled unknown status detected. Add to previous pool + $tmp_data["utimestamp"] = intval($last_timestamp) + (SECONDS_1DAY + 2*$module_interval); + $tmp_data["datos"] = null; + // debug purpose + //$tmp_data["obs"] = "unknown extra"; + // add to previous pool if needed + if (isset($return[$pool_id-1])) { + array_push($return[$pool_id-1]["data"], $tmp_data); + } + } + } + $last_inserted_value = null; + } + + $tmp_data["utimestamp"] = $current_timestamp; + + if ($in_unknown_status == 1) { + $tmp_data["datos"] = null; + } + else { + $tmp_data["datos"] = $last_inserted_value; + } + // debug purpose + //$tmp_data["obs"] = "virtual data"; + + $return[$pool_id]["utimestamp"] = $current_timestamp; + array_push($return[$pool_id]["data"], $tmp_data); + } + + $pool_id++; + $current_timestamp += $slice_size; + } + + return $return; +} + /** * Get all the rows of a table in the database that matches a filter. * diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index 48f56f8ebd..f974f52f9c 100644 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -3717,6 +3717,701 @@ function reporting_sql($report, $content) { return reporting_check_structure_content($return); } + +// +// Truncates a value +// +// Returns the truncated value +// +function sla_truncate($num, $accurancy = 2){ + if (!isset($accurancy)){ + $accurancy = 2; + } + $mult = pow(10, $accurancy); + return floor($num*$mult)/$mult; +} + +// +// Aux: check value limits +// +// Returns if the data is in a valid range or not +// +function sla_check_value($value, $min, $max, $inverse_interval = 0) { + if ($max == $min) { // equal 0 + if ($value == $max) { + return ($inverse_interval==0)?true:false; + } + return ($inverse_interval==0)?false:true; + } + if (!isset ($max)) { + if ($value >= $min) { + return ($inverse_interval==0)?true:false; + } + return ($inverse_interval==0)?false:true; + } + if (!isset ($min)) { + if ($value <= $max) { + return ($inverse_interval==0)?true:false; + } + return ($inverse_interval==0)?false:true; + } + if (($max*1) == 0) { // ignore + return sla_check_value($value,$min,null, $inverse_interval); + } + if (($min*1) == 0) { // ignore + return sla_check_value($value,null,$max, $inverse_interval); + } + if (($value >= $min) && ($value <= $max)) { + return ($inverse_interval==0)?true:false; + } + return ($inverse_interval==0)?false:true; +} + +/** + * SLA fixed worktime + * + * Check (if needed) if the range specified by wt_start and wt_end is a valid + * range or not. + * + * As worktime is order (older ... newer) the idx works as flag to identify + * last range checked, in order to improve the algorythm performance. + * + * @param int $wt_start start of the range + * @param int $wt_end end of the range + * @param hash $worktime hash containing the valid intervals + * @param int $idx last ranges checked + * + */ +function sla_fixed_worktime($wt_start, $wt_end, $worktime = null, $idx = 0) { + + $return = array(); + + // Accept all ranges by default + $return["wt_valid"] = 1; + $return["interval"] = $wt_end - $wt_start; + + // No exclusions defined, entire worktime is valid + if ((!isset($worktime) || (!is_array($worktime)))) { + return $return; + } + + // Check exceptions + $total = count($worktime); + + $return["idx"] = $idx; + + if (!(($idx <= $total) && ($idx >= 0))) { + $idx = 0; + } + + $start_fixed = 0; + for ($i=$idx; $i < $total; $i++) { + $wt = $worktime[$i]; + + if ($start_fixed == 1) { + // Intervals greater than 1 DAY + if ($wt_end < $wt["date_from"]) { + return $return; + } + + if ( ($wt_end >= $wt["date_from"]) + && ($wt_end <= $wt["date_to"])) { + // add last slice + $return["interval"] += $wt_end - $wt["date_from"]; + return $return; + } + if ( ($wt_end >= $wt["date_from"]) + && ($wt_end <= $wt["date_to"])) { + // Add current slice and continue checking + $return["interval"] += $wt["date_to"] - $wt["date_from"]; + // Also ignore this slice + $return["idx"] = $i; + } + } + else { + if ( ($wt_start < $wt["date_from"]) + && ($wt_end < $wt["date_from"])) { + // Case A: ..start..end..[...]...... + $return["wt_valid"] = 0; + return $return; + } + if ( ($wt_start <= $wt["date_from"]) + && ($wt_end >= $wt["date_from"]) + && ($wt_end <= $wt["date_to"])) { + // Case B: ...start..[..end..]...... + $return["wt_valid"] = 1; + $return["interval"] = $wt_end - $wt["date_from"]; + return $return; + } + if ( ($wt_start >= $wt["date_from"]) + && ($wt_start <= $wt["date_to"]) + && ($wt_end >= $wt["date_from"]) + && ($wt_end <= $wt["date_to"])) { + // Case C: ...[..start..end..]...... + $return["wt_valid"] = 1; + return $return; + } + if ( ($wt_start >= $wt["date_from"]) + && ($wt_start <= $wt["date_to"]) + && ($wt_end > $wt["date_to"])) { + // Case D: ...[..start..]...end..... + $return["interval"] = $wt["date_to"] - $wt_start; + + $return["wt_valid"] = 1; + $start_fixed = 1; + if (($i+1) == $total) { + // if there's no more worktime ranges to check return the accumulated + return $return; + } + + } + + if ( ($wt_start < $wt["date_from"]) + && ($wt_end > $wt["date_to"])) { + // Case E: ...start...[...]...end... + $return["wt_valid"] = 1; + $return["interval"] = $wt["date_to"] - $wt["date_from"]; + + if (($wt_end - $wt_start) < SECONDS_1DAY) { + // Interval is less than 1 day + return $return; + } + else { + // Interval greater than 1 day, split valid worktimes + $start_fixed = 1; + } + + } + if ( ($wt_start > $wt["date_to"]) + && ($wt_end > $wt["date_to"])) { + // Case F: ...[....]..start...end... + // Invalid, check next worktime hole + $return["wt_valid"] = 0; + // and remove current one + $return["idx"] = $i+1; + } + } + } + + $return["wt_valid"] = 0; + + return $return; +} + +/** + * Advanced SLA result with summary + * + * @param int $id_agent_module id_agent_module + * @param int $time_from Time start + * @param int $time_to time end + * @param int $min_value minimum value for OK status + * @param int $max_value maximum value for OK status + * @param int $inverse_interval inverse interval (range) for OK status + * @param hash $daysWeek Days of active work times (M-T-W-T-V-S-S) + * @param int $timeFrom Start of work time, in each day + * @param int $timeTo End of work time, in each day + * @param int $slices Number of reports (time division) + * + * @return array Returns a hash with the calculated data + * + */ +function reporting_advanced_sla ($id_agent_module, $time_from = null, $time_to = null, + $min_value = null, $max_value = null, $inverse_interval = null, $daysWeek = null, + $timeFrom = null, $timeTo = null, $slices = 1) { + + // In content: + // + // [time_from, time_to] => Worktime + // week's days => flags to manage workdays + + if (!isset($id_agent_module)) { + return false; + } + + if ($slices < 1) { + $slices = 1; + } + + if (!isset($min_value) && (!isset($max_value) && (!isset($inverse_interval)))) { + // Infer availability range based on the critical thresholds + $agentmodule_info = modules_get_agentmodule($id_agent_module); + + // take in mind: the "inverse" critical threshold + $min_value = $agentmodule_info["min_critical"]; + $max_value = $agentmodule_info["max_critical"]; + $inverse_interval = $agentmodule_info["critical_inverse"]==0?1:0; + + if (!isset($min_value)){ + $min_value = 0; + } + if (!isset($max_value)){ + $max_value = 0; + } + } + + // By default show last day + $datetime_to = time(); + $datetime_from = $datetime_to - SECONDS_1DAY; + + // Or apply specified range + if ((isset($time_to) && isset($time_from)) && ($time_to > $time_from)) { + $datetime_to = $time_to; + $datetime_from = $time_from; + } + if (!isset($time_to)) { + $datetime_to = $time_to; + } + if (!isset($time_from)) { + $datetime_from = $time_from; + } + + + $uncompressed_data = db_uncompress_module_data($id_agent_module, $datetime_from, $datetime_to); + + if (is_array($uncompressed_data)){ + $n_pools = count($uncompressed_data); + if ($n_pools == 0){ + return false; + } + } + $planned_downtimes = reporting_get_planned_downtimes_intervals($id_agent_module, $datetime_from, $datetime_to); + + if ( (is_array($planned_downtimes)) && (count($planned_downtimes) > 0)){ + // Sort retrieved planned downtimes + usort($planned_downtimes, function ($a, $b) { + $a = intval($a["date_from"]); + $b = intval($b["date_from"]); + if ($a==$b) { + return 0; + } + return ($a<$b)?-1:1; + }); + + // Compress (overlapped) planned downtimes + $npd = count($planned_downtimes); + for ($i=0; $i<$npd; $i++) { + if (isset($planned_downtimes[$i+1])) { + if ($planned_downtimes[$i]["date_to"] >= $planned_downtimes[$i+1]["date_from"]) { + // merge + $planned_downtimes[$i]["date_to"] = $planned_downtimes[$i+1]["date_to"]; + array_splice ($planned_downtimes, $i+1, 1); + $npd--; + } + } + } + } + else { + $planned_downtimes = null; + } + + // Structure retrieved: schema: + // + // uncompressed_data => + // pool_id (int) + // utimestamp (start of current slice) + // data + // array + // utimestamp + // datos + // + + + // Build exceptions + $worktime = null; + + if ( ((isset($daysWeek)) + && (isset($timeFrom)) + && (isset($timeTo))) + || (is_array($planned_downtimes)) ) { + $n = 0; + + if (!isset($daysWeek)) { + // init + $daysWeek = array ( + "1" => 1, // sunday" + "2" => 1, // monday + "3" => 1, // tuesday + "4" => 1, // wednesday + "5" => 1, // thursday + "6" => 1, // friday + "7" => 1, // saturday + ); + } + + foreach ($daysWeek as $day) { + if ($day == 1){ + $n++; + } + } + if ( ($n == count($daysWeek)) && ($timeFrom == $timeTo) && (!is_array($planned_downtimes)) ) { + // Ignore custom ranges + $worktime = null; + } + else { + + // get only first day + $date_start = strtotime(date("Y/m/d",$datetime_from)); + $date_end = strtotime(date("Y/m/d",$datetime_to)); + + $t_day = $date_start; + $i = 0; + $worktime = array(); + + if ($timeFrom == $timeTo) { + $timeFrom = "00:00:00"; + $timeTo = "00:00:00"; + } + + if (!isset($timeFrom)) { + $timeFrom = "00:00:00"; + } + if (!isset($timeTo)) { + $timeTo = "00:00:00"; + } + + // timeFrom (seconds) + sscanf($timeFrom, "%d:%d:%d", $hours, $minutes, $seconds); + $secondsFrom = $hours * 3600 + $minutes * 60 + $seconds; + + // timeTo (seconds) + sscanf($timeTo, "%d:%d:%d", $hours, $minutes, $seconds); + $secondsTo = $hours * 3600 + $minutes * 60 + $seconds; + + // Apply planned downtime exceptions (fix matrix) + while ($t_day <= $date_end) { + if ($daysWeek[date("w", $t_day)+1] == 1) { + $wt_start = strtotime(date("Y/m/d H:i:s",$t_day + $secondsFrom)); + $wt_end = strtotime(date("Y/m/d H:i:s",$t_day + $secondsTo)); + if ($timeFrom == $timeTo) { + $wt_end += SECONDS_1DAY; + } + + // Check if in planned downtime + if (is_array($planned_downtimes)) { + $start_fixed = 0; + + $n_planned_downtimes = count($planned_downtimes); + $i_planned_downtimes = 0; + + + + $last_pd = end($planned_downtimes); + + if ($wt_start > $last_pd["date_to"]) { + // There's no more planned downtimes, accept remaining range + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $wt_end; + $i++; + } + else { + for($i_planned_downtimes=0; $i_planned_downtimes < $n_planned_downtimes; $i_planned_downtimes++){ + $pd = $planned_downtimes[$i_planned_downtimes]; + + if($start_fixed == 1) { + // Interval greater than found planned downtime + if ( $wt_end < $pd["date_from"] ) { + $worktime[$i]= array(); + // wt_start already fixed + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $wt_end; + $i++; + break; + } + if ( ( $wt_end >= $pd["date_from"] ) + && ( $wt_end <= $pd["date_to"] )) { + $worktime[$i]= array(); + // wt_start already fixed + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $pd["date_from"]; + $i++; + break; + } + if ( $wt_end > $pd["date_to"] ) { + $worktime[$i]= array(); + // wt_start already fixed + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $pd["date_from"]; + $i++; + + $start_fixed = 0; + // Search following planned downtimes, we're still on work time! + $wt_start = $pd["date_from"]; + } + + } + + if ( ( $wt_start < $pd["date_from"]) + && ( $wt_end < $pd["date_from"]) ) { + // Out of planned downtime: Add worktime + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $wt_end; + $i++; + break; + } + if ( ( $wt_start < $pd["date_from"]) + && ( $wt_end <= $pd["date_to"]) ) { + // Not all worktime in downtime. + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $pd["date_from"]; + $i++; + break; + } + if ( ( $wt_start >= $pd["date_from"]) + && ( $wt_end <= $pd["date_to"]) ) { + // All worktime in downtime, ignore + break; + } + if ( ( $wt_start >= $pd["date_from"]) + && ( $wt_start <= $pd["date_to"]) + && ( $wt_end > $pd["date_to"]) ) { + // Begin of the worktime in downtime, adjust. + // Search for end of worktime. + $wt_start = $pd["date_to"]; + $start_fixed = 1; + } + if ( ( $wt_start < $pd["date_from"]) + && ( $wt_end > $pd["date_to"]) ) { + // Begin of the worktime in downtime, adjust. + // Search for end of worktime. + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $pd["date_from"]; + $i++; + $wt_start = $pd["date_to"]; + $start_fixed = 1; + } + + if ( ($start_fixed == 1) && (($i_planned_downtimes+1) == $n_planned_downtimes) ) { + // There's no more planned downtimes, accept remaining range + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $wt_end; + $i++; + break; + } + } + } + } + else { + // No planned downtimes scheduled + $worktime[$i]= array(); + $worktime[$i]["date_from"] = $wt_start; + $worktime[$i]["date_to"] = $wt_end; + $i++; + } + } + $t_day+=SECONDS_1DAY; + } // End while -> build matrix + } // End else (prepare fixed matrix) + } // Finished: Build exceptions + +// DEBUG +// print "Umcompressed data debug:\n"; +// foreach ($uncompressed_data as $k => $caja) { +// print "caja: $k\t" . $caja["utimestamp"] . "\n"; +// foreach ($caja["data"] as $dato) { +// print "\t" . $dato["utimestamp"] . "\t" . $dato["datos"] . "\t" . date("Y/m/d H:i:s",$dato["utimestamp"]) . "\t" . $dato["obs"] . "\n"; +// } +// } + + + // Initialization + $global_return = array(); + + $wt_check["idx"] = 0; + $last_pool_id = 0; + $last_item_id = 0; + + // Support to slices + $global_datetime_from = $datetime_from; + $global_datetime_to = $datetime_to; + $range = ($datetime_to - $datetime_from) / $slices; + + // Analysis begins + for ($count=0; $count < $slices; $count++) { + + $datetime_from = $global_datetime_from + ($count*$range); + $datetime_to = $global_datetime_from + (($count+1)*$range); + + $return = array(); + // timing + $time_total = 0; + $time_in_ok = 0; + $time_in_error = 0; + $time_in_unknown = 0; + $time_in_not_init = 0; + + // checks + $bad_checks = 0; + $ok_checks = 0; + $not_init_checks = 0; + $unknown_checks = 0; + $total_checks = 0; + + if (is_array($uncompressed_data)) { + + $n_pools = count($uncompressed_data); + for($pool_index = $last_pool_id; $pool_index < $n_pools; $pool_index++ ) { + $pool = $uncompressed_data[$pool_index]; + + // check limits + if (isset($uncompressed_data[$pool_index+1])) { + $next_pool = $uncompressed_data[$pool_index+1]; + } + else { + $next_pool = null; + } + if (isset($next_pool)) { + $pool["next_utimestamp"] = $next_pool["utimestamp"]; + } + else { + $pool["next_utimestamp"] = $global_datetime_to; + } + + // update last pool checked: avoid repetition + $last_pool_id = $pool_index; + + + if ($datetime_from > $pool["utimestamp"]) { + # Skip pool + continue; + } + + // Test if need to acquire current pool + if ( (($datetime_from <= $pool["utimestamp"]) && ($datetime_to >= $pool["next_utimestamp"])) + || ($datetime_to > $pool["utimestamp"]) ) { + + # Acquire pool to this slice + + $nitems_in_pool = count($pool["data"]); + for ($i=0; $i < $nitems_in_pool; $i++ ) { + $current_data = $pool["data"][$i]; + + if (($i+1) >= $nitems_in_pool) { + // if pool exceded, check next pool timestamp + $next_data = $next_pool; + } + else { + // pool not exceded, check next item + $next_data = $pool["data"][$i+1]; + } + + if (isset ($next_data["utimestamp"])) { + // check next mark time in current pool + $next_timestamp = $next_data["utimestamp"]; + + } + else { + // check last time -> datetime_to + if (!isset($next_pool)) { + $next_timestamp = $global_datetime_to; + } + else { + $next_timestamp = $datetime_to; + } + } + + // Effective time limits for current data + $wt_start = $current_data["utimestamp"]; + $wt_end = $next_timestamp; + + // Remove time spent in planned downtime and not in planning + $wt_check = sla_fixed_worktime($wt_start, $wt_end, $worktime, $wt_check["idx"]); + $time_interval = $wt_check["interval"]; + if ($time_interval == 0){ + continue; + } + + if ($wt_check["wt_valid"] == 1) { + $total_checks++; + $time_total += $time_interval; + if ((isset ($current_data["datos"])) && ($current_data["datos"] !== false)) { + // not unknown nor not init values + if (sla_check_value($current_data["datos"],$min_value, $max_value, $inverse_interval)) { + $ok_checks++; + $time_in_ok += $time_interval; + + } + else { + $bad_checks++; + $time_in_error += $time_interval; + } + } + else { + if($current_data["datos"] === null) { + $time_in_unknown += $time_interval; + $unknown_checks++; + } + elseif ($current_data["datos"] === false) { + $time_in_not_init += $time_interval; + $not_init_checks++; + } + } + } + else { + // ignore worktime, is in an invalid period: + // scheduled downtimes + // not 24x7 sla's + } + } // End of pool items analysis (for) + + } // End analysis of pool acquired + else { + break; + } + + } // End of pool analysis (for) + } + else { + // If monitor in not-init status => no data to show + $time_in_not_init = $datetime_to - $datetime_from; + $not_init_checks++; + } + + + // Timing + $return["time_total"] = $time_total; + $return["time_ok"] = $time_in_ok; + $return["time_error"] = $time_in_error; + $return["time_unknown"] = $time_in_unknown; + $return["time_not_init"] = $time_in_not_init; + + // # Checks + $return["checks_total"] = $total_checks; + $return["checks_ok"] = $ok_checks; + $return["checks_error"] = $bad_checks; + $return["checks_unknown"] = $unknown_checks; + $return["checks_not_init"] = $not_init_checks; + + // SLA + if (($time_in_error+$time_in_ok) == 0) { + $return["SLA"] = 0; + } + else { + $return["SLA"] = (($time_in_ok/($time_in_error+$time_in_ok))*100); + } + + // SLA + $return["SLA_fixed"] = sla_truncate($return["SLA"], $config['graph_precision']); + + if ($slices > 1) { + array_push($global_return, $return); + } + + } // end of slice analysis (for) + + if ($slices > 1) { + return $global_return; + } + + return $return; +} + + + function reporting_availability($report, $content, $date=false, $time=false) { global $config;