Merge "Make it possible to sort on simple custom columns"
[ninja.git] / modules / reports / controllers / reports.php
blob636c33e2144e3c7192c621e66860bc580946100f
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3 * Reports controller
5 * This particular reports controller is meant as a base controller for both
6 * SLA and Availability reports, mostly for hysterical reasons.
8 * op5, and the op5 logo are trademarks, servicemarks, registered servicemarks
9 * or registered trademarks of op5 AB.
10 * All other trademarks, servicemarks, registered trademarks, and registered
11 * servicemarks mentioned herein may be the property of their respective owner(s).
12 * The information contained herein is provided AS IS with NO WARRANTY OF ANY
13 * KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY, AND FITNESS FOR A
14 * PARTICULAR PURPOSE.
16 class Reports_Controller extends Base_reports_Controller
18 private $status_link = "status/host/";
19 private $history_link = "alert_history/generate";
22 private static $sla_field_names = array(
23 'hosts' => 'PERCENT_TOTAL_TIME_UP',
24 'hostgroups' => 'PERCENT_TOTAL_TIME_UP',
25 'services' => 'PERCENT_TOTAL_TIME_OK',
26 'servicegroups' => 'PERCENT_TOTAL_TIME_OK'
29 /**
30 * Display report selection/setup page
32 public function index($input=false)
34 $this->setup_options_obj($input);
35 $reports_model = new Status_Reports_Model($this->options);
37 # check if we have all required parts installed
38 if (!$reports_model->_self_check()) {
39 return url::redirect(Router::$controller.'/invalid_setup');
42 # reset current_report_params and main_report_params
43 # just to be sure they're not left behind
44 Session::instance()->set('current_report_params', null);
45 Session::instance()->set('main_report_params', null);
47 $old_config_names = Saved_reports_Model::get_all_report_names($this->type);
48 $old_config_names_js = empty($old_config_names) ? "false" : "new Array('".implode("', '", array_map('addslashes', $old_config_names))."');";
49 $type_str = $this->type == 'avail'
50 ? _('availability')
51 : _('SLA');
52 $this->template->content = $this->add_view('reports/setup');
53 $template = $this->template->content;
55 if(isset($_SESSION['report_err_msg'])) {
56 $template->error_msg = $_SESSION['report_err_msg'];
57 unset($_SESSION['report_err_msg']);
60 # we should set the required js-files
61 $this->template->js_header = $this->add_view('js_header');
62 $this->xtra_js[] = $this->add_path('reports/js/tgraph.js');
63 $this->xtra_js[] = 'application/media/js/jquery.datePicker.js';
64 $this->xtra_js[] = 'application/media/js/jquery.timePicker.js';
65 $this->xtra_js[] = $this->add_path('reports/js/common.js');
66 $this->xtra_js[] = $this->add_path('reports/js/reports.js');
68 # this makes anything in application/media be imported before
69 # application/views before modules/whatever, so op5reports can
70 # put random crap here as well.
72 # I apologize
73 sort($this->xtra_js);
74 $this->xtra_js = array_unique($this->xtra_js);
76 $this->template->js_header->js = $this->xtra_js;
78 $this->template->css_header = $this->add_view('css_header');
79 $this->xtra_css[] = $this->add_path('reports/css/tgraph.css');
80 $this->xtra_css[] = $this->add_path('reports/css/datePicker.css');
81 $this->template->css_header->css = $this->xtra_css;
83 # what scheduled reports are there?
84 $scheduled_ids = array();
85 $scheduled_periods = null;
86 $scheduled_res = Scheduled_reports_Model::get_scheduled_reports($this->type);
87 if ($scheduled_res && count($scheduled_res)!=0) {
88 foreach ($scheduled_res as $sched_row) {
89 $scheduled_ids[] = $sched_row->report_id;
90 $scheduled_periods[$sched_row->report_id] = $sched_row->periodname;
94 $template->report_options = $this->add_view('reports/options');
96 $scheduled_info = false;
97 if ($this->options['report_id']) {
98 $scheduled_info = Scheduled_reports_Model::report_is_scheduled($this->type, $this->options['report_id']);
99 $template->is_scheduled = empty($scheduled_info) ? false: true;
101 $template->scheduled_info = $scheduled_info;
102 if ($this->options['report_id'])
103 $this->js_strings .= "var _report_data = " . $this->options->as_json() . "\n";
105 $this->inline_js .= "invalid_report_names = ".$old_config_names_js .";\n";
108 $this->js_strings .= "var nr_of_scheduled_instances = ". (!empty($scheduled_info) ? sizeof($scheduled_info) : 0).";\n";
109 $this->js_strings .= "var _reports_propagate = '"._('Would you like to propagate this value to all months')."';\n";
110 $this->js_strings .= "var _reports_propagate_remove = '"._("Would you like to remove all values from all months")."';\n";
111 $this->js_strings .= "var _schedule_change_filename = \""._('Would you like to change the filename based on your selections?')."\";\n";
113 $this->js_strings .= reports::js_strings();
115 $this->js_strings .= "var _reports_name_empty = '"._("Please give your report a meaningful name.")."';\n";
116 $this->js_strings .= "var _reports_error_name_exists = '"._("You have entered a name for your report that already exists. <br />Please select a new name")."';\n";
118 $this->template->inline_js = $this->inline_js;
120 $template->new_saved_title = sprintf(_('Create new saved %s report'), $type_str);
121 $template->report_options->months = date::abbr_month_names();
123 $saved_reports = Saved_reports_Model::get_saved_reports($this->type);
124 $template->report_options->saved_reports = $saved_reports;
125 $template->saved_reports = $saved_reports;
126 $template->scheduled_ids = $scheduled_ids;
127 $template->scheduled_periods = $scheduled_periods;
129 $this->js_strings .= "var _reports_no_sla_str = '"._('Please enter at least one SLA value')."';\n";
130 $this->js_strings .= "var _reports_sla_err_str = '"._('Please check SLA values in fields marked red below and try again')."';\n";
132 $this->template->js_strings = $this->js_strings;
134 $this->template->toolbar = new Toolbar_Controller($this->type == 'avail' ? _('Availability report') : _('SLA report'));
136 if ( $this->type == 'avail' ) {
137 $this->template->toolbar->info( '<a id="switch_report_type" href="' . url::base(true) . 'sla' . '">' );
138 $this->template->toolbar->info(
139 html::image($this->add_path('icons/16x16/sla.png'), array('alt' => _('SLA'), 'title' => _('SLA'), 'ID' => 'switcher_image'))
141 $this->template->toolbar->info( ' &nbsp; <span id="switch_report_type_txt">' . _('Switch to SLA report') . '</span>' );
142 $this->template->toolbar->info( '</a>' );
143 } else {
144 $this->template->toolbar->info( '<a id="switch_report_type" href="' . url::base(true) . 'avail' . '">' );
145 $this->template->toolbar->info(
146 html::image($this->add_path('icons/16x16/availability.png'), array('alt' => _('Availability'), 'title' => _('Availability'), 'ID' => 'switcher_image'))
148 $this->template->toolbar->info( ' &nbsp; <span id="switch_report_type_txt">' . _('Switch to Availability report') . '</span>' );
149 $this->template->toolbar->info( '</a>' );
152 $this->template->title = _('Reporting » ').($this->type == 'avail' ? _('Availability Report') : _('SLA Report')).(' » Setup');
156 * Create the same data as generate, but dump it as json
158 public function debug($input=false)
160 $this->setup_options_obj($input);
161 $reports_model = new Status_Reports_Model($this->options);
162 $data_arr = $reports_model->get_uptime();
163 header('Content-Type: text/plain');
164 header('Content-Disposition: attachment; filename="debug.json"');
165 print json_encode($data_arr);
166 exit(1);
170 * Generate (availability) report from parameters set in index()
172 * @param $input array = false
174 public function generate($input=false)
176 $this->setup_options_obj($input);
178 $reports_model = new Status_Reports_Model($this->options);
180 # check if we have all required parts installed
181 if (!$reports_model->_self_check()) {
182 return url::redirect(Router::$controller.'/invalid_setup');
185 $this->_stash_params();
187 $this->template->js_header = $this->add_view('js_header');
188 $this->xtra_js[] = 'application/media/js/jquery.datePicker.js';
189 $this->xtra_js[] = 'application/media/js/jquery.timePicker.js';
190 $this->xtra_js[] = $this->add_path('reports/js/tgraph.js');
191 $this->xtra_js[] = $this->add_path('reports/js/common.js');
192 $this->xtra_js[] = $this->add_path('reports/js/reports.js');
194 if ($this->options['skin']) {
195 if (substr($this->options['skin'], -1, 1) != '/') {
196 $this->options['skin'] .= '/';
198 $this->template->current_skin = $this->options['skin'];
201 $this->xtra_css[] = $this->add_path('reports/css/datePicker.css');
202 $this->xtra_css[] = $this->add_path('reports/css/tgraph.css');
203 $this->template->css_header = $this->add_view('css_header');
205 $old_config_names = Saved_reports_Model::get_all_report_names($this->type);
206 $old_config_names_js = empty($old_config_names) ? "false" : "new Array('".implode("', '", array_map("addslashes", $old_config_names))."');";
207 $this->inline_js .= "invalid_report_names = ".$old_config_names_js .";\n";
209 $this->template->content = $this->add_view('reports/index'); # base template with placeholders for all parts
210 $template = $this->template->content;
212 $scheduled_info = Scheduled_reports_Model::report_is_scheduled($this->type, $this->options['report_id']);
214 $sub_type = false;
216 $date_format = $this->type == 'sla' ? cal::get_calendar_format(true) : nagstat::date_format();
217 if($this->options['report_period'] && $this->options['report_period'] != 'custom')
218 $report_time_formatted = sprintf(
219 _('%s (%s to %s)'),
220 $this->options->get_value('report_period'),
221 "<strong>".date($date_format, $this->options['start_time'])."</strong>",
222 "<strong>".date($date_format, $this->options['end_time'])."</strong>"
224 else
225 $report_time_formatted = sprintf(_("%s to %s"),
226 date($date_format, $this->options['start_time']),
227 date($date_format, $this->options['end_time']));
229 if($this->options['rpttimeperiod'] != '')
230 $report_time_formatted .= " - {$this->options['rpttimeperiod']}";
232 switch ($this->options['report_type']) {
233 case 'hostgroups':
234 $sub_type = "host";
235 $is_group = true;
236 break;
237 case 'servicegroups':
238 $sub_type = "service";
239 $is_group = true;
240 break;
241 case 'hosts':
242 $sub_type = "host";
243 $is_group = false;
244 break;
245 case 'services':
246 $sub_type = "service";
247 $is_group = false;
248 break;
249 default:
250 return url::redirect(Router::$controller.'/index');
252 $var = $this->options->get_value('report_type');
254 $report_members = $this->options->get_report_members();
255 if (empty($report_members)) {
256 if (!$this->options[$var])
257 $_SESSION['report_err_msg'] = _("You didn't select any objects to include in the report");
258 else
259 $_SESSION['report_err_msg'] = sprintf(_("The groups you selected (%s) had no members, so cannot create a report from them"), implode(', ', $this->options[$var]));
260 return url::redirect(Router::$controller.'/index?' . http_build_query($this->options->options));
263 # fetch data
264 if ($this->type == 'avail') {
265 $data_arr = $reports_model->get_uptime();
266 } else {
267 $data_arr = $this->get_sla_data($this->options['months']);
270 if ($this->options['output_format'] == 'csv') {
271 csv::csv_http_headers($this->type, $this->options);
272 $this->template = $this->add_view('reports/'.$this->type.'csv');
273 $this->template->data_arr = $data_arr;
274 return;
277 $template->title = $this->type == 'avail' ? _('Availability Report') : _('SLA Report');
279 # ==========================================
280 # ========= REPORT STARTS HERE =============
281 # ==========================================
283 $template->report_options = $this->add_view('reports/options');
285 $tpl_options = $template->report_options;
286 $saved_reports = Saved_reports_Model::get_saved_reports($this->type);
287 $tpl_options->saved_reports = $saved_reports;
288 $tpl_options->months = date::abbr_month_names();
290 $this->js_strings .= "var nr_of_scheduled_instances = ". (!empty($scheduled_info) ? sizeof($scheduled_info) : 0).";\n";
291 $this->js_strings .= "var _reports_propagate = '"._('Would you like to propagate this value to all months')."';\n";
292 $this->js_strings .= "var _reports_propagate_remove = '"._("Would you like to remove all values from all months")."';\n";
294 $this->js_strings .= "var _reports_error_name_exists = '"._("You have entered a name for your report that already exists. <br />Please select a new name")."';\n";
295 $this->js_strings .= reports::js_strings();
296 $this->js_strings .= "var _reports_name_empty = '"._("Please give your report a meaningful name.")."';\n";
297 $this->js_strings .= "var _report_data = " . $this->options->as_json() . "\n";
299 $host_graph_items = array('TOTAL_TIME_UP' => _('Up'),
300 'TOTAL_TIME_DOWN' => _('Down'),
301 'TOTAL_TIME_UNREACHABLE' => _('Unreachable'),
302 'TOTAL_TIME_UNDETERMINED' => _('Undetermined'),
303 'TOTAL_TIME_EXCLUDED' => 'EXCLUDE',
305 $service_graph_items = array('TOTAL_TIME_OK' => _('Ok'),
306 'TOTAL_TIME_WARNING' => _('Warning'),
307 'TOTAL_TIME_UNKNOWN' => _('Unknown'),
308 'TOTAL_TIME_CRITICAL' => _('Critical'),
309 'TOTAL_TIME_UNDETERMINED' => _('Undetermined'),
310 'TOTAL_TIME_EXCLUDED' => 'EXCLUDE',
312 $graph_filter = ${$sub_type.'_graph_items'};
314 $template->header = $this->add_view('reports/header');
315 $template->header->title = $template->title;
316 $template->header->report_time_formatted = $report_time_formatted;
318 # avail, more than one object
319 $get_vars = $this->options->as_keyval_string(true);
320 if ($this->type == 'avail' && ($is_group || count($this->options[$this->options->get_value('report_type')]) > 1)) {
321 $template_values = array();
322 $template->content = $this->add_view('reports/multiple_'.$sub_type.'_states');
323 $template->content->multiple_states = $data_arr;
324 $template->content->hide_host = false;
326 if($is_group) # actual hostgroup/servicegroup.
327 $tmp_title = ucfirst($sub_type)._('group breakdown');
328 else
329 $tmp_title = ucfirst($sub_type).' '._('state breakdown');
330 $template->header->title = $tmp_title;
332 // ===== SETUP PIECHART VALUES =====
334 if( $this->options['include_pie_charts'] ) {
335 $template->pie = $this->add_view('reports/pie_chart');
336 $data_str = array();
338 foreach($data_arr as $data) { # for every group
339 if (!is_array($data) || !isset($data['states']))
340 continue;
341 $image = array();
342 foreach ($graph_filter as $key => $val) {
343 if ($data['states'][$key]!=0)
344 $image[strtoupper($val)] = $data['states'][$key];
346 $data_str[] = array(
347 'img' => http_build_query($image),
348 'host' => isset($data['groupname'])?implode(', ', $data['groupname']):'',
352 $template->pie->data_str = $data_str;
354 } else { # single avail host/service, or any sla
355 $image_data = array();
356 $data_str = '';
357 if (!empty($data_arr)) {
358 $template->content = $this->add_view('reports/'.$this->type);
360 if ($this->type == 'avail') {
361 $sources = array();
362 foreach ($data_arr as $grouplist) {
363 if (!is_array($grouplist) || !isset($grouplist['states']))
364 continue;
365 foreach ($grouplist as $host) {
366 if (!is_array($host) || !isset($host['states']))
367 continue;
368 $sources[] = $host['source'];
371 $avail = $template->content;
372 $avail->report_data = $data_arr;
374 $avail->header_string = ucfirst($this->options['report_type'])." "._('state breakdown');
376 # Will break epically
377 if( $this->options['include_pie_charts'] ) {
378 $pies = array();
379 foreach ($data_arr as $data) {
380 if (!is_array($data) || !isset($data['states']))
381 continue;
382 $pie = $this->add_view('reports/pie_chart');
384 // ===== SETUP PIECHART VALUES =====
385 if (is_array($data['states'])) {
386 foreach ($graph_filter as $key => $val) {
387 if ($data['states'][$key]!=0)
388 $image_data[strtoupper($val)] = $data['states'][$key];
392 if ($image_data) {
393 $data_str = http_build_query($image_data);
394 $pie->data_str = $data_str;
395 $pie->source = $data['source'];
397 $pies[] = $pie;
399 $avail->pies = $pies;
402 if ($sub_type=='host') {
403 $service_states = $this->_print_states_for_services($sources);
405 if ($service_states !== false) {
406 $header_str = _("Service state breakdown");
407 $template->svc_content = $this->add_view('reports/multiple_service_states');
408 $content = $template->svc_content;
409 $content->header_string = $header_str;
410 $content->multiple_states = $service_states;
411 $content->hide_host = true;
412 $content->source = $sources;
416 $t1 = $this->options['start_time'];
417 $t2 = $this->options['start_time'];
419 # assume default values for the following
420 $backtrack = 1;
422 $links = array();
423 $downtime = $this->options['scheduleddowntimeasuptime'];
424 $not_running = $this->options['assumestatesduringnotrunning'];
425 $soft_states = $this->options['includesoftstates'];
427 # links - only for HTML reports
428 switch($this->options['report_type']) {
429 case 'hosts':
430 $host = $this->options['host_name'][0];
431 $template->header->title = sprintf(_('Host details for %s'), $host);
432 $histogram_params = "host=$host&amp;t1=$t1&amp;t2=$t2";
434 $links[$this->histogram_link . "?" . $histogram_params] = _('Alert histogram');
436 $links[$this->status_link.$host] = _('Status detail');
438 $links[$this->history_link . '?host_name[]=' . $host] = _('Alert history');
439 $links[listview::link('notifications', array('host_name' => $host))] = _('Notifications');
440 break;
442 case 'services':
443 list($host, $service) = explode(';',$this->options['service_description'][0]);
445 $template->header->title = sprintf(_('Service details for %s on host %s'), $service, $host);
446 if (isset($template->content)) {
447 $template->content->host = $host;
448 $template->content->service = $service;
451 $histogram_params = "service[]=".urlencode("$host;$service")."&amp;t1=$t1&amp;t2=$t2";
452 $history_params = "service[]=".urlencode("$host;$service");
454 $links[$this->histogram_link . "?" . $histogram_params] = _('Alert histogram');
455 $links[$this->history_link . "?" . $history_params] = _('Alert history');
456 $links[listview::link('notifications', array('host_name' => $host, 'service_description' => $service))] = _('Notifications');
458 break;
461 $template->links = $links;
462 $template->source = $sources;
463 $template->header_string = sprintf(_("State breakdown for %s"), implode(', ', $sources));
464 } else {
465 # SLA report
466 $template->header->title = _('SLA breakdown');
467 $sla = $template->content;
468 $sla->report_data = $data_arr;
471 } # end if not empty. Display message to user?
472 # ^ no, that sounds like a terrible idea, don't inform the user about anything, ever!
475 if($this->options['include_trends']) {
476 $skipped = 0;
477 $included = 0;
478 $graph_data = array();
479 foreach ($data_arr as $data) {
480 if (!is_array($data) || !isset($data['states']))
481 continue;
482 foreach ($data as $obj) {
483 if (!is_array($obj) || !isset($obj['log']))
484 continue;
485 if ($this->options['collapse_green_trends'] && (($sub_type == 'host' && $obj['states']['PERCENT_TOTAL_TIME_UP'] == 100) || ($sub_type == 'service' && $obj['states']['PERCENT_TOTAL_TIME_OK'] == 100))) {
486 $skipped++;
487 continue;
489 $graph_data[$obj['source']] = $obj['log'];
490 $included++;
494 $template->trends_graph = $this->add_view('trends/new_report');
496 /* New JS trend graph */
498 $template->trends_graph->skipped = $skipped;
499 $template->trends_graph->included = $included;
500 $template->trends_graph->graph_start_date = $this->options['start_time'];
501 $template->trends_graph->graph_end_date = $this->options['end_time'];
502 $template->trends_graph->use_scaling = $this->options['include_trends_scaling'];
503 $template->trends_graph->obj_type = $sub_type;
504 $template->trends_graph->graph_pure_data = Trends_graph_Model::format_graph_data($graph_data);
507 $this->template->inline_js = $this->inline_js;
508 $this->template->js_strings = $this->js_strings;
509 $this->template->css_header->css = $this->xtra_css;
511 $this->template->title = _('Reporting » ').($this->type == 'avail' ? _('Availability Report') : _('SLA Report')).(' » Report');
513 $this->xtra_js[] = $this->add_path('summary/js/summary.js');
514 if ($this->options['include_alerts']) {
515 $alrt_opts = new Alert_history_options($this->options);
516 $alrt_opts['summary_items'] = 0; // we want *every* line in this time range
517 $alrt_opts['include_downtime'] = true; // and we want downtime messages
519 $alerts = new Alert_history_Controller();
520 $alerts->set_options($alrt_opts);
521 $alerts->auto_render = false;
522 $alerts->generate();
523 $this->template->content->log_content = $alerts->template->content->content;
526 if(ninja::has_module('synergy') && $this->options['include_synergy_events']) {
527 $synergy_report_model = new Synergy_report_Model($this->options);
528 $synergy_content = $this->add_view('reports/synergy');
529 $synergy_content->synergy_events = $synergy_report_model->get_data();
530 $this->template->content->synergy_content = $synergy_content;
532 $this->template->js_header->js = $this->xtra_js;
533 $scheduled_info = Scheduled_reports_Model::report_is_scheduled($this->type, $this->options['report_id']);
534 if($scheduled_info) {
535 $schedule_id = $this->input->get('schedule_id', null);
536 if($schedule_id) {
537 $le_schedule = current(array_filter($scheduled_info, function($item) use ($schedule_id) {
538 return $item['id'] == $schedule_id && $item['attach_description'] && $item['description'];
539 }));
540 if($le_schedule) {
541 $template->header->description = $this->options['description'] ? $this->options['description']."\n".$le_schedule['description'] : $le_schedule['description'];
546 if ($this->options['output_format'] == 'pdf') {
547 return $this->generate_pdf();
552 * Stash parameters in session from setup form to be used
553 * for re-generating report.
555 public function _stash_params()
557 Session::instance()->set('current_report_params', null);
559 if (!empty($data)) {
560 if (array_key_exists('ew_report_setup', $input)) {
561 # directly from setup form - keep data for backlink
562 Session::instance()->set('main_report_params', $this->options->as_keyval_string(false));
565 Session::instance()->set('current_report_params', $this->options->as_keyval_string(false));
570 * Print message to user about invalid setup.
571 * This could be because of missing database or
572 * reports module
574 public function invalid_setup()
576 $this->template->content = $this->add_view('reports/reports_module');
577 $template = $this->template->content;
578 $template->error_msg = _('Some parts in your setup is apparently missing.');
579 $template->info = _("make sure you install the latest version of merlin");
582 private function _print_states_for_services($host_name=false)
584 $res = Livestatus::instance()->getServices(array('columns' => array('host_name', 'description'), 'filter' => array('host_name' => $host_name)));
585 if (!empty($res)) {
586 $service_arr = array();
588 $classname = get_class($this->options);
589 $opts = new $classname($this->options);
590 foreach ($res as $row)
591 $service_arr[] = $row['host_name'] . ';' . $row['description'];
592 $opts['service_description'] = $service_arr;
593 $report_class = new Status_Reports_Model($opts);
595 $data_arr = $report_class->get_uptime();
596 return $data_arr;
598 return false;
602 * Fetch data from report_class
603 * Uses split_month_data() to split start- and end_time
604 * on months.
606 * @param $months = false
607 * @return array
609 private function get_sla_data($months)
611 if (empty($months)) {
612 return array();
615 // OK, we have start and end but we will have to split
616 // this time into parts according to sla_periods (months)
617 $time_arr = $this->_split_month_data($this->options['start_time'], $this->options['end_time']);
618 // only use month entered by the user regardless of start- or endtime
619 $data = array();
620 $opts = new Avail_options($this->options);
621 $opts['report_period'] = 'custom';
622 foreach ($time_arr as $mnr => $dates) {
623 $opts['start_time'] = $dates['start'];
624 $opts['end_time'] = $dates['end'];
625 $report_class = new Status_Reports_Model($opts);
626 $data_tmp = $report_class->get_uptime();
627 # So, all this does is to remove the summary for all reports?
628 # That's anti-clever!
629 foreach ($data_tmp as $group => $val) {
630 if (!is_array($val) || !isset($val['states']))
631 continue;
632 $data[$group][$mnr] = $val;
635 return $this->_sla_group_data($data);
639 * Mangle SLA data for host- and servicegroups
641 private function _sla_group_data($sla_data)
643 if (empty($sla_data))
644 return $sla_data;
645 $report_data = array();
646 foreach ($sla_data as $period_data) {
647 $table_data = array();
648 $data = array();
649 $name = false;
650 // loop over whole period for current group
651 foreach ($period_data as $period_start => $tmp_data) {
652 if (!is_array($tmp_data) || !isset($tmp_data['states']))
653 continue;
654 $month_idx = date('n', $period_start);
655 if (array_key_exists($month_idx, $this->options['months'])) {
656 if (arr::search($tmp_data, 'states')) {
658 # $tmp_data['states']['PERCENT_TOTAL_TIME_{UP,OK}']
659 $real_val = $tmp_data['states'][self::$sla_field_names[$this->options['report_type']]];
661 # control colour of bar depending on value
662 # true = green, false = red
663 $sla_ok = $this->options['months'][$month_idx] > $real_val ? true : false;
664 } else {
665 // create empty 'real' values
666 $sla_ok = false;
667 $real_val = 0;
670 $data[date('M', $period_start)] = array($real_val, $this->options['months'][$month_idx], $sla_ok);
671 if ($this->options['scheduleddowntimeasuptime'] == 2)
672 $table_data[$period_start] = array($real_val, $this->options['months'][$month_idx], $tmp_data['states']['PERCENT_TIME_DOWN_COUNTED_AS_UP']);
673 else
674 $table_data[$period_start] = array($real_val, $this->options['months'][$month_idx]);
676 $source = false;
677 foreach ($tmp_data as $subobj) {
678 if (!is_array($subobj) || !isset($subobj['states']))
679 continue;
680 $source[] = $subobj['source'];
682 $name = isset($tmp_data['groupname']) ? $tmp_data['groupname'] : false;
685 if (!$name && count($source) == 1)
686 $name = $source;
688 $report_data[] = array(
689 'name' => $name,
690 'table_data' => $table_data,
691 'data_str' => http_build_query($data),
692 'source' => $source,
693 'avail_link' => $this->_generate_avail_member_link(),
696 return $report_data;
700 * @param string $members
701 * @return string A link to an Availability report for all members
703 private function _generate_avail_member_link()
705 $objects = '';
706 $return = url::site().'avail/generate?';
707 $return .= $this->options->as_keyval_string(false);
708 return $return;
712 * @desc Splits a span of unixtime(start_time, end_time) into slices for every month number in $months.
713 * @param $start_time int start timestamp of the first month
714 * @param $end_time int end timestamp of the last month
715 * @return array of start/end timestamps for every timestamp gives the start and end of the month
717 private function _split_month_data($start_time, $end_time)
719 $months = array();
720 $date = $start_time;
721 while ($date < $end_time) {
722 $end = strtotime('+1 month', $date);
723 $months[$date] = array('start' => $date, 'end' => $end);
724 $date = $end;
726 return $months;
730 * Translated helptexts for this controller
732 public static function _helptexts($id)
734 $helptexts = array(
735 'filter' => _("Free text search, matching the objects in the left list below"),
736 'scheduled_downtime' => _("Select if downtime that occurred during scheduled downtime should be counted as the actual state, as uptime, or if it should be counted as uptime but also showing the difference that makes."),
737 'stated_during_downtime' => _("If the application is not running for some time during a report period we can by this ".
738 "option decide to assume states for hosts and services during the downtime."),
739 'includesoftstates' => _("A problem is classified as a SOFT problem until the number of checks has reached the ".
740 "configured max_check_attempts value. When max_check_attempts is reached the problem is reclassified as HARD."),
741 'sla_mode' => _("What calculation method to use for the report summary.<br/>".
742 "Depending on how your network is configured, your SLA might be the group availability (worst state at any point in time) or cluster mode availability (best state at any point time). You can also choose to use average values instead for ".
743 "the group or object in question.<br/>Note that calculating the summary incorrectly could mislead users."),
744 'use_alias' => _("Select if you would like to see host aliases in the generated reports instead of just the host_name"),
745 'csv_format' => _("The CSV (comma-separated values) format is a file format that stores tabular data. This format is supported ".
746 "by many applications such as MS Excel, OpenOffice and Google Spreadsheets."),
747 'save_report' => _("Check this box if you want to save the configured report for later use."),
748 'enter-sla' => _("Enter the selected SLA values for each month. Percent values (0.00-100.00) are assumed."),
749 'report_settings_sml' => _("Here you can modify the report settings for the report you are currently viewing."),
750 'log_entries' => _("Shows the actual log messages that this report was created of."),
751 'hostgroup_breakdown' => _("Here you have a list of all hosts that are member of this hostgroup and their states."),
752 'servicegroup_breakdown' => _("Here you have a list of all services that are member of this servicegroup and their states."),
753 'average_and_sla' => _("Shows the Average and SLA values for all selected services above."), // text ok?
754 'availability' => _("This table shows a breakdown of the different states. How much time that was ok, warning, unknown, critical or undetermined in both actual time and percent. Time is also divied between uncheduled and scheduled which helps you to separate unplanned and planned events."),
755 'piechart' => _("Pie chart that displays how much time in percent that was ok, warning, unknown, critical or undetermined."),
756 'sla_graph' => _("Graphical report of the SLA. Green bars meens that the SLA was fulfilled and red that it was not fulfilled."),
757 'sla_breakdown' => _("Breakdown of the SLA report in actual figures."),
758 'sla_group_members' => _("Members of the selected group that the report is generated for. All members are links to individual reports."),
759 'trends' => _("Shows trends during selected report period, lines above the main line are upscaled statechanges from the blacked out section below."),
760 'trends_scaling' => _("Scale up rapid state changes into a line above the main line."),
761 'collapse_green_trends' => _("Hide trends that are 100% Up/OK during the report period. This reduces visual noise to help you correlate events."),
762 'saved_reports' => _("A list of all your saved reports. To load them, select the report you wish to generate and click select."),
763 'use-sla-values' => _("Load SLA-values from previously saved reports. Just select a report in the list and it will autoload."),
764 'include_pie_charts' => _('If you include this, your availability percentages will be graphed in pie charts'),
766 // new scheduled report
767 'report-type-save' => _("Select what type of report you would like to schedule the creation of"),
768 'select-report' => _("Select which report you want to you want to schedule"), // text ok?
769 'report' => _("Select the saved report to schedule"),
770 'interval' => _("Select how often the report is to be produced and delivered"),
771 'recipents' => _("Enter the email addresses of the recipients of the report. To enter multiple addresses, separate them by commas"),
772 'filename' => _("This field lets you select a custom filename for the report. If the name ends in <strong>.csv</strong>, a CSV file will be generated - otherwise a PDF will be generated."),
773 'start-date' => _("Enter the start date for the report (or use the pop-up calendar)."),
774 'end-date' => _("Enter the end date for the report (or use the pop-up calendar)."),
775 'local_persistent_filepath' => _("Specify an absolute path on the local disk, where you want the report to be saved in PDF format.").'<br />'._("This should be the location of a folder, for example /tmp"),
776 'attach_description' => _("Append this description inside the report's header to the general description given for the report"),
777 'include_trends' => _("Check this to include a trends graph in your report.<br>Warning: This can make your reports slow!"),
778 'include_trends_scaling' => _("Check this to get upscaled values on your trends graph for small segments of time that would otherwise be hidden."),
779 'include_alerts' => _('Include a log of all alerts for all objects in your report.<br>Warning: This can make your reports slow!'),
780 'synergy_events' => _('Include a detailed history of what happened to BSM objects'),
782 if (array_key_exists($id, $helptexts))
783 echo $helptexts[$id];
784 else
785 parent::_helptexts($id);