Skip to content

Commit

Permalink
Add a new alerts statistics module
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Subiron committed Oct 17, 2017
1 parent c13db68 commit fe1abab
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 17 deletions.
21 changes: 21 additions & 0 deletions module/plugins/stats/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/python

# -*- coding: utf-8 -*-

# Copyright (C) 2009-2012:
# Guillaume Subiron, [email protected]
#
# This file is part of Shinken.
#
# Shinken is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Shinken is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Shinken. If not, see <http://www.gnu.org/licenses/>.
88 changes: 88 additions & 0 deletions module/plugins/stats/stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/python

# -*- coding: utf-8 -*-

# Copyright (C) 2009-2014:
# Guillaume Subiron, [email protected]
#
# This file is part of Shinken.
#
# Shinken is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Shinken is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Shinken. If not, see <http://www.gnu.org/licenses/>.

import time
import urllib

from collections import Counter

### Will be populated by the UI with it's own value
app = None


def get_global_stats():
user = app.bottle.request.environ['USER']
user.is_administrator() or app.redirect403()

range_end = int(time.time())
range_start = int(app.request.GET.get('range_start', range_end - 2592000))

logs = list(app.logs_module.get_ui_logs(range_start=range_start, range_end=range_end, filters={'type': 'SERVICE NOTIFICATION', 'command_name': 'notify-service-by-hubot'}, limit=None))
hosts = Counter()
services = Counter()
hostsservices = Counter()
for l in logs:
hosts[l['host_name']] += 1
services[l['service_description']] += 1
hostsservices[l['host_name'] + '/' + l['service_description']] += 1
return {'hosts': hosts, 'services': services, 'hostsservices': hostsservices}

def get_service_stats(name):
user = app.bottle.request.environ['USER']
user.is_administrator() or app.redirect403()

range_end = int(time.time())
range_start = int(app.request.GET.get('range_start', range_end - 2592000))

logs = list(app.logs_module.get_ui_logs(range_start=range_start, range_end=range_end, filters={'type': 'SERVICE NOTIFICATION', 'command_name': 'notify-service-by-hubot', 'service_description': name}, limit=None))
hosts = Counter()
for l in logs:
hosts[l['host_name']] += 1
return {'service': name, 'hosts': hosts}

def get_host_stats(name):
user = app.bottle.request.environ['USER']
user.is_administrator() or app.redirect403()

range_end = int(time.time())
range_start = int(app.request.GET.get('range_start', range_end - 2592000))

logs = list(app.logs_module.get_ui_logs(range_start=range_start, range_end=range_end, filters={'type': 'SERVICE NOTIFICATION', 'command_name': 'notify-service-by-hubot', 'host_name': name}, limit=None))
services = Counter()
for l in logs:
services[l['service_description']] += 1
return {'host': name, 'services': services}


pages = {
get_global_stats: {
'name': 'GlobalStats', 'route': '/stats', 'view': 'stats'
},

get_service_stats: {
'name': 'Stats', 'route': '/stats/service/<name:path>', 'view': 'stats_service'
},

get_host_stats: {
'name': 'Stats', 'route': '/stats/host/<name:path>', 'view': 'stats_host'
}
}
55 changes: 55 additions & 0 deletions module/plugins/stats/views/stats.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
%rebase("layout", css=['logs/css/logs.css'], js=['logs/js/history.js'], title='Alert Statistics on the last 30 days')

%total = sum(hosts.values())

<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ total }} host alerts</h3></div>
<table class="table table-striped table-condensed">
%for l in hosts.most_common(15):
<tr><td width="160px">{{ l[1] }} ({{ round((l[1] / float(total)) * 100, 1) }}%)</td><td><a href="/stats/host/{{ l[0] }}">{{ l[0] }}</a></td></tr>
%end
%other = sum((h[1] for h in hosts.most_common()[15:]))
<tr><td>{{ other }} ({{ round((other / float(total)) * 100, 1) }}%)</td><td><strong>Others</strong></td></tr>
</table>
</div>
</div>

<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ total }} services alerts</h3></div>
<table class="table table-striped table-condensed">
%for l in services.most_common(15):
<tr><td width="160px">{{ l[1] }} ({{ round((l[1] / float(total)) * 100, 1) }}%)</td><td><a href="/stats/service/{{ l[0] }}">{{ l[0] }}</a></td></tr>
%end
%other = sum((s[1] for s in services.most_common()[15:]))
<tr><td>{{ other }} ({{ round((other / float(total)) * 100, 1) }}%)</td><td><strong>Others</strong></td></tr>
</table>
</div>
</div>

<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ total }} hosts/services alerts</h3></div>
<table class="table table-striped table-condensed">
%for l in hostsservices.most_common(15):
<tr><td width="160px">{{ l[1] }} ({{ round((l[1] / float(total)) * 100, 1) }}%)</td><td>{{ l[0] }}</td></tr>
%end
%other = sum((h[1] for h in hostsservices.most_common()[15:]))
<tr><td>{{ other }} ({{ round((other / float(total)) * 100, 1) }}%)</td><td><strong>Others</strong></td></tr>
</table>
</div>
</div>

<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-body">
<div id="inner_history" data-logclass="3" data-commandname="notify-service-by-slack">
</div>

<div class="text-center" id="loading-spinner">
<h3><i class="fa fa-spinner fa-spin"></i> Loading history data…</h3>
</div>
</div>
</div>
</div>
29 changes: 29 additions & 0 deletions module/plugins/stats/views/stats_host.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
%rebase("layout", css=['logs/css/logs.css'], js=['logs/js/history.js'], title='Alert Statistics on the last 30 days for ' + host)

%total = sum(services.values())

<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ total }} {{ host }} alerts</h3></div>
<table class="table table-striped table-condensed">
%for l in services.most_common(15):
<tr><td>{{ l[1] }} ({{ round((l[1] / float(total)) * 100, 1) }}%)</td><td><a href="/stats/service/{{ l[0] }}">{{ l[0] }}</a></td></tr>
%end
%other = sum((h[1] for h in services.most_common()[15:]))
<tr><td>{{ other }} ({{ round((other / float(total)) * 100, 1) }}%)</td><td><strong>Others</strong></td></tr>
</table>
</div>
</div>

<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-body">
<div id="inner_history" data-host='{{ host }}' data-logclass="3" data-commandname="notify-service-by-slack">
</div>

<div class="text-center" id="loading-spinner">
<h3><i class="fa fa-spinner fa-spin"></i> Loading history data…</h3>
</div>
</div>
</div>
</div>
29 changes: 29 additions & 0 deletions module/plugins/stats/views/stats_service.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
%rebase("layout", css=['logs/css/logs.css'], js=['logs/js/history.js'], title='Alert Statistics on the last 30 days for ' + service)

%total = sum(hosts.values())

<div class="col-lg-4">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ total }} {{ service }} alerts</h3></div>
<table class="table table-striped table-condensed">
%for l in hosts.most_common(15):
<tr><td>{{ l[1] }} ({{ round((l[1] / float(total)) * 100, 1) }}%)</td><td><a href="/stats/host/{{ l[0] }}">{{ l[0] }}</a></td></tr>
%end
%other = sum((h[1] for h in hosts.most_common()[15:]))
<tr><td>{{ other }} ({{ round((other / float(total)) * 100, 1) }}%)</td><td><strong>Others</strong></td></tr>
</table>
</div>
</div>

<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-body">
<div id="inner_history" data-service='{{ service }}' data-logclass="3" data-commandname="notify-service-by-slack">
</div>

<div class="text-center" id="loading-spinner">
<h3><i class="fa fa-spinner fa-spin"></i> Loading history data…</h3>
</div>
</div>
</div>
</div>
35 changes: 18 additions & 17 deletions module/views/header_element.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -186,42 +186,43 @@
<li> <a href="#"><i class="fa fa-sitemap sidebar-icon"></i>
Groups and tags<i class="fa arrow"></i></a>
<ul class="nav nav-second-level">
<li> <a href="{{ app.get_url('HostsGroups') }}"> <span class="fa fa-sitemap"></span> Hosts groups </a> </li>
<li> <a href="{{ app.get_url('ServicesGroups') }}"> <span class="fa fa-sitemap"></span> Services groups </a> </li>
<li> <a href="{{ app.get_url('HostsTags') }}"> <span class="fa fa-tags"></span> Hosts tags </a> </li>
<li> <a href="{{ app.get_url('ServicesTags') }}"> <span class="fa fa-tags"></span> Services tags </a> </li>
<li> <a href="{{ app.get_url('HostsGroups') }}"> <span class="fa fa-sitemap sidebar-icon"></span> Hosts groups </a> </li>
<li> <a href="{{ app.get_url('ServicesGroups') }}"> <span class="fa fa-sitemap sidebar-icon"></span> Services groups </a> </li>
<li> <a href="{{ app.get_url('HostsTags') }}"> <span class="fa fa-tags sidebar-icon"></span> Hosts tags </a> </li>
<li> <a href="{{ app.get_url('ServicesTags') }}"> <span class="fa fa-tags sidebar-icon"></span> Services tags </a> </li>
</ul>
</li>
<li> <a href="#"><i class="fa fa-bar-chart sidebar-icon"></i>
Tactical views<i class="fa arrow"></i></a>
<ul class="nav nav-second-level">
<li> <a href="{{ app.get_url('Impacts') }}"> <span class="fa fa-bolt"></span> Impacts </a> </li>
<li> <a href="{{ app.get_url('Minemap') }}"> <span class="fa fa-table"></span> Minemap </a> </li>
<li> <a href="{{ app.get_url('Worldmap') }}"> <span class="fa fa-globe"></span> World map </a> </li>
<li> <a href="{{ app.get_url('Wall') }}"> <span class="fa fa-th-large"></span> Wall </a> </li>
<li> <a href="{{ app.get_url('Impacts') }}"> <span class="fa fa-bolt sidebar-icon"></span> Impacts </a> </li>
<li> <a href="{{ app.get_url('Minemap') }}"> <span class="fa fa-table sidebar-icon"></span> Minemap </a> </li>
<li> <a href="{{ app.get_url('Worldmap') }}"> <span class="fa fa-globe sidebar-icon"></span> World map </a> </li>
<li> <a href="{{ app.get_url('Wall') }}"> <span class="fa fa-th-large sidebar-icon"></span> Wall </a> </li>
%if app.logs_module.is_available():
<li> <a href="{{ app.get_url('Availability') }}"> <span class="fa fa-bar-chart"></span> Availability </a> </li>
<li> <a href="{{ app.get_url('Availability') }}"> <span class="fa fa-bar-chart sidebar-icon"></span> Availability </a> </li>
%end
</ul>
</li>
%if user.is_administrator():
<li> <a href="#"><i class="fa fa-gears sidebar-icon"></i>
System<i class="fa arrow"></i></a>
<ul class="nav nav-second-level">
<li> <a href="{{ app.get_url('System') }}"> <span class="fa fa-heartbeat"></span> Status </a> </li>
<li> <a href="{{ app.get_url('System') }}"> <span class="fa fa-heartbeat sidebar-icon"></span> Status </a> </li>
%if app.logs_module.is_available():
<li> <a href="{{ app.get_url('History') }}"> <span class="fa fa-th-list"></span> Logs </a> </li>
<li> <a href="{{ app.get_url('History') }}"> <span class="fa fa-th-list sidebar-icon"></span> Logs </a> </li>
<li> <a href="{{ app.get_url('GlobalStats') }}"> <span class="fa fa-bell-o sidebar-icon"></span> Alerts </a> </li>
%end
</ul>
</li>
<li> <a href="#"><i class="fa fa-wrench sidebar-icon"></i>
Configuration<i class="fa arrow"></i></a>
<ul class="nav nav-second-level">
<li> <a href="{{ app.get_url('Parameters') }}"> <span class="fa fa-gears"></span> Parameters </a> </li>
<li> <a href="{{ app.get_url('Contacts') }}"> <span class="fa fa-user"></span> Contacts </a> </li>
<li> <a href="{{ app.get_url('ContactsGroups') }}"> <span class="fa fa-users"></span> Contact Groups </a> </li>
<li> <a href="{{ app.get_url('Commands') }}"> <span class="fa fa-terminal"></span> Commands </a> </li>
<li> <a href="{{ app.get_url('TimePeriods') }}"> <span class="fa fa-calendar"></span> Time periods </a> </li>
<li> <a href="{{ app.get_url('Parameters') }}"> <span class="fa fa-gears sidebar-icon"></span> Parameters </a> </li>
<li> <a href="{{ app.get_url('Contacts') }}"> <span class="fa fa-user sidebar-icon"></span> Contacts </a> </li>
<li> <a href="{{ app.get_url('ContactsGroups') }}"> <span class="fa fa-users sidebar-icon"></span> Contact Groups </a> </li>
<li> <a href="{{ app.get_url('Commands') }}"> <span class="fa fa-terminal sidebar-icon"></span> Commands </a> </li>
<li> <a href="{{ app.get_url('TimePeriods') }}"> <span class="fa fa-calendar sidebar-icon"></span> Time periods </a> </li>
</ul>
</li>
%end
Expand All @@ -232,7 +233,7 @@
<ul class="nav nav-second-level">
%for c in other_uis:
<li>
<a href="{{c['uri']}}" target="_blank"><span class="fa fa-rocket"></span> {{c['label']}}</a>
<a href="{{c['uri']}}" target="_blank"><span class="fa fa-rocket sidebar-icon"></span> {{c['label']}}</a>
</li>
%end
</ul>
Expand Down

0 comments on commit fe1abab

Please sign in to comment.