1
# Copyright (C) 2005-2009 PreludeIDS Technologies. All Rights Reserved.
2
# Author: Nicolas Delon <nicolas.delon@prelude-ids.com>
3
# Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
5
# This file is part of the Prewikka program.
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2, or (at your option)
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; see the file COPYING. If not, write to
19
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27
from prewikka import User, view, Chart, utils, resolve
31
geoip = GeoIP.new(GeoIP.GEOIP_MEMORY_CACHE)
40
class DistributionStatsParameters(view.Parameters):
42
self.optional("timeline_type", str, default="hour", save=True)
43
self.optional("from_year", int, save=True)
44
self.optional("from_month", int, save=True)
45
self.optional("from_day", int, save=True)
46
self.optional("from_hour", int, save=True)
47
self.optional("from_min", int, save=True)
48
self.optional("to_year", int, save=True)
49
self.optional("to_month", int, save=True)
50
self.optional("to_day", int, save=True)
51
self.optional("to_hour", int, save=True)
52
self.optional("to_min", int, save=True)
53
self.optional("filter", str, save=True)
54
self.optional("idmef_filter", str)
55
self.optional("apply", str)
57
def normalize(self, view_name, user):
58
do_save = self.has_key("_save")
60
view.Parameters.normalize(self, view_name, user)
62
if do_save and not self.has_key("filter"):
63
user.delConfigValue(view_name, "filter")
66
class StatsSummary(view.View):
67
view_name = "stats_summary"
68
view_template = "StatsSummary"
70
view_parameters = view.Parameters
78
class DistributionStats(view.View):
79
view_template = "Stats"
80
view_permissions = [ User.PERM_IDMEF_VIEW ]
81
view_parameters = DistributionStatsParameters
83
def _getNameFromMap(self, name, names_and_colors):
84
if names_and_colors.has_key(name):
85
return names_and_colors[name][0]
89
def _namesAndColors2ColorMap(self, names_and_colors):
90
d = utils.OrderedDict()
91
for name, color in names_and_colors.values():
96
def _getBaseURL(self):
97
start = long(time.mktime(self._period_start))
99
if self.parameters["timeline_type"] in ("month", "day", "hour"):
100
unit = self.parameters["timeline_type"]
103
delta = long(time.mktime(self._period_end)) - start
106
value = delta / (24 * 3600) + 1
109
value = delta / 3600 + 1
112
if self.parameters.has_key("filter"):
113
filter_str = "&" + urllib.urlencode({"filter": self.parameters["filter"]})
115
return utils.create_link("alert_listing", { "timeline_unit": unit,
116
"timeline_value": value,
117
"timeline_start": start }) + filter_str
120
def _addDistributionChart(self, title, value_name, width, height, path, criteria, sub_url_handler, limit=-1, dns=False, names_and_colors={}):
121
base_url = self._getBaseURL()
122
chart = { "title": title, "value_name": value_name }
124
distribution = Chart.DistributionChart(self.user, width, height)
126
distribution.setColorMap(self._namesAndColors2ColorMap(names_and_colors))
128
chart["chart"] = distribution
129
chart["render"] = (distribution, title, base_url)
131
results = self.env.idmef_db.getValues([ path + "/group_by", "count(%s)/order_desc" % path ],
132
criteria=criteria + [ path ], limit=limit)
134
for value, count in results:
136
v = resolve.AddressResolve(value)
138
v = self._getNameFromMap(value or _(u"n/a"), names_and_colors)
140
distribution.addLabelValuePair(v, count, base_url + "&" + sub_url_handler(value))
142
distribution.render(title)
143
self.dataset["charts"].append(chart)
145
def _processTimeCriteria(self):
147
self._period_end = time.localtime(now)
149
if self.parameters["timeline_type"] == "hour":
150
self.dataset["timeline_hour_selected"] = "selected=\"selected\""
151
self._period_start = time.localtime(now - 3600)
153
elif self.parameters["timeline_type"] == "day":
154
self.dataset["timeline_day_selected"] = "selected=\"selected\""
155
tm = time.localtime(now - 24 * 3600)
156
self._period_start = time.localtime(now - 24 * 3600)
158
elif self.parameters["timeline_type"] == "month":
159
self.dataset["timeline_month_selected"] = "selected=\"selected\""
160
tm = list(time.localtime(now))
162
self._period_start = time.localtime(time.mktime(tm))
165
self.dataset["timeline_custom_selected"] = "selected=\"selected\""
166
self._period_start = time.struct_time((self.parameters["from_year"], self.parameters["from_month"],
167
self.parameters["from_day"], self.parameters["from_hour"],
168
self.parameters["from_min"], 0, 0, 0, -1))
169
self._period_end = time.struct_time((self.parameters["to_year"], self.parameters["to_month"],
170
self.parameters["to_day"], self.parameters["to_hour"],
171
self.parameters["to_min"], 0, 0, 0, -1))
173
self.dataset["from_year"] = "%.4d" % self._period_start.tm_year
174
self.dataset["from_month"] = "%.2d" % self._period_start.tm_mon
175
self.dataset["from_day"] = "%.2d" % self._period_start.tm_mday
176
self.dataset["from_hour"] = "%.2d" % self._period_start.tm_hour
177
self.dataset["from_min"] = "%.2d" % self._period_start.tm_min
179
self.dataset["to_year"] = "%.4d" % self._period_end.tm_year
180
self.dataset["to_month"] = "%.2d" % self._period_end.tm_mon
181
self.dataset["to_day"] = "%.2d" % self._period_end.tm_mday
182
self.dataset["to_hour"] = "%.2d" % self._period_end.tm_hour
183
self.dataset["to_min"] = "%.2d" % self._period_end.tm_min
185
criteria = [ "alert.create_time >= '%d-%d-%d %d:%d:%d' && alert.create_time < '%d-%d-%d %d:%d:%d'" % \
186
(self._period_start.tm_year, self._period_start.tm_mon, self._period_start.tm_mday,
187
self._period_start.tm_hour, self._period_start.tm_min, self._period_start.tm_sec,
188
self._period_end.tm_year, self._period_end.tm_mon, self._period_end.tm_mday,
189
self._period_end.tm_hour, self._period_end.tm_min, self._period_end.tm_sec) ]
193
def _processFilterCriteria(self):
195
if self.parameters.has_key("idmef_filter"):
196
c.append(unicode(self.parameters["idmef_filter"]))
198
self.dataset["current_filter"] = self.parameters.get("filter", "")
199
if self.parameters.has_key("filter"):
200
f = self.env.db.getAlertFilter(self.user.login, self.parameters["filter"])
206
def _processCriteria(self):
208
criteria += self._processTimeCriteria()
209
criteria += self._processFilterCriteria()
214
self.dataset["hidden_parameters"] = [ ("view", self.view_name) ]
215
self.dataset["charts"] = [ ]
216
self.dataset["filters"] = self.env.db.getAlertFilterNames(self.user.login)
217
self.dataset["timeline_hour_selected"] = ""
218
self.dataset["timeline_day_selected"] = ""
219
self.dataset["timeline_month_selected"] = ""
220
self.dataset["timeline_custom_selected"] = ""
222
def _setPeriod(self):
223
tm = time.localtime()
225
period = "from %s/%s/%s %s:%s to %s/%s/%s %s:%s" % \
226
(self.dataset["from_year"], self.dataset["from_month"], self.dataset["from_day"],
227
self.dataset["from_hour"], self.dataset["from_min"],
228
self.dataset["to_year"], self.dataset["to_month"], self.dataset["to_day"],
229
self.dataset["to_hour"], self.dataset["to_min"])
231
if self.parameters["timeline_type"] == "month":
232
self.dataset["period"] = "Period: current month (%s)" % period
233
elif self.parameters["timeline_type"] == "day":
234
self.dataset["period"] = "Period: today (%s)" % period
235
elif self.parameters["timeline_type"] == "hour":
236
self.dataset["period"] = "Period: current hour (%s)" % period
238
self.dataset["period"] = "Period: %s" % period
240
def genPathValueURI(self, path, value, index=0, type=None):
248
type = path.split(".")[1]
254
if type == "assessment":
255
type = "classification"
257
if type not in ("classification", "source", "target", "analyzer"):
258
raise Exception, "The path '%s' cannot be mapped to a column" % path
260
return utils.urlencode({ "%s_object_%d" % (type, index): path, "%s_operator_%d" % (type, index): operator, "%s_value_%d" % (type, index): value })
264
class GenericTimelineStats(DistributionStats):
265
def _getAlertCount(self, criteria, link, zoom_view):
268
results = self.env.idmef_db.getValues(self._getSelection(), criteria)
272
for name, count in results:
273
if zoom_view == "alert_listing":
274
link += "&" + self.genPathValueURI(self._path, name)
276
d[self._getNameFromMap(name or _(u"n/a"), self._names_and_colors)] = (count, link)
280
def _newTimeline(self, user, width, height, stacked=False):
282
timeline = Chart.StackedTimelineChart(user, width, height)
284
timeline = Chart.TimelineChart(user, width, height)
286
if not self.parameters.has_key("idmef_filter"):
287
timeline.enableMultipleValues(self._namesAndColors2ColorMap(self._names_and_colors))
291
def _getTimeCrit(self, start, step):
292
tm1 = start #time.localtime(start)
293
tm2 = start+step #time.localtime(start + step)
295
c = [ "alert.create_time >= '%d-%d-%d %d:%d:%d' && alert.create_time < '%d-%d-%d %d:%d:%d'" % \
296
(tm1.year, tm1.month, tm1.day, tm1.hour, tm1.minute, tm1.second,
297
tm2.year, tm2.month, tm2.day, tm2.hour, tm2.minute, tm2.second) ]
301
def _getStep(self, type, absolute=False):
305
type = self.getCustomUnit()
306
start = datetime.datetime(*self._period_start[:6])
307
end = datetime.datetime(*self._period_end[:6])
309
end = datetime.datetime.today()
313
start = end - datetime.timedelta(seconds=60)
314
step = datetime.timedelta(seconds=1)
315
label_tm_index = "%Hh%M:%S"
316
zoom_view = "alert_listing"
317
timeline_type = "min"
322
start = end - datetime.timedelta(minutes=60)
323
step = datetime.timedelta(minutes=1)
324
label_tm_index = "%Hh%M"
325
zoom_view = "alert_listing"
326
timeline_type = "min"
331
start = end - datetime.timedelta(hours=24)
332
step = datetime.timedelta(hours=1)
333
label_tm_index = "%d/%Hh"
334
zoom_view = "stats_timeline"
335
timeline_type = "custom"
336
timeline_unit = "hour"
338
elif type == "month":
340
start = end - datetime.timedelta(days=31)
341
step = datetime.timedelta(days=1)
342
label_tm_index = "%m/%d"
343
zoom_view = "stats_timeline"
344
timeline_type = "custom"
345
timeline_unit = "day"
349
start = end - datetime.timedelta(days=365)
350
step = datetime.timedelta(days=31)
351
label_tm_index = "%m/%d"
352
zoom_view = "stats_timeline"
353
timeline_type = "custom"
354
timeline_unit = "day"
356
return start, end, step, label_tm_index, zoom_view, timeline_type, timeline_unit
359
def _setTimelineZoom(self, base_parameters, start, end):
360
#tm = time.localtime(start)
361
base_parameters["from_year"] = start.year
362
base_parameters["from_month"] = start.month
363
base_parameters["from_day"] = start.day
364
base_parameters["from_hour"] = start.hour
365
base_parameters["from_min"] = start.minute
367
#tm = time.localtime(end)
368
base_parameters["to_year"] = end.year
369
base_parameters["to_month"] = end.month
370
base_parameters["to_day"] = end.day
371
base_parameters["to_hour"] = end.hour
372
base_parameters["to_min"] = end.minute
374
def _generateTimeline(self, user, width, height):
375
start, end, step, format, zoom_view, timeline_type, timeline_time = self._getStep(self.parameters["timeline_type"])
376
timeline = self._newTimeline(user, width, height)
378
if timeline_type != "custom":
379
base_parameters = { "timeline_unit": "min" }
381
base_parameters = { "timeline_type": timeline_type }
383
self.dataset["timeline_user_type"] = self.parameters.get("timeline_type")
386
c = self._getTimeCrit(start, step) + self._criteria
388
if timeline_type != "custom":
389
base_parameters["timeline_start"] = long(time.mktime(start.timetuple())) #long(start)
391
self._setTimelineZoom(base_parameters, start, start + step)
393
link = utils.create_link(zoom_view, base_parameters)
394
count = self._getAlertCount(c, link, zoom_view)
395
label = start.strftime(format)
398
timeline.addLabelValuePair(label, count, link)
402
def getCustomUnit(self):
403
start = long(time.mktime(self._period_start))
404
delta = long(time.mktime(self._period_end)) - start
417
def _getSelection(self):
418
return ("%s/group_by" % self._path, "count(%s)/order_desc" % self._path)
420
def _addTimelineChart(self, title, value_name, width, height, path, criteria, limit=-1, names_and_colors={}, allow_stacked=False, value_callback=None, zoom_type=None):
423
self._value_callback = value_callback
424
self._criteria = criteria
425
self._zoom_type = zoom_type
426
self._names_and_colors = names_and_colors
428
base_url = self._getBaseURL()
429
chart = { "title": title, "value_name": value_name }
432
res = self.env.idmef_db.getValues(self._getSelection(), criteria = criteria, limit=self._limit)
435
for name, count in res:
440
c += "%s = '%s'" % (self._path, utils.escape_criteria(name))
442
c += "! %s" % (self._path)
446
timeline = self._generateTimeline(self.user, width, height)
447
timeline.render(title)
449
chart["chart"] = timeline
450
self.dataset["charts"].append(chart)
451
self.dataset["zoom"] = self.parameters.get("zoom", None)
454
class CategorizationStats(DistributionStats, GenericTimelineStats):
455
view_name = "stats_categorization"
457
def _renderClassifications(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
458
self._addDistributionChart(_("Top 10 Classifications"), _("Classification"), width, height,
459
"alert.classification.text",
461
lambda value: self.genPathValueURI("alert.classification.text", value, type="classification"),
464
def _renderReferences(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
465
self._addDistributionChart(_("Top 10 Alert References"), _("References"), width, height,
466
"alert.classification.reference.name",
468
lambda value: self.genPathValueURI("alert.classification.reference.name", value, type="classification"),
471
def _renderImpactSeverities(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
472
_severity_maps = utils.OrderedDict()
473
_severity_maps["high"] = (_("High"), Chart.RED_STD)
474
_severity_maps["medium"] = (_("Medium"), Chart.ORANGE_STD)
475
_severity_maps["low"] = (_("Low"), Chart.GREEN_STD)
476
_severity_maps["info"] = (_("Informational"), Chart.BLUE_STD)
477
_severity_maps[None] = (_("N/a"), "000000")
479
self._addDistributionChart(_("Severities"), _("Severity"), width, height,
480
"alert.assessment.impact.severity",
482
lambda value: self.genPathValueURI("alert.assessment.impact.severity", value, type="classification"), names_and_colors=_severity_maps)
484
def _renderImpactTypes(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
485
self._addDistributionChart(_("Alert Impact Types"), _("Impact Types"), width, height,
486
"alert.assessment.impact.type",
488
lambda value: self.genPathValueURI("alert.assessment.impact.type", value, type="classification"))
490
def _renderClassificationsTrend(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
491
GenericTimelineStats._addTimelineChart(self, "Top 10 Classifications Trend", None, width, height,
492
"alert.classification.text", criteria, limit = 10, zoom_type="classifications_trend")
495
DistributionStats.render(self)
497
self.dataset["title"] = "Alerts categorization"
499
criteria = self._processCriteria()
503
self._renderClassificationsTrend(criteria)
504
self._renderClassifications(criteria)
505
self._renderReferences(criteria)
506
self._renderImpactSeverities(criteria)
507
self._renderImpactTypes(criteria)
511
class SourceStats(DistributionStats, GenericTimelineStats):
512
view_name = "stats_source"
514
def _countryDistributionChart(self, criteria, width, height):
516
base_url = self._getBaseURL()
517
distribution = Chart.WorldChart(self.user, width, height)
519
chart = { "title": _("Top Source Country"), "value_name": _("Country"), "chart": distribution }
521
results = self.env.idmef_db.getValues([ "alert.source.node.address.address/group_by",
522
"count(alert.source.node.address.address)"],
523
criteria=criteria, limit=-1)
527
for value, count in results:
529
if distribution.needCountryCode():
530
nvalue = geoip.country_code_by_addr(value)
532
nvalue = geoip.country_name_by_addr(value)
539
if not merge.has_key(nvalue):
541
merge[nvalue] = (0, 0, nvalue, "")
543
url_index = merge[nvalue][1]
545
encode = "&" + self.genPathValueURI("alert.source.node.address.address", value, type="source", index=url_index)
546
merge[nvalue] = (merge[nvalue][0] + count, url_index + 1, nvalue, merge[nvalue][3] + encode)
548
s = [ t[1] for t in merge.items() ]
554
distribution.addLabelValuePair(item[2], item[0])
556
distribution.render("Top 10 Source Country")
557
chart["filename"] = distribution.getHref()
558
chart["type"] = distribution.getType()
559
self.dataset["charts"].append(chart)
562
def _renderCountry(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
563
if geoip is not None:
564
self._countryDistributionChart(criteria, width, height)
566
def _renderAddresses(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
567
self._addDistributionChart(_("Top 10 Source Addresses"), _("Address"), width, height,
568
"alert.source.node.address.address",
570
lambda value: self.genPathValueURI("alert.source.node.address.address", value, type="source"),
573
def _renderUsers(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
574
self._addDistributionChart(_("Top 10 Source Users"), _("User"), width, height,
575
"alert.source.user.user_id.name",
577
lambda value: self.genPathValueURI("alert.source.user.user_id.name", value, type="source"),
580
def _renderSourcesTrend(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
581
GenericTimelineStats._addTimelineChart(self, "Top 10 Sources Trend", None, DEFAULT_WIDTH, DEFAULT_HEIGHT,
582
"alert.source.node.address.address", criteria, 10, zoom_type="sources_trend")
585
DistributionStats.render(self)
587
self.dataset["title"] = "Top Alert Sources"
589
criteria = self._processCriteria()
593
self._renderCountry(criteria)
594
self._renderSourcesTrend(criteria)
595
self._renderAddresses(criteria)
596
self._renderUsers(criteria)
598
resolve.process(self.env.dns_max_delay)
600
class TargetStats(DistributionStats):
601
view_name = "stats_target"
603
def _renderPorts(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
604
base_url = self._getBaseURL()
605
title = "Top 10 Targeted Ports"
606
distribution = Chart.DistributionChart(self.user, width, height)
607
chart = { "title": title, "value_name": "Port", "chart": distribution }
609
criteria = criteria[:] + [ "(alert.target.service.iana_protocol_number == 6 ||"
610
"alert.target.service.iana_protocol_number == 17 ||"
611
"alert.target.service.iana_protocol_name =* 'tcp' ||"
612
"alert.target.service.iana_protocol_name =* 'udp' ||"
613
"alert.target.service.protocol =* 'udp' ||"
614
"alert.target.service.protocol =* 'tcp')" ]
616
results = self.env.idmef_db.getValues([ "alert.target.service.port/group_by",
617
"alert.target.service.iana_protocol_number/group_by",
618
"alert.target.service.iana_protocol_name/group_by",
619
"alert.target.service.protocol/group_by",
620
"count(alert.target.service.port)/order_desc" ],
621
criteria=criteria, limit=10)
625
merge = { _(u"n/a"): { }, u"tcp": { }, u"udp": { } }
627
for port, iana_protocol_number, iana_protocol_name, protocol, count in results:
631
if iana_protocol_number:
632
protocol = utils.protocol_number_to_name(iana_protocol_number)
634
elif iana_protocol_name:
635
protocol = iana_protocol_name
640
protocol = protocol.lower()
641
if not merge.has_key(protocol):
644
if not merge[protocol].has_key(port):
645
merge[protocol][port] = 0
647
merge[protocol][port] += count
651
for protocol, values in merge.items():
652
for port, count in values.items():
653
results.append((port, protocol, count))
655
results.sort(lambda x, y: int(y[2] - x[2]))
657
for port, protocol, count in results:
658
name = "%d / %s" % (port, protocol)
659
distribution.addLabelValuePair(name, count, base_url + "&" + "target_object_0=alert.target.service.port&target_value_0=%d" % port)
661
distribution.render(title)
662
self.dataset["charts"].append(chart)
664
def _renderAddresses(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
665
self._addDistributionChart(_("Top 10 Targeted Addresses"), _("Address"), width, height,
666
"alert.target.node.address.address",
668
lambda value: self.genPathValueURI("alert.target.node.address.address", value, type="target"),
671
def _renderUsers(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
672
self._addDistributionChart(_("Top 10 Targeted Users"), _("User"), width, height,
673
"alert.target.user.user_id.name",
675
lambda value: self.genPathValueURI("alert.target.user.user_id.name", value, type="target"),
679
DistributionStats.render(self)
681
self.dataset["title"] = "Top Alert Targets"
683
criteria = self._processCriteria()
687
self._renderAddresses(criteria)
688
self._renderPorts(criteria)
689
self._renderUsers(criteria)
691
resolve.process(self.env.dns_max_delay)
694
class AnalyzerStats(DistributionStats, GenericTimelineStats):
695
view_name = "stats_analyzer"
697
def _renderAnalyzers(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
698
base_url = self._getBaseURL()
699
title = "Top 10 analyzers"
700
distribution = Chart.DistributionChart(self.user, width, height)
701
chart = { "title": title, "value_name": "Analyzer", "chart": distribution }
703
results = self.env.idmef_db.getValues([ "alert.analyzer(-1).name/group_by", "alert.analyzer(-1).node.name/group_by",
704
"count(alert.analyzer(-1).name)/order_desc" ],
705
criteria=criteria + [ "alert.analyzer(-1).name" ], limit=10)
707
for analyzer_name, node_name, count in results:
708
value = analyzer_name or _(u"n/a")
710
value = "%s on %s" % (value, node_name)
712
analyzer_criteria = self.genPathValueURI("alert.analyzer(-1).name", analyzer_name, type="analyzer")
713
distribution.addLabelValuePair(value, count, base_url + "&" + analyzer_criteria)
715
distribution.render(title)
716
self.dataset["charts"].append(chart)
718
def _renderModels(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
719
self._addDistributionChart(_("Top 10 Analyzer Models"), _("Model"), width, height,
720
"alert.analyzer(-1).model",
722
lambda value: self.genPathValueURI("alert.analyzer(-1).model", value, type="analyzer"),
725
def _renderClasses(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
726
self._addDistributionChart(_("Top 10 Analyzer Classes"), _("Class"), width, height,
727
"alert.analyzer(-1).class",
729
lambda value: self.genPathValueURI("alert.analyzer(-1).class", value, type="analyzer"),
732
def _renderNodeAddresses(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
733
self._addDistributionChart(_("Top 10 Analyzer Node Addresses"), _("Address"), width, height,
734
"alert.analyzer(-1).node.address.address",
736
lambda value: self.genPathValueURI("alert.analyzer(-1).node.address.address", value, type="analyzer"),
739
def _renderNodeLocations(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
740
self._addDistributionChart(_("Analyzer Locations"), _("Location"), width, height,
741
"alert.analyzer(-1).node.location",
743
lambda value: self.genPathValueURI("alert.analyzer(-1).node.location", value, type="analyzer"))
745
def _renderClassesTrend(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
746
GenericTimelineStats._addTimelineChart(self, "Top 10 Analyzer Classes Trend", None, width, height,
747
"alert.analyzer(-1).class", criteria, limit = 10, zoom_type="analyzer_classes_trend")
750
DistributionStats.render(self)
752
self.dataset["title"] = "Top Analyzers"
754
criteria = self._processCriteria()
758
self._renderClassesTrend(criteria)
759
self._renderAnalyzers(criteria)
760
self._renderModels(criteria)
761
self._renderClasses(criteria)
762
self._renderNodeAddresses(criteria)
763
self._renderNodeLocations(criteria)
767
class TimelineStats(GenericTimelineStats, AnalyzerStats, CategorizationStats, SourceStats):
768
view_name = "stats_timeline"
770
def _renderTimelineChart(self, criteria, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT):
771
_severity_maps = utils.OrderedDict()
772
_severity_maps["high"] = (_("High"), Chart.RED_STD)
773
_severity_maps["medium"] = (_("Medium"), Chart.ORANGE_STD)
774
_severity_maps["low"] = (_("Low"), Chart.GREEN_STD)
775
_severity_maps["info"] = (_("Informational"), Chart.BLUE_STD)
776
_severity_maps[None] = (_("N/a"), "000000")
778
GenericTimelineStats._addTimelineChart(self, "Timeline", None, width, height,
779
"alert.assessment.impact.severity", criteria, names_and_colors=_severity_maps)
782
DistributionStats.render(self)
783
self.dataset["title"] = "Timeline"
785
criteria = self._processCriteria()
788
type = self.parameters.get("type", None)
789
if type == "analyzer_classes_trend":
790
AnalyzerStats._renderClassesTrend(self, criteria)
792
elif type == "classifications_trend":
793
CategorizationStats._renderClassificationsTrend(self, criteria)
795
elif type == "sources_trend":
796
SourceStats._renderSourcesTrend(self, criteria)
798
self._renderTimelineChart(criteria)
803
class AnalyzerTrendStats(GenericTimelineStats, AnalyzerStats):
804
view_name = "stats_analyzer_trend"
807
DistributionStats.render(self)
808
self.dataset["title"] = "Timeline"
810
criteria = self._processCriteria()
813
title = "Top 10 Analyzer Trend " + self.dataset["period"]
814
AnalyzerStats._renderClassesTrend(self, criteria, width, height)