log_sense 1.7.0 → 1.8.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 +5 -0
- data/README.org +46 -46
- data/lib/log_sense/apache_report_shaper.rb +267 -163
- data/lib/log_sense/emitter.rb +1 -3
- data/lib/log_sense/rails/log_parser.rb +74 -14
- data/lib/log_sense/rails_aggregator.rb +74 -1
- data/lib/log_sense/rails_report_shaper.rb +330 -107
- data/lib/log_sense/templates/_log_structure.html.erb +6 -6
- data/lib/log_sense/templates/_performance.html.erb +6 -5
- data/lib/log_sense/templates/_rails.css.erb +14 -2
- data/lib/log_sense/templates/_stylesheet.css +26 -8
- data/lib/log_sense/templates/_summary.html.erb +8 -8
- data/lib/log_sense/templates/report_html.erb +18 -2
- data/lib/log_sense/version.rb +1 -1
- metadata +2 -2
@@ -37,7 +37,7 @@ module LogSense
|
|
37
37
|
source_file TEXT,
|
38
38
|
line_number INTEGER
|
39
39
|
)
|
40
|
-
|
40
|
+
EOS
|
41
41
|
|
42
42
|
ins = db.prepare <<-EOS
|
43
43
|
insert into Event(
|
@@ -60,7 +60,7 @@ module LogSense
|
|
60
60
|
line_number
|
61
61
|
)
|
62
62
|
values (#{Array.new(17, "?").join(", ")})
|
63
|
-
|
63
|
+
EOS
|
64
64
|
|
65
65
|
db.execute <<-EOS
|
66
66
|
CREATE TABLE IF NOT EXISTS Error(
|
@@ -71,18 +71,18 @@ module LogSense
|
|
71
71
|
filename TEXT,
|
72
72
|
line_number INTEGER
|
73
73
|
)
|
74
|
-
|
74
|
+
EOS
|
75
75
|
|
76
76
|
ins_error = db.prepare <<-EOS
|
77
|
-
|
77
|
+
insert into Error(
|
78
78
|
log_id,
|
79
79
|
context,
|
80
80
|
description,
|
81
81
|
filename,
|
82
82
|
line_number
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
)
|
84
|
+
values (?, ?, ?, ?, ?)
|
85
|
+
EOS
|
86
86
|
|
87
87
|
db.execute <<-EOS
|
88
88
|
CREATE TABLE IF NOT EXISTS Render(
|
@@ -93,18 +93,46 @@ module LogSense
|
|
93
93
|
filename TEXT,
|
94
94
|
line_number INTEGER
|
95
95
|
)
|
96
|
-
|
96
|
+
EOS
|
97
97
|
|
98
98
|
ins_rendered = db.prepare <<-EOS
|
99
|
-
|
99
|
+
insert into Render(
|
100
100
|
partial,
|
101
101
|
duration_ms,
|
102
102
|
allocations,
|
103
103
|
filename,
|
104
104
|
line_number
|
105
|
-
|
106
|
-
|
107
|
-
|
105
|
+
)
|
106
|
+
values (?, ?, ?, ?, ?)
|
107
|
+
EOS
|
108
|
+
|
109
|
+
db.execute <<-EOS
|
110
|
+
CREATE TABLE IF NOT EXISTS BrowserInfo(
|
111
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
112
|
+
browser TEXT,
|
113
|
+
platform TEXT,
|
114
|
+
device_name TEXT,
|
115
|
+
controller TEXT,
|
116
|
+
method TEXT,
|
117
|
+
request_format TEXT,
|
118
|
+
anon_ip TEXT,
|
119
|
+
timestamp TEXT
|
120
|
+
)
|
121
|
+
EOS
|
122
|
+
|
123
|
+
ins_browser_info = db.prepare <<-EOS
|
124
|
+
insert into BrowserInfo(
|
125
|
+
browser,
|
126
|
+
platform,
|
127
|
+
device_name,
|
128
|
+
controller,
|
129
|
+
method,
|
130
|
+
request_format,
|
131
|
+
anon_ip,
|
132
|
+
timestamp
|
133
|
+
)
|
134
|
+
values (?, ?, ?, ?, ?, ?, ?, ?)
|
135
|
+
EOS
|
108
136
|
|
109
137
|
# requests in the log might be interleaved.
|
110
138
|
#
|
@@ -149,6 +177,19 @@ module LogSense
|
|
149
177
|
# I and F for completed requests, [ is for error messages
|
150
178
|
next if line[0] != 'I' and line[0] != 'F' and line[0] != '['
|
151
179
|
|
180
|
+
data = match_and_process_browser_info line
|
181
|
+
if data
|
182
|
+
ins_browser_info.execute(data[:browser],
|
183
|
+
data[:platform],
|
184
|
+
data[:device_name],
|
185
|
+
data[:controller],
|
186
|
+
data[:method],
|
187
|
+
data[:request_format],
|
188
|
+
data[:anon_ip],
|
189
|
+
data[:timestamp])
|
190
|
+
next
|
191
|
+
end
|
192
|
+
|
152
193
|
data = match_and_process_error line
|
153
194
|
if data
|
154
195
|
ins_error.execute(data[:log_id],
|
@@ -245,6 +286,7 @@ module LogSense
|
|
245
286
|
db
|
246
287
|
end
|
247
288
|
|
289
|
+
|
248
290
|
TIMESTAMP = /(?<timestamp>[^ ]+)/
|
249
291
|
ID = /(?<id>[a-z0-9-]+)/
|
250
292
|
VERB = /(?<verb>GET|POST|PATCH|PUT|DELETE)/
|
@@ -254,6 +296,24 @@ module LogSense
|
|
254
296
|
STATUS_IN_WORDS = /(OK|Unauthorized|Found|Internal Server Error|Bad Request|Method Not Allowed|Request Timeout|Not Implemented|Bad Gateway|Service Unavailable)/
|
255
297
|
MSECS = /[0-9.]+/
|
256
298
|
|
299
|
+
# I, [2024-07-01T02:21:34.339058 #1392909] INFO -- : [815b3e28-8d6e-4741-8605-87654a9ff58c] BrowserInfo: "Unknown Browser","unknown_platform","Unknown","Devise::SessionsController","new","html","4db749654a0fcacbf3868f87723926e7405262f8d596e8514f4997dc80a3cd7e","2024-07-01T02:21:34+02:00"
|
300
|
+
BROWSER_INFO_REGEXP = /BrowserInfo: "(?<browser>.+)","(?<platform>.+)","(?<device_name>.+)","(?<controller>.+)","(?<method>.+)","(?<request_format>.+)","(?<anon_ip>.+)","(?<timestamp>.+)"/
|
301
|
+
def match_and_process_browser_info(line)
|
302
|
+
matchdata = BROWSER_INFO_REGEXP.match line
|
303
|
+
if matchdata
|
304
|
+
{
|
305
|
+
browser: matchdata[:browser],
|
306
|
+
platform: matchdata[:platform],
|
307
|
+
device_name: matchdata[:device_name],
|
308
|
+
controller: matchdata[:controller],
|
309
|
+
method: matchdata[:method],
|
310
|
+
request_format: matchdata[:request_format],
|
311
|
+
anon_ip: matchdata[:anon_ip],
|
312
|
+
timestamp: matchdata[:timestamp],
|
313
|
+
}
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
257
317
|
# Error Messages
|
258
318
|
# [584cffcc-f1fd-4b5c-bb8b-b89621bd4921] ActionController::RoutingError (No route matches [GET] "/assets/foundation-icons.svg"):
|
259
319
|
# [fd8df8b5-83c9-48b5-a056-e5026e31bd5e] ActionView::Template::Error (undefined method `all_my_ancestor' for nil:NilClass):
|
@@ -261,7 +321,7 @@ module LogSense
|
|
261
321
|
EXCEPTION = /[A-Za-z_0-9:]+(Error)?/
|
262
322
|
ERROR_REGEXP = /^\[#{ID}\] (?<context>#{EXCEPTION}) \((?<description>(#{EXCEPTION})?.*)\):/
|
263
323
|
|
264
|
-
def match_and_process_error
|
324
|
+
def match_and_process_error(line)
|
265
325
|
matchdata = ERROR_REGEXP.match line
|
266
326
|
if matchdata
|
267
327
|
{
|
@@ -275,7 +335,7 @@ module LogSense
|
|
275
335
|
# I, [2021-10-19T08:16:34.343858 #10477] INFO -- : [67103c0d-455d-4fe8-951e-87e97628cb66] Started GET "/grow/people/471" for 217.77.80.35 at 2021-10-19 08:16:34 +0000
|
276
336
|
STARTED_REGEXP = /I, \[#{TIMESTAMP} #[0-9]+\] INFO -- : \[#{ID}\] Started #{VERB} "#{URL}" for #{IP} at/
|
277
337
|
|
278
|
-
def match_and_process_start
|
338
|
+
def match_and_process_start(line)
|
279
339
|
matchdata = STARTED_REGEXP.match line
|
280
340
|
if matchdata
|
281
341
|
{
|
@@ -40,6 +40,62 @@ module LogSense
|
|
40
40
|
where #{filter}
|
41
41
|
group by controller order by controller).gsub("\n", "")
|
42
42
|
|
43
|
+
#
|
44
|
+
# Use the performance information to build a tree map.
|
45
|
+
# We then compute by device and show the treemap and the table by device
|
46
|
+
# together
|
47
|
+
#
|
48
|
+
|
49
|
+
# ["CompletedSurveysController#new", 14, "22.00", "51.57", "116.00"]
|
50
|
+
controller_and_methods = @performance.group_by { |element|
|
51
|
+
(element[0] || "#").split("#")[0]
|
52
|
+
}
|
53
|
+
|
54
|
+
@controller_and_methods_treemap = controller_and_methods.map do |key, values|
|
55
|
+
{
|
56
|
+
name: key,
|
57
|
+
value: values.map { |value| value[1] || 0.0 }.inject(&:+),
|
58
|
+
children: values.map { |value|
|
59
|
+
{
|
60
|
+
name: (value[0] || "#").split("#")[1],
|
61
|
+
value: value[1]
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
@controller_and_methods_by_device = @db.execute %Q(
|
68
|
+
SELECT controller as Controller,
|
69
|
+
method as Method,
|
70
|
+
request_format as Format,
|
71
|
+
sum(iif(platform = 'ios', 1, 0)) as iOS,
|
72
|
+
sum(iif(platform = 'android', 1, 0)) as Android,
|
73
|
+
sum(iif(platform = 'mac', 1, 0)) as Mac,
|
74
|
+
sum(iif(platform = 'windows', 1, 0)) as Windows,
|
75
|
+
sum(iif(platform = 'linux', 1, 0)) as Linux,
|
76
|
+
sum(iif(platform != 'ios' and platform != 'android' and platform != 'mac' and platform != 'windows' and platform != 'linux', 1, 0)) as Other,
|
77
|
+
count(distinct(id)) as Total
|
78
|
+
from BrowserInfo
|
79
|
+
group by controller, method, request_format
|
80
|
+
)
|
81
|
+
|
82
|
+
#
|
83
|
+
# Browser Info data
|
84
|
+
#
|
85
|
+
@browsers = @db.execute %Q(
|
86
|
+
SELECT browser as Browser,
|
87
|
+
count(distinct(id)) as Visits
|
88
|
+
from BrowserInfo
|
89
|
+
group by browser
|
90
|
+
)
|
91
|
+
|
92
|
+
@platforms = @db.execute %Q(
|
93
|
+
SELECT platform as Platform,
|
94
|
+
count(distinct(id)) as Visits
|
95
|
+
from BrowserInfo
|
96
|
+
group by platform
|
97
|
+
)
|
98
|
+
|
43
99
|
@fatal = @db.execute %Q(
|
44
100
|
SELECT strftime("%Y-%m-%d %H:%M", started_at),
|
45
101
|
ip,
|
@@ -50,6 +106,14 @@ module LogSense
|
|
50
106
|
ON event.log_id == error.log_id
|
51
107
|
WHERE #{filter} and exit_status == 'F').gsub("\n", "") || [[]]
|
52
108
|
|
109
|
+
@fatal_plot = @db.execute %Q(
|
110
|
+
SELECT strftime("%Y-%m-%d", started_at) as Day,
|
111
|
+
count(distinct(event.id)) as Errors
|
112
|
+
FROM Event JOIN Error
|
113
|
+
ON event.log_id == error.log_id
|
114
|
+
WHERE #{filter} and exit_status == 'F'
|
115
|
+
GROUP BY strftime("%Y-%m-%d", started_at)).gsub("\n", "") || [[]]
|
116
|
+
|
53
117
|
@internal_server_error = @db.execute %Q(
|
54
118
|
SELECT strftime("%Y-%m-%d %H:%M", started_at), status, ip, url,
|
55
119
|
error.description,
|
@@ -59,10 +123,19 @@ module LogSense
|
|
59
123
|
WHERE #{filter} and substr(status, 1, 1) == '5').gsub("\n", "") || [[]]
|
60
124
|
|
61
125
|
@error = @db.execute %Q(
|
62
|
-
SELECT filename, log_id,
|
126
|
+
SELECT filename, log_id, description, count(log_id)
|
63
127
|
FROM Error
|
128
|
+
WHERE (description NOT LIKE '%No route matches%' and
|
129
|
+
description NOT LIKE '%Couldn''t find%')
|
64
130
|
GROUP BY description).gsub("\n", "") || [[]]
|
65
131
|
|
132
|
+
@possible_attacks = @db.execute %Q(
|
133
|
+
SELECT filename, log_id, description, count(log_id)
|
134
|
+
FROM Error
|
135
|
+
WHERE (description LIKE '%No route matches%' or
|
136
|
+
description LIKE '%Couldn''t find%')
|
137
|
+
GROUP BY description).gsub("\n", "") || [[]]
|
138
|
+
|
66
139
|
instance_vars_to_hash
|
67
140
|
end
|
68
141
|
end
|