From 461a4b25060835346f13986fe44ae8b9abcdded9 Mon Sep 17 00:00:00 2001 From: Robin Sonefors Date: Tue, 6 May 2014 17:51:13 +0200 Subject: [PATCH] histogram: Make histograms crash less They used to crash whenever you tried to view a host histogram for a host that had an unreachable service. This fixes bug #7751. It could be that it's still crash:able, but my brand new, relatively encompassing suite of tests should be easy to extend if new ways of achieving that are discovered. As described in comments for #7751, there is a fundamental problem with how our histograms are presented - therefore, this moves histograms to the main menu, and because I literally got saving for free, I'm throwing that in as well, at no extra charge. Finally, this moves the histogram views to the report module where they belong, and some unused code - such as a custom CSS with no relevant content - are deleted. Change-Id: I4955df5b16fbccf1ace7a93587eaab8191026bdb Signed-off-by: Robin Sonefors --- application/views/histogram/css/bg.png | Bin 48231 -> 0 bytes application/views/histogram/css/histogram.css | 182 ----------- application/views/histogram/histogram.php | 56 ---- application/views/histogram/index.php | 9 - application/views/histogram/options.php | 65 ---- application/views/histogram/setup.php | 75 ----- application/views/menu/menu.php | 4 +- application/views/template_head.php | 1 - features/histogram.feature | 340 +++++++++++++++++++++ features/reports.feature | 3 + modules/reports/controllers/histogram.php | 212 ++++--------- modules/reports/libraries/Histogram_options.php | 2 +- modules/reports/libraries/Summary_options.php | 1 + modules/reports/models/summary_reports.php | 96 +++--- modules/reports/views/histogram/histogram.php | 47 +++ .../reports}/views/histogram/js/histogram.js | 31 +- modules/reports/views/histogram/options.php | 91 ++++++ modules/reports/views/reports/header.php | 32 +- 18 files changed, 628 insertions(+), 619 deletions(-) delete mode 100644 application/views/histogram/css/bg.png delete mode 100644 application/views/histogram/css/histogram.css delete mode 100644 application/views/histogram/histogram.php delete mode 100644 application/views/histogram/index.php delete mode 100644 application/views/histogram/options.php delete mode 100644 application/views/histogram/setup.php create mode 100644 features/histogram.feature create mode 100644 modules/reports/views/histogram/histogram.php rename {application => modules/reports}/views/histogram/js/histogram.js (62%) create mode 100644 modules/reports/views/histogram/options.php diff --git a/application/views/histogram/css/bg.png b/application/views/histogram/css/bg.png deleted file mode 100644 index 9f0f91de08f5e966fe13b0b1fc7fa527351f6910..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 48231 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�D*-{uBYd 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 GtiJ&L&THZT diff --git a/application/views/histogram/css/histogram.css b/application/views/histogram/css/histogram.css deleted file mode 100644 index 913f8cf4a..000000000 --- a/application/views/histogram/css/histogram.css +++ /dev/null @@ -1,182 +0,0 @@ -body { margin: 0px; } - -#progress{ - position: absolute; - top:107px; - left:410px; - display: none; -} - -#progress em, -#progress img { - float: left; -} -#progress em { - display: block; - margin-top: 12px; -} - -#response { - margin-left:5px; - padding-top:5px; - background: #f9f9f5 url(default/images/response.png) repeat-x; -} - -#response h1 { - font: bold 12px arial,helvetica,sans-serif; - display: none; -} - -#options_container, -#block_host_states, -#block_service_states{ - display:none; -} - -#response ul { - padding: 7px 2px 5px 50px; - margin: 0px; - margin-bottom: 7px; - width: auto; - background: transparent 7px 5px no-repeat; -} - -#response li { - background: none; - padding: 2px 0px; - width: auto; - list-style: none; -} - -#response ul.ok { background-image: url(icons/32x32/shield-ok.png); } -#response ul.error { background-image: url(icons/32x32/shield-error.png); } -#response ul.warning { background-image: url(icons/32x32/shield-warning.png); } -#response ul.info { background-image: url(icons/32x32/shield-info.png); } -#response ul.help { background-image: url(icons/32x32/shield-help.png); } - -/* nytt */ - -input, -select, -textarea, -input#cal_end, -input.datepick-end, -input.datepick-start, -input#cal_start, -input#time_start, -input#time_end { - background: #fafafa; - border: 1px solid #cccccc; - outline: 0px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - padding: 1px; - width: 378px; - margin-top: 3px; - margin-left: 0px; - margin-bottom: 15px; -} - -select { width: 382px} - -input#cal_end, -input#cal_start, -input.datepick-end, -input.datepick-start, -input#time_start, -input#time_end { - width: 100px; -} - -select[multiple=multiple] { - padding: 3px; - width: 380px; -} - -input[type=button], -input[type=submit], -input[type=reset], -input[type=checkbox], -input[type=radio] { - width: auto -} - -input[type=checkbox], -input[type=radio] { - margin-top: 0px; - margin-left: 0px; - margin-bottom: 5px; -} - -input[type=radio] { border: 0px; } - -input[type=reset], -input[type=submit], -input[type=button] { - background: #cdcdcd url(bg.png) repeat-x; - border: 1px solid #cccccc; - outline: 0px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - padding: 1px 3px; - margin-bottom: 5px; -} - -h1 { font-size: 15px; font-weight: normal; margin: 7px 0px 15px 0px} -h2 { font-weight: normal; font-size: 13px; margin: 7px 0px 15px 3px} - -caption { padding-left:0px} - -#settings_table, -#std_report_table { width: auto; } -#settings_table tr td, -#history_report_table tr td { padding: 0px 5px 0px 0px; background: none;} - -.time_error { - border:1px solid red; - color:red; -} - -div.time-picker { - position: absolute; - height: 200px; - width:9em; /* needed for IE */ - overflow: auto; - background: #fff; - border: 1px solid #000; - z-index: 99; -} -div.time-picker-12hours { - width:6em; /* needed for IE */ -} - -div.time-picker ul { - list-style-type: none; - margin: 0; - padding: 0; -} -div.time-picker li { - padding: 1px; - cursor: pointer; -} -div.time-picker li.selected { - background: #316AC5; - color: #fff; -} - -#report tr td, -#histogram_holder tr td { - background: #ffffff; -} - -#histogram_holder tr.odd td { - background: #f5f5f5; -} - -h1 { font-size: 15px; font-weight: normal; margin: 7px 0px 15px 0px} - -td.ledgedColorBox { width: auto; float; left; } - -#idUp, #idDown, #idUnreachable { margin-right: 5px;} - - diff --git a/application/views/histogram/histogram.php b/application/views/histogram/histogram.php deleted file mode 100644 index 4cad9314a..000000000 --- a/application/views/histogram/histogram.php +++ /dev/null @@ -1,56 +0,0 @@ - -
-

- $print_limit) { - $show_objects = array_slice($objects, 0, $print_limit); - $rest_objects = array_slice($objects, $print_limit); ?> - - ... - -
- - - -

- - - - - - - - - - - -
-

:

-
-
- - - - - - - - - - - - - - - - - -
- -
-
diff --git a/application/views/histogram/index.php b/application/views/histogram/index.php deleted file mode 100644 index 55d98a3d5..000000000 --- a/application/views/histogram/index.php +++ /dev/null @@ -1,9 +0,0 @@ - -
-
- diff --git a/application/views/histogram/options.php b/application/views/histogram/options.php deleted file mode 100644 index 1080a8b39..000000000 --- a/application/views/histogram/options.php +++ /dev/null @@ -1,65 +0,0 @@ - - add_path('icons/32x32/square-edit.png'), - array('alt' => _('edit settings'), 'title' => _('edit settings'), 'style' => 'position: absolute; right: 0px; top: 10px')) - ?> - - - -
-
- 'histogram_form', 'onsubmit' => 'return check_form_values(this);')); ?> - - - - - - - - - - - - - - - - - - - - - - -
'report_period', 'onchange' => 'show_calendar(this.value);'), $options->get_alternatives('report_period'), $options['report_period']); ?>
-
- get_alternatives('state_types'), $options['state_types']) ?> -
-
- get_alternatives('breakdown'), $options['breakdown']) ?> -
-
- - get_alternatives('host_states'), $options['host_states']); - } else { ?> - get_alternatives('service_states'), $options['service_states']); - } ?> - -
- - -
- -
- as_form(false, true); ?> - -
-
diff --git a/application/views/histogram/setup.php b/application/views/histogram/setup.php deleted file mode 100644 index 7294fa847..000000000 --- a/application/views/histogram/setup.php +++ /dev/null @@ -1,75 +0,0 @@ - -
-
- - - -
- -

- -
- 'histogram_form')); ?> - - -
- - - - - - - - - - - - - - - - - - - - - - - -
-
- 'report_period'), $options->get_alternatives('report_period'), $options['report_period']); ?> -
  -
- get_alternatives('state_types')) ?> -
-
- get_alternatives('breakdown'), $options['breakdown']) ?> -
  -
-
- get_alternatives('host_states')) ?> -
-
-
- get_alternatives('service_states')) ?> -
-
- - -
-
- -
diff --git a/application/views/menu/menu.php b/application/views/menu/menu.php index ea86de87f..0c2c6b9d8 100644 --- a/application/views/menu/menu.php +++ b/application/views/menu/menu.php @@ -44,6 +44,7 @@ $menu_items['notifications'] = _('Notifications'); $menu_items['event_log'] = _('Event log'); $menu_items['availability'] = _('Availability'); $menu_items['sla'] = _('SLA Reporting'); +$menu_items['histogram'] = _('Histogram Reporting'); $menu_items['schedule_reports'] = _('Schedule reports'); if (Kohana::config('config.cacti_path')) { @@ -76,7 +77,7 @@ $menu = array( 'network_outages', //'host_problems', 'service_problems', 'unhandled_problems', 'comments', 'scheduled_downtime', 'recurring_downtime', 'process_info', 'scheduling_queue', 'performance_info', 'hyper_map', 'nagvis'), /* remove hardcoded nagvis menu entry */ 'section_reporting' => array('trends', 'pnp', 'alert_history', 'alert_summary', 'notifications', 'event_log', - 'availability', 'sla', 'schedule_reports', 'statistics'), + 'availability', 'sla', 'histogram', 'schedule_reports', 'statistics'), 'section_configuration' => array('view_config', 'my_account', 'backup_restore', 'configure') ); @@ -91,6 +92,7 @@ $section_reporting[$menu_items['notifications']] = array(listview::querylink('[ $section_reporting[$menu_items['event_log']] = array('/showlog/showlog', 'eventlog',0); $section_reporting[$menu_items['availability']] = array('/avail/index', 'availability',0); $section_reporting[$menu_items['sla']] = array('/sla/index', 'sla',0); +$section_reporting[$menu_items['histogram']] = array('/histogram/index', 'histogram',0); $section_reporting[$menu_items['schedule_reports']]= array('/schedule/show', 'schedulereports',0); # base menu (all) diff --git a/application/views/template_head.php b/application/views/template_head.php index d9744c8dc..ed4f21b66 100644 --- a/application/views/template_head.php +++ b/application/views/template_head.php @@ -160,7 +160,6 @@ if (!empty($base_href)) { diff --git a/features/histogram.feature b/features/histogram.feature new file mode 100644 index 000000000..bbffbaf3d --- /dev/null +++ b/features/histogram.feature @@ -0,0 +1,340 @@ +Feature: Histogram reports + Background: + Given I have these hostgroups configured: + | hostgroup_name | + | LinuxServers | + | WindowsServers | + | MixedGroup | + | EmptyGroup | + And I have these hosts: + | host_name | host_groups | + | linux-server1 | LinuxServers,MixedGroup | + | linux-server2 | LinuxServers | + | win-server1 | WindowsServers | + | win-server2 | WindowsServers,MixedGroup | + And I have these servicegroups: + | servicegroup_name | alias | + | pings | ping services plus one non-ping | + | empty | nothing in here | + And I have these services: + | service_description | host_name | check_command | notifications_enabled | active_checks_enabled | service_groups | + | System Load | linux-server1 | check_nrpe!load | 1 | 1 | | + | PING | linux-server1 | check_ping | 1 | 0 | pings | + | System Load | linux-server2 | check_nrpe!load | 1 | 1 | | + | PING | win-server1 | check_ping | 1 | 0 | pings | + | Swap Usage | win-server1 | check_swap | 1 | 0 | pings | + | PING | win-server2 | check_ping | 0 | 1 | pings | + And I have these report data entries: + | timestamp | event_type | flags | attrib | host_name | service_description | state | hard | retry | downtime_depth | output | + | 2013-01-01 12:00:00 | 100 | NULL | NULL | | | 0 | 0 | 0 | NULL | NULL | + | 2013-01-01 12:00:01 | 801 | NULL | NULL | win-server1 | | 0 | 1 | 1 | NULL | OK - laa-laa | + | 2013-01-01 12:00:02 | 801 | NULL | NULL | linux-server1 | | 0 | 1 | 1 | NULL | OK - Sven Melander | + | 2013-01-01 12:00:03 | 701 | NULL | NULL | win-server1 | PING | 0 | 1 | 1 | NULL | OK - po | + | 2013-01-01 12:00:04 | 701 | NULL | NULL | win-server1 | PING | 2 | 0 | 1 | NULL | ERROR - tinky-winky | + | 2013-01-01 12:00:05 | 701 | NULL | NULL | win-server1 | Swap Usage | 3 | 0 | 1 | NULL | UNKNOWN - out of teletubbies | + | 2013-01-01 12:00:02 | 801 | NULL | NULL | linux-server2 | | 0 | 1 | 1 | NULL | PRETTY OK - Jon Skolmen | + And I have activated the configuration + + + @configuration @asmonitor + Scenario: Generate empty report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I click "Show report" + Then I should see "Please select what objects to base the report on" + And I should see "Report Settings" + + @configuration @asmonitor @reports + Scenario: Generate report on empty hostgroup + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "EmptyGroup" from "Available hostgroups" + And I doubleclick "EmptyGroup" + Then "Selected hostgroups" should have option "EmptyGroup" + When I click "Show report" + Then I should see "The groups you selected (EmptyGroup) had no members, so cannot create a report from them" + And I should see "Report Settings" + + @configuration @asmonitor @reports + Scenario: Generate report on empty servicegroup + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Servicegroups" from "Report type" + And I select "empty" from "Available servicegroups" + And I doubleclick "empty" + Then "Selected servicegroups" should have option "empty" + When I click "Show report" + Then I should see "The groups you selected (empty) had no members, so cannot create a report from them" + And I should see "Report Settings" + + @configuration @asmonitor @reports + Scenario: Generate single host report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Hosts" from "Report type" + And I select "linux-server1" from "Available hosts" + And I doubleclick "linux-server1" + Then "Selected hosts" should have option "linux-server1" + When I select "Hard states" from "State types to graph" + And I select "Day of month" from "Statistics breakdown" + And I select "This year" from "Reporting period" + And I click "Show report" + Then I should see "Alert histogram" + And I should see "Included hosts" + And I should see "linux-server1" + And I shouldn't see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate multi host report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Hosts" from "Report type" + And I select "linux-server1" from "Available hosts" + And I doubleclick "linux-server1" + And I select "win-server1" from "Available hosts" + And I doubleclick "win-server1" + Then "Selected hosts" should have option "linux-server1" + And "Selected hosts" should have option "win-server1" + When I select "Monthly" from "Statistics breakdown" + And I click "Show report" + Then I should see "Alert histogram" + And I should see "Included hosts" + And I should see "linux-server1" + And I should see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate single service report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Services" from "Report type" + And I select "linux-server1;PING" from "Available services" + And I doubleclick "linux-server1;PING" + Then "Selected services" should have option "linux-server1;PING" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included services" + And I should see "linux-server1;PING" + And I shouldn't see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate multi service on same host report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Services" from "Report type" + And I select "linux-server1;PING" from "Available services" + And I doubleclick "linux-server1;PING" + And I select "linux-server1;System Load" from "Available services" + And I doubleclick "linux-server1;System Load" + Then "Selected services" should have option "linux-server1;PING" + And "Selected services" should have option "linux-server1;System Load" + When I select "Day of week" from "Statistics breakdown" + And I check "Ignore repeated states" + And I click "Show report" + Then I should see "Alert histogram" + And I should see "Included services" + And I should see "linux-server1;PING" + And I should see "linux-server1;System Load" + And I shouldn't see "linux-server2" + And I shouldn't see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate multi service on different host report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Services" from "Report type" + And I select "linux-server1;PING" from "Available services" + And I doubleclick "linux-server1;PING" + And I select "linux-server2;System Load" from "Available services" + And I doubleclick "linux-server2;System Load" + Then "Selected services" should have option "linux-server1;PING" + And "Selected services" should have option "linux-server2;System Load" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included services" + And I should see "linux-server1;PING" + And I should see "linux-server2;System Load" + + @configuration @asmonitor @reports + Scenario: Generate single hostgroup report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + Then "Selected hostgroups" should have option "LinuxServers" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included hosts" + And I should see "linux-server1" + And I should see "linux-server2" + + @configuration @asmonitor @reports + Scenario: Generate multi hostgroup report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + And I select "WindowsServers" from "Available hostgroups" + And I doubleclick "WindowsServers" + Then "Selected hostgroups" should have option "LinuxServers" + And "Selected hostgroups" should have option "WindowsServers" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included hosts" + And I should see "linux-server1" + And I should see "linux-server2" + And I should see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate hostgroup report with overlapping members + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + And I select "MixedGroup" from "Available hostgroups" + And I doubleclick "MixedGroup" + Then "Selected hostgroups" should have option "LinuxServers" + And "Selected hostgroups" should have option "MixedGroup" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included hosts" + And I should see "linux-server1" + And I should see "linux-server2" + And I shouldn't see "win-server1" + + @configuration @asmonitor @reports + Scenario: Generate single servicegroup report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Servicegroups" from "Report type" + And I select "pings" from "Available servicegroups" + And I doubleclick "pings" + Then "Selected servicegroups" should have option "pings" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included services" + And I should see "linux-server1;PING" + + @configuration @asmonitor @reports + Scenario: Generate multi servicegroup report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "Servicegroups" from "Report type" + And I select "pings" from "Available servicegroups" + And I doubleclick "pings" + And I select "empty" from "Available servicegroups" + And I doubleclick "empty" + Then "Selected servicegroups" should have option "pings" + And "Selected servicegroups" should have option "empty" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Included services" + And I should see "linux-server1;PING" + + @configuration @asmonitor @reports + Scenario: Generate report on custom report date + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + Then "Selected hostgroups" should have option "LinuxServers" + When I select "Custom" from "Reporting period" + And I enter "2013-01-02" into "Start date" + And I enter "23:31" into "time_start" + And I enter "2013-04-03" into "End date" + And I enter "22:32" into "time_end" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Reporting period: 2013-01-02 23:31:00 to 2013-04-03 22:32:00" + + @configuration @asmonitor @reports + Scenario: Generate report on custom report date without time specified + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + And I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + Then "Selected hostgroups" should have option "LinuxServers" + When I select "Custom" from "Reporting period" + And I enter "2013-01-02" into "Start date" + And I enter "" into "time_start" + And I enter "2013-04-03" into "End date" + And I enter "" into "time_end" + When I click "Show report" + Then I should see "Alert histogram" + And I should see "Reporting period: 2013-01-02 00:00:00 to 2013-04-03 23:59:00" + + @configuration @asmonitor @reports + Scenario: Save report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + Then I shouldn't see "Saved reports" + #And "Saved reports" shouldn't have option "saved test report" + When I select "LinuxServers" from "Available hostgroups" + And I doubleclick "LinuxServers" + Then "Selected hostgroups" should have option "LinuxServers" + # Toggle *everything*! + When I select "Last month" from "Reporting period" + And I select "Day of week" from "Statistics breakdown" + And I select "Soft states" from "State types to graph" + And I check "Ignore repeated states" + And I select "pink_n_fluffy" from "Skin" + And I enter "This is a saved test report" into "Description" + And I click "Show report" + # I don't care where, but I want everything to be visible somehow + Then I should see "Last month" + And I should see "Alert histogram" + And I should see "This is a saved test report" + When I click "Save report" + And I enter "saved test report" into "report_name" + And I click "Save report" inside "#save_report_form" + Then I should see "Report was successfully saved" + + @configuration @asmonitor @reports + Scenario: View saved report + Given I am on the Host details page + When I hover over the "Reporting" button + And I click "Histogram" + Then I should see "Saved reports" + And "Saved reports" should have option "saved test report" + When I select "saved test report" from "Saved reports" + Then "Selected hostgroups" should have option "LinuxServers" + And "Last month" should be selected from "Reporting period" + And "Day of week" should be selected from "Statistics breakdown" + And "Soft states" should be selected from "State types to graph" + And "Ignore repeated states" should be checked + And "pink_n_fluffy" should be selected from "Skin" + And "Description" should contain "This is a saved test report" + When I click "Show report" + Then I should see "Last month" + And I should see "Alert histogram" + And I should see "This is a saved test report" + + @configuration @asmonitor @reports + Scenario: Delete previously created report + Given I am on the Host details page + And I hover over the "Reporting" button + When I click "Histogram" + Then I should see "Saved reports" + And "Saved reports" should have option "saved test report" + When I select "saved test report" + Then "Selected hostgroups" should have option "LinuxServers" + When I click "Delete" + # Test available first, to force capybara to wait for page reload + Then "Available hostgroups" should have option "LinuxServers" + And "Saved reports" shouldn't have option "saved test report" + And "Selected hostgroups" shouldn't have option "LinuxServers" diff --git a/features/reports.feature b/features/reports.feature index 441a854ae..9485cc320 100644 --- a/features/reports.feature +++ b/features/reports.feature @@ -20,6 +20,9 @@ Feature: Reports When I hover over the "Reporting" button And I click "Schedule Reports" Then all helptexts should be defined + When I hover over the "Reporting" button + And I click "Histogram Reports" + Then all helptexts should be defined @asmonitor @reports @calendar Scenario: Toggle JS-calendars on custom report date diff --git a/modules/reports/controllers/histogram.php b/modules/reports/controllers/histogram.php index 5d8deed7b..c6c2a1652 100644 --- a/modules/reports/controllers/histogram.php +++ b/modules/reports/controllers/histogram.php @@ -13,7 +13,6 @@ */ class Histogram_Controller extends Base_reports_Controller { - public $data = false; /**< Awesomely named variable for passing the result of the histogram method in the summary report model */ private $labels = array(); public $type = 'histogram'; @@ -25,16 +24,26 @@ class Histogram_Controller extends Base_reports_Controller $this->setup_options_obj($input); $this->template->disable_refresh = true; - $this->template->content = $this->add_view('histogram/setup'); + $this->template->content = $this->add_view('reports/setup'); $template = $this->template->content; + if(isset($_SESSION['report_err_msg'])) { + $template->error_msg = $_SESSION['report_err_msg']; + unset($_SESSION['report_err_msg']); + } + + $template->saved_reports = $this->options->get_all_saved(); + $scheduled_info = false; + if ($this->options['report_id']) { + $scheduled_info = Scheduled_reports_Model::report_is_scheduled($this->type, $this->options['report_id']); + } + $template->scheduled_info = $scheduled_info; + $template->report_options = $this->add_view('histogram/options'); $this->xtra_js[] = 'application/media/js/jquery.datePicker.js'; $this->xtra_js[] = 'application/media/js/jquery.timePicker.js'; $this->xtra_js[] = $this->add_path('reports/js/common.js'); - $this->xtra_js[] = $this->add_path('histogram/js/histogram.js'); $this->xtra_css[] = $this->add_path('reports/css/datePicker.css'); - $this->xtra_css[] = $this->add_path('histogram/css/histogram.css'); $this->js_strings .= reports::js_strings(); $this->js_strings .= "var _reports_error = '"._('Error')."';\n"; @@ -54,78 +63,13 @@ class Histogram_Controller extends Base_reports_Controller $this->xtra_js[] = 'application/media/js/jquery.flot.min.js'; $this->xtra_js[] = 'application/media/js/jquery.datePicker.js'; $this->xtra_js[] = 'application/media/js/jquery.timePicker.js'; + $this->xtra_js[] = 'application/media/js/excanvas.compiled.js'; $this->xtra_js[] = $this->add_path('reports/js/common.js'); - $this->xtra_js[] = $this->add_path('histogram/js/histogram.js'); + $this->xtra_js[] = ninja::add_path('histogram/js/histogram.js', 'reports'); $this->xtra_css[] = $this->add_path('reports/css/datePicker.css'); - $this->xtra_css[] = $this->add_path('histogram/css/histogram.css'); $rpt = new Summary_Reports_Model($this->options); - $hostgroup = false; - $hostname = false; - $servicegroup = false; - $service = false; - - $group_name = false; - $title = _('Event history for '); - $objects = false; - switch ($this->options['report_type']) { - case 'hostgroups': - $sub_type = "host"; - $hostgroup = $this->options['hostgroup']; - $group_name = $hostgroup; - $title .= _('Hostgroup(s): '); - $this->object_varname = 'host_name'; - $objects = $this->options['hostgroup']; - break; - case 'servicegroups': - $sub_type = "service"; - $servicegroup = $this->options['servicegroup']; - $group_name = $servicegroup; - $title .= _('Servicegroup(s): '); - $this->object_varname = 'service_description'; - $objects = $this->options['servicegroup']; - break; - case 'hosts': - $sub_type = "host"; - $hostname = $this->options['host_name']; - $title .= _('Host(s): '); - $this->object_varname = 'host_name'; - if (is_array($this->options['host_name'])) { - $objects = $this->options['host_name']; - } else { - $objects[] = $this->options['host_name']; - } - break; - case 'services': - $sub_type = "service"; - $service = $this->options['service_description']; - $title .= _('Service(s): '); - $tmp_obj = false; - if (is_array($service)) { - foreach ($service as $s) { - if (strstr($s, ';')) { - $tmp = explode(';', $s); - $tmp_obj[] = "'".$tmp[1]."' "._('On Host')." '".$tmp[0]."' "; - } else { - $tmp_obj[] = "'".$s."' "._('On Host')." '".$this->options['host_name']."' "; - } - } - if (!empty($tmp_obj)) { - $objects = $tmp_obj; - } - } else { - if (strstr($service, ';')) { - $tmp = explode(';', $service); - $objects[] = "'".$tmp[1]."' "._('On Host')." '".$tmp[0]."' "; - } else { - $objects[] = "'".$service."' "._('On Host')." '".$this->options['host_name']."' "; - } - } - $this->object_varname = 'service_description'; - break; - default: - return url::redirect(Router::$controller.'/index'); - } + $title = _('Alert histogram'); $breakdown_keys = false; switch ($this->options['breakdown']) { @@ -147,23 +91,19 @@ class Histogram_Controller extends Base_reports_Controller } $histogram_data = $rpt->histogram($breakdown_keys); - $min = false; - $max = false; - $avg = false; - $sum = false; - - if (!empty($histogram_data)) { - # pull the data from the returned array - $this->data = isset($histogram_data['data']) ? $histogram_data['data'] : false; - $min = isset($histogram_data['min']) ? $histogram_data['min'] : false; - $max = isset($histogram_data['max']) ? $histogram_data['max'] : false; - $avg = isset($histogram_data['avg']) ? $histogram_data['avg'] : false; - $sum = isset($histogram_data['sum']) ? $histogram_data['sum'] : false; - } + # pull the data from the returned array + $data = isset($histogram_data['data']) ? $histogram_data['data'] : array(); + $min = isset($histogram_data['min']) ? $histogram_data['min'] : array(); + $max = isset($histogram_data['max']) ? $histogram_data['max'] : array(); + $avg = isset($histogram_data['avg']) ? $histogram_data['avg'] : array(); + $sum = isset($histogram_data['sum']) ? $histogram_data['sum'] : array(); $sub_type = false; + $is_group = false; switch ($this->options['report_type']) { - case 'hosts': case 'hostgroups': + case 'hostgroups': + $is_group = true; + case 'hosts': $state_names = array( Reports_Model::HOST_UP => _('UP'), Reports_Model::HOST_DOWN => _('DOWN'), @@ -171,7 +111,9 @@ class Histogram_Controller extends Base_reports_Controller ); $sub_type = 'host'; break; - case 'services': case 'servicegroups': + case 'servicegroups': + $is_group = true; + case 'services': $state_names = array( Reports_Model::SERVICE_OK => _('OK'), Reports_Model::SERVICE_WARNING => _('WARNING'), @@ -182,52 +124,41 @@ class Histogram_Controller extends Base_reports_Controller break; } - $this->inline_js .= "var graph_options = {legend: {show: true,container: $('#overviewLegend')},xaxis:{ticks:".$this->_get_xaxis_ticks()."},bars:{align:'center'}, grid: { hoverable: true, clickable: true }, yaxis:{min:0}};"; - $this->js_strings .= "var graph_xlables = new Array(".implode(',', $this->labels).");"; + $report_members = $this->options->get_report_members(); + if (empty($report_members)) { + if (!$is_group) + $_SESSION['report_err_msg'] = _("You didn't select any objects to include in the report"); + else + $_SESSION['report_err_msg'] = sprintf(_("The groups you selected (%s) had no members, so cannot create a report from them"), implode(', ', $this->options['objects'])); + return url::redirect(Router::$controller.'/index?' . http_build_query($this->options->options)); + } + + $this->js_strings .= "var graph_options = {legend: {show: true,container: $('#overviewLegend')},xaxis:{ticks:".json_encode($this->_get_xaxis_ticks($data))."},bars:{align:'center'}, grid: { hoverable: true, clickable: true }, yaxis:{min:0}};\n"; + $this->js_strings .= "var graph_xlables = ".json_encode($this->labels).";\n"; $this->js_strings .= reports::js_strings(); - $data = $this->_prepare_graph_data(); + $data = $this->_prepare_graph_data($data); $datasets = array(); - $this->inline_js .= "var datasets = {"; $states = array_keys($state_names); foreach ($data as $key => $val) { - $datasets[] = "'".ucfirst(strtolower($state_names[$key]))."': {label: '".ucfirst(strtolower($state_names[$key]))."', data: [".implode(',', $val)."], color:'".reports::_state_colors($sub_type, $states[$key])."', bars: { show: true}}"; + $datasets[ucfirst(strtolower($state_names[$key]))] = array('label' => ucfirst(strtolower($state_names[$key])), 'data' => $val, 'color' => reports::_state_colors($sub_type, $states[$key]), 'bars' => array('show' => true)); } - $this->inline_js .= implode(',', $datasets).'};'; - - $this->inline_js .= "var choiceContainer = $('#choices'); - $.each(datasets, function(key, val) { - choiceContainer.append('
' + - ''); - }); - choiceContainer.find(\"input\").click(plotAccordingToChoices); - - function plotAccordingToChoices() { - var data = []; + $this->js_strings .= 'var datasets = '.json_encode($datasets).";\n"; - choiceContainer.find(\"input:checked\").each(function () { - var key = $(this).attr(\"name\"); - if (key && datasets[key]) - data.push(datasets[key]); - }); - - if (data.length > 0) - $.plot($('#histogram_graph'), data, graph_options); - } - - plotAccordingToChoices();"; + $this->template->content = $this->add_view('reports/index'); + $base = $this->template->content; - $this->template->content = $this->add_view('histogram/index'); + $base->header = $this->add_view('reports/header'); + $base->header->title = $title; + $base->header->report_time_formatted = $this->format_report_time(nagstat::date_format()); + $base->header->skip_csv = true; + $base->header->skip_pdf = true; - $base = $this->template->content; $base->content = $this->add_view("histogram/histogram"); $content = $base->content; - $content->state_names = $state_names; $content->min = $min; $content->max = $max; @@ -235,16 +166,13 @@ class Histogram_Controller extends Base_reports_Controller $content->sum = $sum; $content->states = $state_names; $content->available_states = array_keys($min); - $content->title = $title; - $content->objects = $objects; + $content->objects = $this->options['objects']; $timeformat_str = nagstat::date_format(); $content->report_time = date($timeformat_str, $this->options['start_time']).' '._('to').' '.date($timeformat_str, $this->options['end_time']); $this->template->content->report_options = $this->add_view('histogram/options'); $tpl_options = $this->template->content->report_options; - $tpl_options->sub_type = $sub_type; - $this->template->inline_js = $this->inline_js; $this->template->js_strings = $this->js_strings; $this->template->title = _('Reporting » Histogram » Report'); @@ -254,52 +182,44 @@ class Histogram_Controller extends Base_reports_Controller * Replace all integer indicies with proper * translated strings */ - public function _get_xaxis_ticks() + private function _get_xaxis_ticks($data) { - if (empty($this->data)) { - return false; - } - $return = false; $i = 0; - foreach ($this->data as $key => $data) { + foreach ($data as $key => $values) { switch ($this->options['breakdown']) { case 'dayofmonth': - $return[] = '['.$i.', '.$key.']'; - $this->labels[] = "'".$key."'"; + $return[] = array($i, $key); + $this->labels[] = $key; break; case 'monthly': - $return[] = '['.$i.', "'.$key.'"]'; + $return[] = array($i, $key); $this->labels[] = "'".$key."'"; break; case 'dayofweek': - $return[] = '['.$i.', "'.$key.'"]'; - $this->labels[] = "'".$key."'"; + $return[] = array($i, $key); + $this->labels[] = $key; break; case 'hourly': - $return[] = '['.$i.', "'.$key.':00'.'"]'; - $this->labels[] = "'".$key.':00'."'"; + $return[] = array($i, $key.':00'); + $this->labels[] = $key.':00'; break; } $i++; } - return '['.implode(',', $return).']'; + return $return; } /** * Prepare data structore for use in histogram */ - public function _prepare_graph_data($data=false) + private function _prepare_graph_data($data) { - if (empty($this->data)) { - return false; - } - - $return = false; + $return = array(); $i = 0; # graph data needs to have 0 indicies - foreach ($this->data as $key => $data) { - foreach ($data as $k => $v) { - $return[$k][] = '['.$i.','.$v.']'; + foreach ($data as $key => $value) { + foreach ($value as $k => $v) { + $return[$k][] = array($i, $v); } $i++; } diff --git a/modules/reports/libraries/Histogram_options.php b/modules/reports/libraries/Histogram_options.php index ff6d36f87..4106950e4 100644 --- a/modules/reports/libraries/Histogram_options.php +++ b/modules/reports/libraries/Histogram_options.php @@ -3,7 +3,7 @@ /** * Report options for histogram reports */ -class Histogram_options_Core extends Report_options +class Histogram_options_Core extends Summary_options { public static $type = 'histogram'; diff --git a/modules/reports/libraries/Summary_options.php b/modules/reports/libraries/Summary_options.php index a032a9dfd..c413ff286 100644 --- a/modules/reports/libraries/Summary_options.php +++ b/modules/reports/libraries/Summary_options.php @@ -118,6 +118,7 @@ class Summary_options extends Report_options break; default: + var_dump('unknown standard report'); Kohana::debug("Unknown standard report: $value"); die; } diff --git a/modules/reports/models/summary_reports.php b/modules/reports/models/summary_reports.php index ee5fb0320..3761630d4 100644 --- a/modules/reports/models/summary_reports.php +++ b/modules/reports/models/summary_reports.php @@ -22,7 +22,7 @@ class Summary_Reports_Model extends Reports_Model $query = $this->build_alert_summary_query ('timestamp, event_type, host_name, service_description, ' . 'state, hard, retry, downtime_depth, output', - true, array(), null, $auth); + true, array(), $auth); // investigate if there are more rows available for this query, // with another set of pagination parameters @@ -76,22 +76,15 @@ class Summary_Reports_Model extends Reports_Model * @param $fields string Comma separated list of database columns the caller needs * @param $is_api_call boolean = false * @param $blacklisted_criteria array = array() - * @param $db_table string = null * @param $auth auth module to use, if not using default * @return string (sql) */ - function build_alert_summary_query($fields = null, $is_api_call = false, $blacklisted_criteria = array(), $db_table = null, $auth = null) + function build_alert_summary_query($fields = null, $is_api_call = false, $blacklisted_criteria = array(), $auth = null) { if(!$fields) { // default to the most commonly used fields $fields = 'host_name, service_description, state, hard'; } - if(!$db_table) - { - // this method ('s purpose) is so good I wanna copy it.. but that's not feasable, - // so I'm just gonna pretend it does dependency injection - $db_table = $this->db_table; - } if(!$auth) { $auth = op5auth::instance(); } @@ -161,7 +154,7 @@ class Summary_Reports_Model extends Reports_Model } if (empty($hosts) && empty($services) && !$is_api_call) { - return "SELECT $fields FROM $db_table LIMIT 0"; + return "SELECT $fields FROM $this->db_table LIMIT 0"; } $object_selection = false; @@ -275,7 +268,7 @@ class Summary_Reports_Model extends Reports_Model "\n OR UPPER(service_description) LIKE $wc_str_esc"; } - $query = "SELECT " . $fields . "\nFROM " . $db_table; + $query = "SELECT " . $fields . "\nFROM " . $this->db_table; $query .= ' WHERE '. sql::combine('and', $time_first, @@ -680,7 +673,7 @@ class Summary_Reports_Model extends Reports_Model public function histogram($slots=false) { if (empty($slots) || !is_array($slots)) - return false; + return array(); $breakdown = $this->options['breakdown']; $report_type = $this->options['report_type']; @@ -694,39 +687,39 @@ class Summary_Reports_Model extends Reports_Model $events = array(0 => 0, 1 => 0, 2 => 0); } else { $events = array(); - for ($i = 0; $i < 7; $i++) { + for ($i = 0; $i <= 2; $i++) { if (1 << $i & $this->options['host_states']) { $events[$i] = 0; } } } + $this->options['alert_types'] = 1; break; case 'services': case 'servicegroups': if (!$this->options['service_states'] || $this->options['service_states'] == self::SERVICE_ALL) { $events = array(0 => 0, 1 => 0, 2 => 0, 3 => 0); } else { $events = array(); - for ($i = 0; $i < 15; $i++) { + for ($i = 0; $i <= 3; $i++) { if (1 << $i & $this->options['service_states']) { $events[$i] = 0; } } } + $this->options['alert_types'] = 2; break; } # add event (state) counters to slots - $fixed_slots = false; + $data = false; foreach ($slots as $s => $l) { - $fixed_slots[$l] = $events; + $data[$l] = $events; } # fields to fetch from db $fields = 'timestamp, event_type, host_name, service_description, state, hard, retry'; $query = $this->build_alert_summary_query($fields); - $data = false; - # tell histogram_data() how to treat timestamp $date_str = false; switch ($breakdown) { @@ -744,61 +737,42 @@ class Summary_Reports_Model extends Reports_Model break; } - $data = $this->histogram_data($query, $date_str, $fixed_slots, $newstatesonly); - - $min = $events; - $max = $events; - $avg = $events; - $sum = $events; - if (!empty($data)) { - foreach ($data as $slot => $slotstates) { - foreach ($slotstates as $id => $val) { - if ($val > $max[$id]) $max[$id] = $val; - if ($val < $min[$id]) $min[$id] = $val; - $sum[$id] += $val; - } - } - foreach ($max as $v => $k) { - if ($k != 0) { - $avg[$v] = number_format(($k/count($data)), 2); - } - } - return array('min' => $min, 'max' => $max, 'avg' => $avg, 'sum' => $sum, 'data' => $data); - } - return false; - } - - /** - * Populate slots for histogram - * - * @param $query sql - * @param $date_str string for use in PHP date() - * @param $slots array with slots to fill with data - * @param $newstatesonly bool Used to decide if to ignore repated events or not - * @return array Populated slots array with found data - */ - public function histogram_data($query, $date_str='j' , $slots=false, $newstatesonly=false) - { - if (empty($slots)) { - return false; - } - $res = $this->db->query($query)->result(false); if (!$res) { - return false; + return array(); } $last_state = null; foreach ($res as $row) { if ($newstatesonly) { if ($row['state'] != $last_state) { # only count this state if it differs from the last - $slots[date($date_str, $row['timestamp'])][$row['state']]++; + $data[date($date_str, $row['timestamp'])][$row['state']]++; } } else { - $slots[date($date_str, $row['timestamp'])][$row['state']]++; + $data[date($date_str, $row['timestamp'])][$row['state']]++; } $last_state = $row['state']; } - return $slots; + + $min = $events; + $max = $events; + $avg = $events; + $sum = $events; + if (empty($data)) + return array(); + + foreach ($data as $slot => $slotstates) { + foreach ($slotstates as $id => $val) { + if ($val > $max[$id]) $max[$id] = $val; + if ($val < $min[$id]) $min[$id] = $val; + $sum[$id] += $val; + } + } + foreach ($max as $v => $k) { + if ($k != 0) { + $avg[$v] = number_format(($k/count($data)), 2); + } + } + return array('min' => $min, 'max' => $max, 'avg' => $avg, 'sum' => $sum, 'data' => $data); } } diff --git a/modules/reports/views/histogram/histogram.php b/modules/reports/views/histogram/histogram.php new file mode 100644 index 000000000..1b2b73162 --- /dev/null +++ b/modules/reports/views/histogram/histogram.php @@ -0,0 +1,47 @@ + +
+ + + + + + + + + + +
+

:

+
+
+ + + + + + + + + + + + + + + + + +
+ +
+
+
+

+ +get_report_members() as $object) { + echo ''; +} ?> +
'.$object.'
+
diff --git a/application/views/histogram/js/histogram.js b/modules/reports/views/histogram/js/histogram.js similarity index 62% rename from application/views/histogram/js/histogram.js rename to modules/reports/views/histogram/js/histogram.js index 859692bf8..3c5bab176 100644 --- a/application/views/histogram/js/histogram.js +++ b/modules/reports/views/histogram/js/histogram.js @@ -1,9 +1,4 @@ $(document).ready(function() { - $("#histogram_form").bind('submit', function() { - loopElements(); - return check_form_values(); - }); - var previousPoint = null; $("#histogram_graph").bind("plothover", function (event, pos, item) { $("#x").text(pos.x.toFixed(2)); @@ -26,14 +21,34 @@ $(document).ready(function() { previousPoint = null; } }); - $("#report_period").bind('change', function() { - show_calendar($(this).attr('value')); - }); $('#show_all_objects').click(function() { $('#all_objects').toggle('slow'); }); + var choiceContainer = $('#choices'); + $.each(datasets, function(key, val) { + choiceContainer.append('
' + + ''); + }); + choiceContainer.find("input").click(plotAccordingToChoices); + + function plotAccordingToChoices() { + var data = []; + + choiceContainer.find("input:checked").each(function () { + var key = $(this).attr("name"); + if (key && datasets[key]) + data.push(datasets[key]); + }); + + if (data.length > 0) + $.plot($('#histogram_graph'), data, graph_options); + } + + plotAccordingToChoices(); }); function get_label(x) diff --git a/modules/reports/views/histogram/options.php b/modules/reports/views/histogram/options.php new file mode 100644 index 000000000..f7a6e5d8b --- /dev/null +++ b/modules/reports/views/histogram/options.php @@ -0,0 +1,91 @@ +
+

+
+ + +
+ + + + + +
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 'report_period', 'onchange' => 'show_calendar(this.value);'), $options->get_alternatives('report_period'), $options['report_period']); ?> +
  +
+ get_alternatives('breakdown'), $options['breakdown']) ?> +
+
+ get_alternatives('state_types'), $options['state_types']) ?> +
  +
+
+ get_alternatives('host_states'), $options['host_states']); ?> +
+
+ get_alternatives('service_states'), $options['service_states']); ?> +
+
+ + +
+
+ + +
+ + +
+ 'skin'), ninja::get_skins(), $options['skin']); ?> + + +
+
+ +
+ +
+ diff --git a/modules/reports/views/reports/header.php b/modules/reports/views/reports/header.php index b1d90295e..bc43b3faa 100644 --- a/modules/reports/views/reports/header.php +++ b/modules/reports/views/reports/header.php @@ -1,21 +1,25 @@