From 107b6ebb00389e58f6fee7090676dbfb7c62dcaf Mon Sep 17 00:00:00 2001 From: Pepijn Over Date: Sun, 13 Apr 2014 23:44:20 +0200 Subject: [PATCH] issue #52: adding uptime percentage to uptime graph --- src/lang/bg_BG.lang.php | 1 + src/lang/de_DE.lang.php | 1 + src/lang/en_US.lang.php | 1 + src/lang/fr_FR.lang.php | 1 + src/lang/ko_KR.lang.php | 1 + src/lang/nl_NL.lang.php | 1 + src/lang/pt_BR.lang.php | 1 + src/lang/zh_CN.lang.php | 1 + src/psm/Util/Server/HistoryGraph.class.php | 195 +++++++++++++-------- src/templates/server/history.tpl.html | 9 +- static/css/history.css | 12 +- 11 files changed, 141 insertions(+), 83 deletions(-) diff --git a/src/lang/bg_BG.lang.php b/src/lang/bg_BG.lang.php index cc6d2a6f..fb63ad72 100644 --- a/src/lang/bg_BG.lang.php +++ b/src/lang/bg_BG.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latency (maximum)', 'latency_min' => 'Latency (minimum)', 'latency_avg' => 'Latency (average)', + 'uptime' => 'Uptime', 'year' => 'Year', 'month' => 'Month', 'week' => 'Week', diff --git a/src/lang/de_DE.lang.php b/src/lang/de_DE.lang.php index ab30c216..37a95871 100644 --- a/src/lang/de_DE.lang.php +++ b/src/lang/de_DE.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latency (maximum)', 'latency_min' => 'Latency (minimum)', 'latency_avg' => 'Latency (average)', + 'uptime' => 'Uptime', 'year' => 'Year', 'month' => 'Month', 'week' => 'Week', diff --git a/src/lang/en_US.lang.php b/src/lang/en_US.lang.php index f5e7da58..498cad8b 100644 --- a/src/lang/en_US.lang.php +++ b/src/lang/en_US.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latency (maximum)', 'latency_min' => 'Latency (minimum)', 'latency_avg' => 'Latency (average)', + 'uptime' => 'Uptime', 'year' => 'Year', 'month' => 'Month', 'week' => 'Week', diff --git a/src/lang/fr_FR.lang.php b/src/lang/fr_FR.lang.php index 39abd716..40f18a67 100644 --- a/src/lang/fr_FR.lang.php +++ b/src/lang/fr_FR.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Temps de réponse maximum', 'latency_min' => 'Temps de réponse minimum', 'latency_avg' => 'Temps de réponse moyen', + 'uptime' => 'Uptime', 'year' => 'Année', 'month' => 'Mois', 'week' => 'Semaine', diff --git a/src/lang/ko_KR.lang.php b/src/lang/ko_KR.lang.php index 936bb479..5fd2f907 100644 --- a/src/lang/ko_KR.lang.php +++ b/src/lang/ko_KR.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latency (maximum)', 'latency_min' => 'Latency (minimum)', 'latency_avg' => 'Latency (average)', + 'uptime' => 'Uptime', 'year' => 'Year', 'month' => 'Month', 'week' => 'Week', diff --git a/src/lang/nl_NL.lang.php b/src/lang/nl_NL.lang.php index 21013dd1..b57f5bc5 100644 --- a/src/lang/nl_NL.lang.php +++ b/src/lang/nl_NL.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latency (maximum)', 'latency_min' => 'Latency (minimum)', 'latency_avg' => 'Latency (gemiddeld)', + 'uptime' => 'Uptime', 'year' => 'Jaar', 'month' => 'Maand', 'week' => 'Week', diff --git a/src/lang/pt_BR.lang.php b/src/lang/pt_BR.lang.php index 661451ef..a388f89b 100644 --- a/src/lang/pt_BR.lang.php +++ b/src/lang/pt_BR.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => 'Latência (máxima)', 'latency_min' => 'Latência (minima)', 'latency_avg' => 'Latência (média)', + 'uptime' => 'Uptime', 'year' => 'Ano', 'month' => 'Mês', 'week' => 'Semana', diff --git a/src/lang/zh_CN.lang.php b/src/lang/zh_CN.lang.php index 8627b181..7899f3f4 100644 --- a/src/lang/zh_CN.lang.php +++ b/src/lang/zh_CN.lang.php @@ -130,6 +130,7 @@ $sm_lang = array( 'latency_max' => '延迟(最大)', 'latency_min' => '延迟(最小)', 'latency_avg' => '延迟(平均)', + 'uptime' => 'Uptime', 'year' => '年', 'month' => '月', 'week' => '周', diff --git a/src/psm/Util/Server/HistoryGraph.class.php b/src/psm/Util/Server/HistoryGraph.class.php index 2700e97a..53b900fa 100644 --- a/src/psm/Util/Server/HistoryGraph.class.php +++ b/src/psm/Util/Server/HistoryGraph.class.php @@ -64,13 +64,32 @@ class HistoryGraph { 0 => $this->generateGraphUptime($server_id), 1 => $this->generateGraphHistory($server_id), ); + $info_fields = array( + 'latency_avg' => '%01.4f', + 'uptime' => '%01.3f%%', + ); + + foreach($graphs as $i => &$graph) { + // add subarray for info fields + $graph['info'] = array(); + + foreach($info_fields as $field => $format) { + if(!isset($graph[$field])) { + continue; + } + $graph['info'][] = array( + 'label' => psm_get_lang('servers', $field), + 'value' => sprintf($format, $graph[$field]), + ); + } + } + $this->tpl->addTemplateDataRepeat($tpl_id, 'graphs', $graphs); $this->tpl->addTemplateData( $tpl_id, array( 'label_server' => psm_get_lang('servers', 'server'), - 'label_latency_avg' => psm_get_lang('servers', 'latency_avg'), 'day_format' => psm_get_lang('servers', 'chart_day_format'), 'long_date_format' => psm_get_lang('servers', 'chart_long_date_format'), 'short_date_format' => psm_get_lang('servers', 'chart_short_date_format'), @@ -86,55 +105,26 @@ class HistoryGraph { * @param int $server_id * @return array */ - protected function generateGraphUptime($server_id) { - $uptimes = $this->db->select(PSM_DB_PREFIX.'servers_uptime' , array('server_id' => $server_id), null, '', 'date'); - $last_date = 0; - $latency_avg = 0; - // Create the list of points and server down zones - $line = array(); - $lines = array(); - $down = array(); - foreach ($uptimes as $uptime) { - $latency_avg += (float) $uptime['latency']; - - $time = strtotime($uptime['date']) * 1000; - if($uptime['status']) { - // The server is up - $line[] = '[' . $time . ',' . round((float)$uptime['latency'], 4) . ']'; - if($last_date) { - // Was down before. - // Record the first and last date as a string in the down array - $down[] = '[' . $last_date . ',' . $time . ']'; - $last_date = 0; - } - } - else { - if(!$last_date) { - $last_date = $time; - } - } - } - if(!empty($line)) { - $lines[] = '[' . implode(',', $line) . ']'; - } - if($last_date) { - $down[] = '[' . $last_date . ',0]'; - } - $buttons = array(); - $buttons[] = array('mode' => 'hour', 'label' => psm_get_lang('servers', 'hour'), 'class_active' => 'btn-info'); - $buttons[] = array('mode' => 'day', 'label' => psm_get_lang('servers', 'day')); - $buttons[] = array('mode' => 'week', 'label' => psm_get_lang('servers', 'week')); - - $data = array( - 'title' => psm_get_lang('servers', 'chart_last_week'), - 'latency_avg' => count($uptimes) > 0 ? round(($latency_avg / count($uptimes)), 4) : 0, - 'server_lines' => sizeof($lines) ? '[' . implode(',', $lines) . ']' : '', - 'server_down' => sizeof($down) ? '[' . implode(',', $down) . ']' : '', - 'series' => "[{label: '".psm_get_lang('servers', 'latency')."'}]", - 'plotmode' => 'hour', - 'buttons' => $buttons, - 'chart_id' => $server_id . '_uptime', + public function generateGraphUptime($server_id) { + $lines = array( + 'latency' => array(), ); + $cb_if_up = function($uptime_record) { + return ($uptime_record['status'] == 1); + }; + $records = $this->getRecords('uptime', $server_id); + + $data = $this->generateGraphLines($records, $lines, $cb_if_up, 'latency', true); + + $data['title'] = psm_get_lang('servers', 'chart_last_week'); + $data['plotmode'] = 'hour'; + $data['buttons'] = array(); + $data['buttons'][] = array('mode' => 'hour', 'label' => psm_get_lang('servers', 'hour'), 'class_active' => 'btn-info'); + $data['buttons'][] = array('mode' => 'day', 'label' => psm_get_lang('servers', 'day')); + $data['buttons'][] = array('mode' => 'week', 'label' => psm_get_lang('servers', 'week')); + // make sure to add chart id after buttons so its added to those tmeplates as well + $data['chart_id'] = $server_id . '_uptime'; + return $data; } @@ -143,41 +133,102 @@ class HistoryGraph { * @param int $server_id * @return array */ - protected function generateGraphHistory($server_id) { - $uptimes = $this->db->select(PSM_DB_PREFIX.'servers_history' , array('server_id' => $server_id), null, '', 'date'); - - $last_date = 0; - // Create the list of points and server down zones + public function generateGraphHistory($server_id) { $lines = array( 'latency_avg' => array(), 'latency_max' => array(), 'latency_min' => array(), ); + $server = $this->db->selectRow(PSM_DB_PREFIX.'servers', array('server_id' => $server_id), array('warning_threshold')); + + $cb_if_up = function($uptime_record) use($server) { + return ($uptime_record['checks_failed'] < $server['warning_threshold']); + }; + $records = $this->getRecords('history', $server_id); + + // dont add uptime for now because we have no way to calculate accurate uptimes for archived records + $data = $this->generateGraphLines($records, $lines, $cb_if_up, 'latency_avg', false); + + $data['title'] = psm_get_lang('servers', 'chart_history'); + $data['plotmode'] = 'month'; + $data['buttons'] = array(); + $data['buttons'][] = array('mode' => 'week2', 'label' => psm_get_lang('servers', 'week')); + $data['buttons'][] = array('mode' => 'month', 'label' => psm_get_lang('servers', 'month'), 'class_active' => 'btn-info'); + $data['buttons'][] = array('mode' => 'year', 'label' => psm_get_lang('servers', 'year')); + // make sure to add chart id after buttons so its added to those tmeplates as well + $data['chart_id'] = $server_id . '_history'; + + return $data; + } + + /** + * Get all uptime/history records for a server + * @param string $type + * @param int $server_id + * @return array + */ + protected function getRecords($type, $server_id) { + if(!in_array($type, array('history', 'uptime'))) { + return array(); + } + $records = $this->db->select(PSM_DB_PREFIX.'servers_'.$type , array('server_id' => $server_id), null, '', 'date'); + return $records; + } + + /** + * Generate data arrays for graphs + * @param array $records all uptime records to parse + * @param array $lines array with keys as line ids to prepare (key must be available in uptime records) + * @param callable $cb_if_up function to check if the server is up or down + * @param string $latency_avg_key which key from uptime records to use for calculating averages + * @param boolean $add_uptime add uptime calculation? + * @return array + */ + protected function generateGraphLines($records, $lines, callable $cb_if_up, $latency_avg_key, $add_uptime = false) { + $data = array(); + + // PLEASE NOTE: all times are in microseconds! because of javascript. + $last_date = 0; $latency_avg = 0; $series = array(); + // lowest timestamp of the graph (start time) + $time_start = 0; + // highest timestamp of the graph (end time) $time_end = 0; + // number of microseconds of downtime + $time_down = 0; $down = array(); - foreach ($uptimes as $uptime) { + + // Create the list of points and server down zones + foreach ($records as $i => $uptime) { $time = strtotime($uptime['date']) * 1000; - // keep track of highest timestamp to use as end-date for graphs + + // keep track of lowest and highest timestamp to use as end-date for graphs + // and for calculating uptime + if($i == 0 || $time < $time_start) { + $time_start = $time; + } if($time > $time_end) { $time_end = $time; } - $latency_avg += (float) $uptime['latency_avg']; + // use the first line to calculate average latency + $latency_avg += (float) $uptime[$latency_avg_key]; - if($uptime['checks_failed'] == 0) { + if($cb_if_up($uptime)) { // The server is up foreach($lines as $key => &$value) { // add the value for each of the different lines if(isset($uptime[$key])) { - $value[] = '[' . $time . ',' . round((float)$uptime[$key], 4) . ']'; + $value[] = '[' . $time . ',' . round((float) $uptime[$key], 4) . ']'; } } if($last_date) { // Was down before. // Record the first and last date as a string in the down array $down[] = '[' . $last_date . ',' . $time . ']'; + // add the number of microseconds of downtime to counter for % + $time_down += ($time - $last_date); $last_date = 0; } } else { @@ -199,23 +250,17 @@ class HistoryGraph { if($last_date) { $down[] = '[' . $last_date . ',0]'; } - $buttons = array(); - $buttons[] = array('mode' => 'week2', 'label' => psm_get_lang('servers', 'week')); - $buttons[] = array('mode' => 'month', 'label' => psm_get_lang('servers', 'month'), 'class_active' => 'btn-info'); - $buttons[] = array('mode' => 'year', 'label' => psm_get_lang('servers', 'year')); - $data = array( - 'title' => psm_get_lang('servers', 'chart_history'), - 'latency_avg' => count($uptimes) > 0 ? round(($latency_avg / count($uptimes)), 4) : 0, - 'server_lines' => sizeof($lines_merged) ? '[' . implode(',', $lines_merged) . ']' : '', - 'server_down' => sizeof($down) ? '[' . implode(',', $down) . ']' : '', - 'series' => sizeof($series) ? '[' . implode(',', $series) . ']' : '', - 'plotmode' => 'month', - 'end_timestamp' => $time_end ? $time_end : '', - 'buttons' => $buttons, - // make sure to add chart id after buttons so its added to those tmeplates as well - 'chart_id' => $server_id . '_history', - ); + if($add_uptime && $time_end > $time_start) { + $data['uptime'] = 100 - (($time_down / ($time_end - $time_start)) * 100); + } + + $data['latency_avg'] = count($records) > 0 ? ($latency_avg / count($records)) : 0; + $data['server_lines'] = sizeof($lines_merged) ? '[' . implode(',', $lines_merged) . ']' : ''; + $data['server_down'] = sizeof($down) ? '[' . implode(',', $down) . ']' : ''; + $data['series'] = sizeof($series) ? '[' . implode(',', $series) . ']' : ''; + $data['end_timestamp'] = $time_end ? $time_end : ''; + return $data; } } \ No newline at end of file diff --git a/src/templates/server/history.tpl.html b/src/templates/server/history.tpl.html index a36d00db..47923532 100644 --- a/src/templates/server/history.tpl.html +++ b/src/templates/server/history.tpl.html @@ -28,12 +28,13 @@
- + +
  • {label}: {value}
  • + +
    - {label_latency_avg}: {latency_avg}
    +
      {info}
    diff --git a/static/css/history.css b/static/css/history.css index 51718506..c858064f 100644 --- a/static/css/history.css +++ b/static/css/history.css @@ -39,6 +39,10 @@ padding-top: 40px; height: 200px; } +.server-info ul { + list-style: none; + margin: 0; +} .chart-selector { } @@ -47,11 +51,11 @@ .chart-container { margin-right: 0; } - + .chart-content { margin-right: 0; } - + .info-container { float: none; clear: both; @@ -62,11 +66,11 @@ display: block; float: left; } - + .server-info { display: none; } - + .chart-selector { float: right; }