log_sense 1.9.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.org +15 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +15 -15
- data/README.org +169 -116
- data/exe/log_sense +2 -1
- data/lib/log_sense/aggregator.rb +3 -2
- data/lib/log_sense/apache_report_shaper.rb +19 -260
- data/lib/log_sense/emitter.rb +2 -0
- data/lib/log_sense/rails_aggregator.rb +12 -2
- data/lib/log_sense/rails_report_shaper.rb +25 -198
- data/lib/log_sense/report_shaper.rb +364 -1
- data/lib/log_sense/templates/_apache_theme.css +35 -0
- data/lib/log_sense/templates/_navigation.html.erb +2 -2
- data/lib/log_sense/templates/_rails_theme.css +36 -0
- data/lib/log_sense/templates/_stylesheet.css +64 -44
- data/lib/log_sense/templates/report_html.erb +14 -6
- data/lib/log_sense/templates/world.svg +977 -0
- data/lib/log_sense/version.rb +1 -1
- data/log_sense.gemspec +9 -9
- data/screenshots/combined_log-screenshot.png +0 -0
- data/screenshots/rails-screenshot.png +0 -0
- data/todo.org +309 -0
- metadata +38 -35
- data/lib/log_sense/templates/_rails.css.erb +0 -20
- data/screenshots/apache-screenshot.png +0 -0
@@ -64,38 +64,12 @@ module LogSense
|
|
64
64
|
}
|
65
65
|
",
|
66
66
|
},
|
67
|
-
|
68
|
-
|
67
|
+
time_distribution(
|
68
|
+
data,
|
69
69
|
header: %w[Hour Hits Visits Size],
|
70
70
|
column_alignment: %i[left right right right],
|
71
|
-
|
72
|
-
|
73
|
-
xAxis: {
|
74
|
-
type: 'category',
|
75
|
-
data: SERIES_DATA.map(row => row['Hour'])
|
76
|
-
/* data: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
|
77
|
-
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
|
78
|
-
'20', '21', '22', '23', '24'] */
|
79
|
-
},
|
80
|
-
yAxis: {
|
81
|
-
type: 'value'
|
82
|
-
},
|
83
|
-
tooltip: {
|
84
|
-
trigger: 'axis'
|
85
|
-
},
|
86
|
-
series: [
|
87
|
-
{
|
88
|
-
data: SERIES_DATA.map(row => row['Hits']),
|
89
|
-
type: 'bar',
|
90
|
-
color: '#4C78A8',
|
91
|
-
label: {
|
92
|
-
show: true,
|
93
|
-
position: 'top'
|
94
|
-
},
|
95
|
-
}
|
96
|
-
]
|
97
|
-
}",
|
98
|
-
},
|
71
|
+
color: "#4C78A8"
|
72
|
+
),
|
99
73
|
{
|
100
74
|
title: "20_ and 30_ on HTML pages",
|
101
75
|
header: %w[Path Hits Visits Size Status],
|
@@ -154,242 +128,27 @@ module LogSense
|
|
154
128
|
]
|
155
129
|
}&.sort { |x, y| y[1] <=> x[1] }
|
156
130
|
},
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
rows: data[:statuses],
|
162
|
-
echarts_spec: "{
|
163
|
-
xAxis: {
|
164
|
-
type: 'category',
|
165
|
-
data: SERIES_DATA.map(row => row['Status'])
|
166
|
-
/* data: ['100', '101', '102', '103',
|
167
|
-
'200', '201', '202', '203', '204', '205', '206', '207', '208', '226',
|
168
|
-
'300', '301', '302', '303', '304', '305', '306', '307', '308',
|
169
|
-
'400', '401', '402', '403', '404', '405', '406', '407', '408', '409', '410', '411', '412', '413', '414', '415', '416', '417', '418', '421', '422', '423', '424', '425', '426', '428', '429', '431', '451',
|
170
|
-
'500', '501', '502', '503', '504', '505', '506', '507', '508', '510', '511'] */
|
171
|
-
},
|
172
|
-
yAxis: {
|
173
|
-
type: 'value'
|
174
|
-
},
|
175
|
-
tooltip: {
|
176
|
-
trigger: 'axis'
|
177
|
-
},
|
178
|
-
series: [
|
179
|
-
{
|
180
|
-
data: SERIES_DATA.map(row => row['Count']),
|
181
|
-
type: 'bar',
|
182
|
-
color: '#4C78A8',
|
183
|
-
label: {
|
184
|
-
show: true,
|
185
|
-
position: 'top'
|
186
|
-
},
|
187
|
-
}
|
188
|
-
]
|
189
|
-
}",
|
190
|
-
},
|
191
|
-
{
|
192
|
-
title: "Daily Statuses",
|
193
|
-
header: %w[Date S_2xx S_3xx S_4xx S_5xx],
|
194
|
-
column_alignment: %i[left right right right right],
|
195
|
-
rows: data[:statuses_by_day],
|
196
|
-
echarts_spec: "{
|
197
|
-
xAxis: {
|
198
|
-
type: 'category',
|
199
|
-
data: SERIES_DATA.map(row => row['Date'])
|
200
|
-
},
|
201
|
-
yAxis: {
|
202
|
-
type: 'value'
|
203
|
-
},
|
204
|
-
tooltip: {
|
205
|
-
trigger: 'axis'
|
206
|
-
},
|
207
|
-
series: [
|
208
|
-
{
|
209
|
-
data: SERIES_DATA.map(row => row['S_2xx']),
|
210
|
-
type: 'bar',
|
211
|
-
color: '#218521',
|
212
|
-
stack: 'total',
|
213
|
-
label: {
|
214
|
-
show: true,
|
215
|
-
position: 'right'
|
216
|
-
},
|
217
|
-
},
|
218
|
-
{
|
219
|
-
data: SERIES_DATA.map(row => row['S_3xx']),
|
220
|
-
type: 'bar',
|
221
|
-
color: '#FF8C00',
|
222
|
-
stack: 'total',
|
223
|
-
label: {
|
224
|
-
show: true,
|
225
|
-
position: 'right'
|
226
|
-
},
|
227
|
-
},
|
228
|
-
{
|
229
|
-
data: SERIES_DATA.map(row => row['S_4xx']),
|
230
|
-
type: 'bar',
|
231
|
-
color: '#A52A2A',
|
232
|
-
stack: 'total',
|
233
|
-
label: {
|
234
|
-
show: true,
|
235
|
-
position: 'right'
|
236
|
-
},
|
237
|
-
},
|
238
|
-
{
|
239
|
-
data: SERIES_DATA.map(row => row['S_5xx']),
|
240
|
-
type: 'bar',
|
241
|
-
color: '#000000',
|
242
|
-
stack: 'total',
|
243
|
-
label: {
|
244
|
-
show: true,
|
245
|
-
position: 'right'
|
246
|
-
},
|
247
|
-
},
|
248
|
-
]
|
249
|
-
}",
|
250
|
-
},
|
251
|
-
{
|
252
|
-
title: "Browsers",
|
131
|
+
total_statuses(data),
|
132
|
+
daily_statuses(data),
|
133
|
+
browsers(
|
134
|
+
data,
|
253
135
|
header: %w[Browser Hits Visits Size],
|
254
136
|
column_alignment: %i[left right right right],
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
saveAsImage: {},
|
260
|
-
}
|
261
|
-
},
|
262
|
-
tooltip: {
|
263
|
-
trigger: 'axis'
|
264
|
-
},
|
265
|
-
xAxis: {
|
266
|
-
type: 'category',
|
267
|
-
data: SERIES_DATA.sort(order_by_name).map(row => row['Browser']),
|
268
|
-
showGrid: true,
|
269
|
-
axisLabel: {
|
270
|
-
rotate: 45 // Rotate the labels by 90 degrees
|
271
|
-
}
|
272
|
-
},
|
273
|
-
yAxis: {
|
274
|
-
type: 'value',
|
275
|
-
name: 'Browser Hits',
|
276
|
-
showGrid: true,
|
277
|
-
},
|
278
|
-
series: [
|
279
|
-
{
|
280
|
-
name: 'Hits',
|
281
|
-
data: SERIES_DATA.sort(order_by_name).map(row => row['Hits']),
|
282
|
-
type: 'bar',
|
283
|
-
color: '#4C78A8',
|
284
|
-
label: {
|
285
|
-
show: true,
|
286
|
-
position: 'top'
|
287
|
-
},
|
288
|
-
},
|
289
|
-
]
|
290
|
-
}
|
291
|
-
function order_by_name(a, b) {
|
292
|
-
return a['Browser'] < b['Browser'] ? -1 : 1
|
293
|
-
}
|
294
|
-
",
|
295
|
-
},
|
296
|
-
{
|
297
|
-
title: "Platforms",
|
137
|
+
color: '#4C78A8'
|
138
|
+
),
|
139
|
+
platforms(
|
140
|
+
data,
|
298
141
|
header: %w[Platform Hits Visits Size],
|
299
142
|
column_alignment: %i[left right right right],
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
saveAsImage: {},
|
305
|
-
}
|
306
|
-
},
|
307
|
-
tooltip: {
|
308
|
-
trigger: 'axis'
|
309
|
-
},
|
310
|
-
xAxis: {
|
311
|
-
type: 'category',
|
312
|
-
data: SERIES_DATA.sort(order_by_platform).map(row => row['Platform']),
|
313
|
-
showGrid: true,
|
314
|
-
axisLabel: {
|
315
|
-
rotate: 45 // Rotate the labels by 90 degrees
|
316
|
-
}
|
317
|
-
},
|
318
|
-
yAxis: {
|
319
|
-
type: 'value',
|
320
|
-
name: 'Platform Hits',
|
321
|
-
showGrid: true,
|
322
|
-
},
|
323
|
-
series: [
|
324
|
-
{
|
325
|
-
name: 'Hits',
|
326
|
-
data: SERIES_DATA.sort(order_by_platform).map(row => row['Hits']),
|
327
|
-
type: 'bar',
|
328
|
-
color: '#4C78A8',
|
329
|
-
label: {
|
330
|
-
show: true,
|
331
|
-
position: 'top'
|
332
|
-
},
|
333
|
-
},
|
334
|
-
]
|
335
|
-
}
|
336
|
-
function order_by_platform(a, b) {
|
337
|
-
return a['Platform'] < b['Platform'] ? -1 : 1
|
338
|
-
}",
|
339
|
-
},
|
340
|
-
{
|
341
|
-
title: "IPs",
|
143
|
+
color: '#4C78A8'
|
144
|
+
),
|
145
|
+
ips(
|
146
|
+
data,
|
342
147
|
header: %w[IP Hits Visits Size Country],
|
343
148
|
column_alignment: %i[left right right right left],
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
title: "Countries",
|
348
|
-
header: ["Country", "Hits", "Visits", "IPs", "IP List"],
|
349
|
-
column_alignment: %i[left right right right left],
|
350
|
-
rows: data[:countries]&.map { |k, v|
|
351
|
-
[
|
352
|
-
k,
|
353
|
-
v.map { |x| x[1] }.inject(&:+),
|
354
|
-
v.map { |x| x[2] }.inject(&:+),
|
355
|
-
v.map { |x| x[0] }.uniq.size,
|
356
|
-
v.map { |x| x[0] }.join(WORDS_SEPARATOR)
|
357
|
-
]
|
358
|
-
}&.sort { |x, y| y[3] <=> x[3] },
|
359
|
-
echarts_height: "600px",
|
360
|
-
echarts_spec: "{
|
361
|
-
tooltip: {
|
362
|
-
trigger: 'axis',
|
363
|
-
axisPointer: {
|
364
|
-
type: 'shadow'
|
365
|
-
}
|
366
|
-
},
|
367
|
-
xAxis: {
|
368
|
-
type: 'value',
|
369
|
-
boundaryGap: [0, 0.01]
|
370
|
-
},
|
371
|
-
yAxis: {
|
372
|
-
type: 'category',
|
373
|
-
data: SERIES_DATA.sort(order_by_hits).map(row => row['Country'] ),
|
374
|
-
},
|
375
|
-
series: [
|
376
|
-
{
|
377
|
-
type: 'bar',
|
378
|
-
data: SERIES_DATA.sort(order_by_hits).map(row => row['Hits'] ),
|
379
|
-
color: '#4C78A8',
|
380
|
-
label: {
|
381
|
-
show: true,
|
382
|
-
position: 'right'
|
383
|
-
},
|
384
|
-
},
|
385
|
-
]
|
386
|
-
};
|
387
|
-
|
388
|
-
function order_by_hits(a, b) {
|
389
|
-
return Number(a['Hits']) < Number(b['Hits']) ? -1 : 1
|
390
|
-
}
|
391
|
-
"
|
392
|
-
},
|
149
|
+
palette: :apache
|
150
|
+
),
|
151
|
+
countries(data, color: '#4C78A8'),
|
393
152
|
ip_per_hour_report_spec(ips_per_hour(data[:ips_per_hour])),
|
394
153
|
{
|
395
154
|
title: "Combined Platform Data",
|
data/lib/log_sense/emitter.rb
CHANGED
@@ -28,6 +28,8 @@ module LogSense
|
|
28
28
|
@data = data
|
29
29
|
@options = options
|
30
30
|
@report_title = options[:input_format].capitalize
|
31
|
+
|
32
|
+
@format_specific_theme = "#{@options[:input_format]}_theme.css"
|
31
33
|
@format_specific_css = "#{@options[:input_format]}.css.erb"
|
32
34
|
|
33
35
|
# Chooses template and destination
|
@@ -122,15 +122,25 @@ module LogSense
|
|
122
122
|
ON event.log_id == error.log_id
|
123
123
|
WHERE #{filter} and substr(status, 1, 1) == '5').gsub("\n", "") || [[]]
|
124
124
|
|
125
|
+
@internal_server_error_plot = @db.execute %Q(
|
126
|
+
SELECT strftime('%Y-%m-%d', started_at) as Day,
|
127
|
+
count(distinct(event.id)) as Errors
|
128
|
+
FROM Event JOIN Error
|
129
|
+
ON event.log_id == error.log_id
|
130
|
+
WHERE #{filter} and substr(status, 1, 1) == '5'
|
131
|
+
GROUP BY strftime('%Y-%m-%d', started_at)).gsub("\n", "") || [[]]
|
132
|
+
|
125
133
|
@error = @db.execute %Q(
|
126
|
-
SELECT filename,
|
134
|
+
SELECT filename,
|
135
|
+
log_id, description, count(log_id)
|
127
136
|
FROM Error
|
128
137
|
WHERE (description NOT LIKE '%No route matches%' and
|
129
138
|
description NOT LIKE '%Couldn''t find%')
|
130
139
|
GROUP BY description).gsub("\n", "") || [[]]
|
131
140
|
|
132
141
|
@possible_attacks = @db.execute %Q(
|
133
|
-
SELECT filename,
|
142
|
+
SELECT filename,
|
143
|
+
log_id, description, count(log_id)
|
134
144
|
FROM Error
|
135
145
|
WHERE (description LIKE '%No route matches%' or
|
136
146
|
description LIKE '%Couldn''t find%')
|
@@ -39,73 +39,9 @@ module LogSense
|
|
39
39
|
]
|
40
40
|
};",
|
41
41
|
},
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
column_alignment: %i[left right],
|
46
|
-
rows: data[:time_distribution],
|
47
|
-
echarts_spec: "{
|
48
|
-
xAxis: {
|
49
|
-
type: 'category',
|
50
|
-
data: SERIES_DATA.map(row => row['Hour'])
|
51
|
-
/* data: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
|
52
|
-
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
|
53
|
-
'20', '21', '22', '23', '24'] */
|
54
|
-
},
|
55
|
-
yAxis: {
|
56
|
-
type: 'value'
|
57
|
-
},
|
58
|
-
tooltip: {
|
59
|
-
trigger: 'axis'
|
60
|
-
},
|
61
|
-
series: [
|
62
|
-
{
|
63
|
-
data: SERIES_DATA.map(row => row['Hits']),
|
64
|
-
type: 'bar',
|
65
|
-
color: '#D30001',
|
66
|
-
label: {
|
67
|
-
show: true,
|
68
|
-
position: 'top'
|
69
|
-
},
|
70
|
-
}
|
71
|
-
]
|
72
|
-
}",
|
73
|
-
},
|
74
|
-
{
|
75
|
-
title: "Statuses",
|
76
|
-
header: %w[Status Count],
|
77
|
-
column_alignment: %i[left right],
|
78
|
-
rows: data[:statuses],
|
79
|
-
col: "small-12 cell",
|
80
|
-
echarts_spec: "{
|
81
|
-
xAxis: {
|
82
|
-
type: 'category',
|
83
|
-
data: SERIES_DATA.map(row => row['Status'])
|
84
|
-
/* data: ['100', '101', '102', '103',
|
85
|
-
'200', '201', '202', '203', '204', '205', '206', '207', '208', '226',
|
86
|
-
'300', '301', '302', '303', '304', '305', '306', '307', '308',
|
87
|
-
'400', '401', '402', '403', '404', '405', '406', '407', '408', '409', '410', '411', '412', '413', '414', '415', '416', '417', '418', '421', '422', '423', '424', '425', '426', '428', '429', '431', '451',
|
88
|
-
'500', '501', '502', '503', '504', '505', '506', '507', '508', '510', '511'] */
|
89
|
-
},
|
90
|
-
yAxis: {
|
91
|
-
type: 'value'
|
92
|
-
},
|
93
|
-
tooltip: {
|
94
|
-
trigger: 'axis'
|
95
|
-
},
|
96
|
-
series: [
|
97
|
-
{
|
98
|
-
data: SERIES_DATA.map(row => row['Count']),
|
99
|
-
type: 'bar',
|
100
|
-
color: '#D30001',
|
101
|
-
label: {
|
102
|
-
show: true,
|
103
|
-
position: 'top'
|
104
|
-
},
|
105
|
-
}
|
106
|
-
]
|
107
|
-
}",
|
108
|
-
},
|
42
|
+
time_distribution(data),
|
43
|
+
total_statuses(data),
|
44
|
+
daily_statuses(data),
|
109
45
|
{
|
110
46
|
title: "Rails Performance",
|
111
47
|
header: %w[Controller Hits Min Avg Max],
|
@@ -208,7 +144,7 @@ module LogSense
|
|
208
144
|
data: fatal_plot.filter(row => row[0] != '').map(row => row[0]),
|
209
145
|
showGrid: true,
|
210
146
|
axisLabel: {
|
211
|
-
rotate: 45 // Rotate the labels
|
147
|
+
rotate: 45 // Rotate the labels
|
212
148
|
}
|
213
149
|
},
|
214
150
|
yAxis: {
|
@@ -234,72 +170,8 @@ module LogSense
|
|
234
170
|
header: %w[Date Status IP URL Description Log ID],
|
235
171
|
column_alignment: %i[left left left left left left],
|
236
172
|
rows: data[:internal_server_error],
|
237
|
-
col: "small-12 cell"
|
238
|
-
|
239
|
-
{
|
240
|
-
title: "Errors",
|
241
|
-
header: %w[Log ID Description Count],
|
242
|
-
column_alignment: %i[left left left],
|
243
|
-
rows: data[:error],
|
244
|
-
col: "large-6 cell"
|
245
|
-
},
|
246
|
-
{
|
247
|
-
title: "Possible Attacks",
|
248
|
-
header: %w[Log ID Description Count],
|
249
|
-
column_alignment: %i[left left left],
|
250
|
-
rows: data[:possible_attacks],
|
251
|
-
col: "large-6 cell"
|
252
|
-
},
|
253
|
-
{
|
254
|
-
title: "Browsers",
|
255
|
-
header: %w[Browser Visits],
|
256
|
-
column_alignment: %i[left right],
|
257
|
-
rows: data[:browsers],
|
258
|
-
echarts_spec: "{
|
259
|
-
toolbox: {
|
260
|
-
feature: {
|
261
|
-
saveAsImage: {},
|
262
|
-
}
|
263
|
-
},
|
264
|
-
tooltip: {
|
265
|
-
trigger: 'axis'
|
266
|
-
},
|
267
|
-
xAxis: {
|
268
|
-
type: 'category',
|
269
|
-
data: SERIES_DATA.sort(order_by_name).map(row => row['Browser']),
|
270
|
-
showGrid: true,
|
271
|
-
axisLabel: {
|
272
|
-
rotate: 45 // Rotate the labels by 90 degrees
|
273
|
-
}
|
274
|
-
},
|
275
|
-
yAxis: {
|
276
|
-
type: 'value',
|
277
|
-
name: 'Browser Visits',
|
278
|
-
showGrid: true,
|
279
|
-
},
|
280
|
-
series: [
|
281
|
-
{
|
282
|
-
name: 'Hits',
|
283
|
-
data: SERIES_DATA.sort(order_by_name).map(row => row['Visits']),
|
284
|
-
type: 'bar',
|
285
|
-
color: '#D30001',
|
286
|
-
label: {
|
287
|
-
show: true,
|
288
|
-
position: 'top'
|
289
|
-
},
|
290
|
-
},
|
291
|
-
]
|
292
|
-
}
|
293
|
-
function order_by_name(a, b) {
|
294
|
-
return a['Browser'] < b['Browser'] ? -1 : 1
|
295
|
-
}
|
296
|
-
",
|
297
|
-
},
|
298
|
-
{
|
299
|
-
title: "Platforms",
|
300
|
-
header: %w[Platform Visits],
|
301
|
-
column_alignment: %i[left right],
|
302
|
-
rows: data[:platforms],
|
173
|
+
col: "small-12 cell",
|
174
|
+
echarts_extra: "var internal_server_error_plot=#{data[:internal_server_error_plot].to_json}",
|
303
175
|
echarts_spec: "{
|
304
176
|
toolbox: {
|
305
177
|
feature: {
|
@@ -311,21 +183,20 @@ module LogSense
|
|
311
183
|
},
|
312
184
|
xAxis: {
|
313
185
|
type: 'category',
|
314
|
-
data:
|
186
|
+
data: internal_server_error_plot.filter(row => row[0] != '').map(row => row[0]),
|
315
187
|
showGrid: true,
|
316
188
|
axisLabel: {
|
317
|
-
rotate: 45 // Rotate the labels
|
189
|
+
rotate: 45 // Rotate the labels
|
318
190
|
}
|
319
191
|
},
|
320
192
|
yAxis: {
|
321
193
|
type: 'value',
|
322
|
-
name: '
|
194
|
+
name: 'Errors',
|
323
195
|
showGrid: true,
|
324
196
|
},
|
325
197
|
series: [
|
326
198
|
{
|
327
|
-
|
328
|
-
data: SERIES_DATA.sort(order_by_platform).map(row => row['Visits']),
|
199
|
+
data: internal_server_error_plot.filter(row => row[0] != '').map(row => row[1]),
|
329
200
|
type: 'bar',
|
330
201
|
color: '#D30001',
|
331
202
|
label: {
|
@@ -334,73 +205,29 @@ module LogSense
|
|
334
205
|
},
|
335
206
|
},
|
336
207
|
]
|
337
|
-
}
|
338
|
-
function order_by_platform(a, b) {
|
339
|
-
return a['Platform'] < b['Platform'] ? -1 : 1
|
340
|
-
}",
|
208
|
+
};"
|
341
209
|
},
|
342
210
|
{
|
343
|
-
title: "
|
344
|
-
header: %w[
|
345
|
-
column_alignment: %i[left
|
346
|
-
rows: data[:
|
211
|
+
title: "Errors",
|
212
|
+
header: %w[Log ID Description Count],
|
213
|
+
column_alignment: %i[left left left right],
|
214
|
+
rows: data[:error],
|
215
|
+
col: "small-12 cell"
|
347
216
|
},
|
348
217
|
{
|
349
|
-
title: "
|
350
|
-
header: [
|
351
|
-
column_alignment: %i[left
|
352
|
-
rows:
|
353
|
-
|
354
|
-
echarts_spec: "{
|
355
|
-
tooltip: {
|
356
|
-
trigger: 'axis',
|
357
|
-
axisPointer: {
|
358
|
-
type: 'shadow'
|
359
|
-
}
|
360
|
-
},
|
361
|
-
xAxis: {
|
362
|
-
type: 'value',
|
363
|
-
boundaryGap: [0, 0.01]
|
364
|
-
},
|
365
|
-
yAxis: {
|
366
|
-
type: 'category',
|
367
|
-
data: SERIES_DATA.sort(order_by_hits).map(row => row['Country'] ),
|
368
|
-
},
|
369
|
-
series: [
|
370
|
-
{
|
371
|
-
type: 'bar',
|
372
|
-
data: SERIES_DATA.sort(order_by_hits).map(row => row['Hits'] ),
|
373
|
-
color: '#D30001',
|
374
|
-
label: {
|
375
|
-
show: true,
|
376
|
-
position: 'right'
|
377
|
-
},
|
378
|
-
},
|
379
|
-
]
|
380
|
-
};
|
381
|
-
|
382
|
-
function order_by_hits(a, b) {
|
383
|
-
return Number(a['Hits']) < Number(b['Hits']) ? -1 : 1
|
384
|
-
}
|
385
|
-
"
|
218
|
+
title: "Potential Attacks",
|
219
|
+
header: %w[Log ID Description Count],
|
220
|
+
column_alignment: %i[left left left right],
|
221
|
+
rows: data[:possible_attacks],
|
222
|
+
col: "small-12 cell"
|
386
223
|
},
|
224
|
+
browsers(data),
|
225
|
+
platforms(data),
|
226
|
+
ips(data),
|
227
|
+
countries(data),
|
387
228
|
ip_per_hour_report_spec(ips_per_hour(data[:ips_per_hour])),
|
388
229
|
session_report_spec(ips_detailed(data[:ips_per_day_detailed]))
|
389
230
|
]
|
390
231
|
end
|
391
|
-
|
392
|
-
private
|
393
|
-
|
394
|
-
# { country => [[ip, visit, country], ...]
|
395
|
-
def countries_table(data)
|
396
|
-
data&.map { |k, v|
|
397
|
-
[
|
398
|
-
k || "-",
|
399
|
-
v.map { |x| x[1] }.inject(&:+),
|
400
|
-
v.map { |x| x[0] }.uniq.size,
|
401
|
-
v.map { |x| x[0] }.join(WORDS_SEPARATOR)
|
402
|
-
]
|
403
|
-
}&.sort { |x, y| x[0] <=> y[0] }
|
404
|
-
end
|
405
232
|
end
|
406
233
|
end
|