log_sense 1.0.7 → 1.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/lib/log_sense/ip_locator.rb +2 -0
- data/lib/log_sense/options_parser.rb +2 -1
- data/lib/log_sense/rails_data_cruncher.rb +4 -2
- data/lib/log_sense/rails_log_parser.rb +122 -6
- data/lib/log_sense/templates/_summary.html.erb +1 -1
- data/lib/log_sense/templates/_summary.txt.erb +1 -1
- data/lib/log_sense/templates/rails.txt.erb +6 -0
- data/lib/log_sense/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45cf68bf2165554a6392a9277c121952e05dd9a283fe59b881ef957f3682920e
|
4
|
+
data.tar.gz: 99ded91c60080ffbfda3e60f05ee4b058e215286adfccdb2a727a50d2c7d0467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45674016ae3c3110584e967dd60166391a07b1401186428e7e949c012bfc883686110e86afeec5450e03d34a8b7831c6bbc1d1b9393215808a2d1feafcd6422b
|
7
|
+
data.tar.gz: a4e9b7bf983d23ba4e8ac744621e34c5b83eee45076cf165ba9eb856d5687d47191ab048be6fed0ca4316448c84d8f80e1b7daedb518d94a90b52b7f94ee2077
|
data/.gitignore
CHANGED
data/lib/log_sense/ip_locator.rb
CHANGED
@@ -22,7 +22,7 @@ module LogSense
|
|
22
22
|
args[:input_file] = n
|
23
23
|
end
|
24
24
|
|
25
|
-
opts.on("-tFORMAT", "--output-format=FORMAT", String, "Output format: html, org, txt, sqlite.
|
25
|
+
opts.on("-tFORMAT", "--output-format=FORMAT", String, "Output format: html, org, txt, sqlite. See below for available formats") do |n|
|
26
26
|
args[:output_format] = n
|
27
27
|
end
|
28
28
|
|
@@ -74,6 +74,7 @@ module LogSense
|
|
74
74
|
components = templates.map { |x| File.basename(x).split "." }.group_by { |x| x[0] }
|
75
75
|
components.each do |k, vs|
|
76
76
|
puts "#{k} parsing can produce the following outputs:"
|
77
|
+
puts " - sqlite"
|
77
78
|
vs.each do |v|
|
78
79
|
puts " - #{v[1]}"
|
79
80
|
end
|
@@ -15,8 +15,8 @@ module LogSense
|
|
15
15
|
|
16
16
|
# make first and last day into dates or nil
|
17
17
|
# TODO: bug possible value here: [[nil]], which is not empty
|
18
|
-
@first_day =
|
19
|
-
@last_day =
|
18
|
+
@first_day = first_day_s&.first&.first ? Date.parse(first_day_s[0][0]) : nil
|
19
|
+
@last_day = last_day_s&.first&.first ? Date.parse(last_day_s[0][0]) : nil
|
20
20
|
|
21
21
|
@total_days = 0
|
22
22
|
if @first_day and @last_day
|
@@ -100,6 +100,8 @@ module LogSense
|
|
100
100
|
|
101
101
|
@performance = db.execute "SELECT distinct(controller), count(controller), printf(\"%.2f\", min(duration_total_ms)), printf(\"%.2f\", avg(duration_total_ms)), printf(\"%.2f\", max(duration_total_ms)) from Event group by controller order by controller"
|
102
102
|
|
103
|
+
@fatal = db.execute "SELECT strftime(\"%Y-%m-%d %H:%M\", started_at), ip, url, log_id FROM Event WHERE exit_status == 'F'"
|
104
|
+
|
103
105
|
data = {}
|
104
106
|
self.instance_variables.each do |variable|
|
105
107
|
var_as_symbol = variable.to_s[1..-1].to_sym
|
@@ -8,6 +8,7 @@ module LogSense
|
|
8
8
|
db = SQLite3::Database.new ":memory:"
|
9
9
|
db.execute 'CREATE TABLE IF NOT EXISTS Event(
|
10
10
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
11
|
+
exit_status TEXT,
|
11
12
|
started_at TEXT,
|
12
13
|
ended_at TEXT,
|
13
14
|
log_id TEXT,
|
@@ -20,10 +21,12 @@ module LogSense
|
|
20
21
|
duration_total_ms FLOAT,
|
21
22
|
duration_views_ms FLOAT,
|
22
23
|
duration_ar_ms FLOAT,
|
23
|
-
allocations INTEGER
|
24
|
+
allocations INTEGER,
|
25
|
+
comment TEXT
|
24
26
|
)'
|
25
27
|
|
26
28
|
ins = db.prepare("insert into Event(
|
29
|
+
exit_status,
|
27
30
|
started_at,
|
28
31
|
ended_at,
|
29
32
|
log_id,
|
@@ -36,8 +39,10 @@ module LogSense
|
|
36
39
|
duration_total_ms,
|
37
40
|
duration_views_ms,
|
38
41
|
duration_ar_ms,
|
39
|
-
allocations
|
40
|
-
|
42
|
+
allocations,
|
43
|
+
comment
|
44
|
+
)
|
45
|
+
values (#{Array.new(15, '?').join(', ')})")
|
41
46
|
|
42
47
|
# requests in the log might be interleaved.
|
43
48
|
#
|
@@ -61,7 +66,7 @@ module LogSense
|
|
61
66
|
|
62
67
|
File.readlines(filename).each do |line|
|
63
68
|
# We discard LOG_LEVEL != 'I'
|
64
|
-
next if line[0] != 'I'
|
69
|
+
next if line[0] != 'I' and line[0] != 'F'
|
65
70
|
|
66
71
|
data = self.match_and_process_start line
|
67
72
|
if data
|
@@ -77,6 +82,37 @@ module LogSense
|
|
77
82
|
next
|
78
83
|
end
|
79
84
|
|
85
|
+
data = self.match_and_process_fatal line
|
86
|
+
if data
|
87
|
+
id = data[:log_id]
|
88
|
+
# it might as well be that the first event started before
|
89
|
+
# the log. With this, we make sure we add only events whose
|
90
|
+
# start was logged and parsed
|
91
|
+
if pending[id]
|
92
|
+
event = data.merge (pending[id] || {})
|
93
|
+
|
94
|
+
ins.execute(
|
95
|
+
event[:exit_status],
|
96
|
+
event[:started_at],
|
97
|
+
event[:ended_at],
|
98
|
+
event[:log_id],
|
99
|
+
event[:ip],
|
100
|
+
"#{DateTime.parse(event[:started_at]).strftime("%Y-%m-%d")} #{event[:ip]}",
|
101
|
+
event[:url],
|
102
|
+
event[:controller],
|
103
|
+
event[:html_verb],
|
104
|
+
event[:status],
|
105
|
+
event[:duration_total_ms],
|
106
|
+
event[:duration_views_ms],
|
107
|
+
event[:duration_ar_ms],
|
108
|
+
event[:allocations],
|
109
|
+
event[:comment]
|
110
|
+
)
|
111
|
+
|
112
|
+
pending.delete(id)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
80
116
|
data = self.match_and_process_completed line
|
81
117
|
if data
|
82
118
|
id = data[:log_id]
|
@@ -88,6 +124,40 @@ module LogSense
|
|
88
124
|
event = data.merge (pending[id] || {})
|
89
125
|
|
90
126
|
ins.execute(
|
127
|
+
event[:exit_status],
|
128
|
+
event[:started_at],
|
129
|
+
event[:ended_at],
|
130
|
+
event[:log_id],
|
131
|
+
event[:ip],
|
132
|
+
"#{DateTime.parse(event[:started_at]).strftime("%Y-%m-%d")} #{event[:ip]}",
|
133
|
+
event[:url],
|
134
|
+
event[:controller],
|
135
|
+
event[:html_verb],
|
136
|
+
event[:status],
|
137
|
+
event[:duration_total_ms],
|
138
|
+
event[:duration_views_ms],
|
139
|
+
event[:duration_ar_ms],
|
140
|
+
event[:allocations],
|
141
|
+
event[:comment]
|
142
|
+
)
|
143
|
+
|
144
|
+
pending.delete(id)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
data = self.match_and_process_completed_no_alloc line
|
150
|
+
if data
|
151
|
+
id = data[:log_id]
|
152
|
+
|
153
|
+
# it might as well be that the first event started before
|
154
|
+
# the log. With this, we make sure we add only events whose
|
155
|
+
# start was logged and parsed
|
156
|
+
if pending[id]
|
157
|
+
event = data.merge (pending[id] || {})
|
158
|
+
|
159
|
+
ins.execute(
|
160
|
+
event[:exit_status],
|
91
161
|
event[:started_at],
|
92
162
|
event[:ended_at],
|
93
163
|
event[:log_id],
|
@@ -100,12 +170,14 @@ module LogSense
|
|
100
170
|
event[:duration_total_ms],
|
101
171
|
event[:duration_views_ms],
|
102
172
|
event[:duration_ar_ms],
|
103
|
-
event[:allocations]
|
173
|
+
event[:allocations],
|
174
|
+
event[:comment]
|
104
175
|
)
|
105
176
|
|
106
177
|
pending.delete(id)
|
107
178
|
end
|
108
179
|
end
|
180
|
+
|
109
181
|
end
|
110
182
|
|
111
183
|
db
|
@@ -141,9 +213,10 @@ module LogSense
|
|
141
213
|
COMPLETED_REGEXP = /I, \[#{TIMESTAMP} #[0-9]+\] INFO -- : \[#{ID}\] Completed #{STATUS} [^ ]+ in (?<total>#{MSECS})ms \(Views: (?<views>#{MSECS})ms \| ActiveRecord: (?<arec>#{MSECS})ms \| Allocations: (?<alloc>[0-9]+)\)/
|
142
214
|
|
143
215
|
def self.match_and_process_completed line
|
144
|
-
matchdata = COMPLETED_REGEXP.match line
|
216
|
+
matchdata = (COMPLETED_REGEXP.match line)
|
145
217
|
if matchdata
|
146
218
|
{
|
219
|
+
exit_status: "I",
|
147
220
|
ended_at: matchdata[:timestamp],
|
148
221
|
log_id: matchdata[:id],
|
149
222
|
status: matchdata[:status],
|
@@ -151,12 +224,36 @@ module LogSense
|
|
151
224
|
duration_views_ms: matchdata[:views],
|
152
225
|
duration_ar_ms: matchdata[:arec],
|
153
226
|
allocations: matchdata[:alloc],
|
227
|
+
comment: ""
|
228
|
+
}
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# I, [2021-12-09T16:53:52.657727 #2735058] INFO -- : [0064e403-9eb2-439d-8fe1-a334c86f5532] Completed 200 OK in 13ms (Views: 11.1ms | ActiveRecord: 1.2ms)
|
235
|
+
COMPLETED_NO_ALLOC_REGEXP = /I, \[#{TIMESTAMP} #[0-9]+\] INFO -- : \[#{ID}\] Completed #{STATUS} [^ ]+ in (?<total>#{MSECS})ms \(Views: (?<views>#{MSECS})ms \| ActiveRecord: (?<arec>#{MSECS})ms\)/
|
236
|
+
|
237
|
+
def self.match_and_process_completed_no_alloc line
|
238
|
+
matchdata = (COMPLETED_NO_ALLOC_REGEXP.match line)
|
239
|
+
if matchdata
|
240
|
+
{
|
241
|
+
exit_status: "I",
|
242
|
+
ended_at: matchdata[:timestamp],
|
243
|
+
log_id: matchdata[:id],
|
244
|
+
status: matchdata[:status],
|
245
|
+
duration_total_ms: matchdata[:total],
|
246
|
+
duration_views_ms: matchdata[:views],
|
247
|
+
duration_ar_ms: matchdata[:arec],
|
248
|
+
allocations: -1,
|
249
|
+
comment: ""
|
154
250
|
}
|
155
251
|
else
|
156
252
|
nil
|
157
253
|
end
|
158
254
|
end
|
159
255
|
|
256
|
+
|
160
257
|
# I, [2021-10-19T08:16:34.345162 #10477] INFO -- : [67103c0d-455d-4fe8-951e-87e97628cb66] Processing by PeopleController#show as HTML
|
161
258
|
PROCESSING_REGEXP = /I, \[#{TIMESTAMP} #[0-9]+\] INFO -- : \[#{ID}\] Processing by (?<controller>[^ ]+) as/
|
162
259
|
|
@@ -172,6 +269,25 @@ module LogSense
|
|
172
269
|
end
|
173
270
|
end
|
174
271
|
|
272
|
+
# F, [2021-12-04T00:34:05.838973 #2735058] FATAL -- : [3a16162e-a6a5-435e-a9d8-c4df5dc0f728]
|
273
|
+
# F, [2021-12-04T00:34:05.839157 #2735058] FATAL -- : [3a16162e-a6a5-435e-a9d8-c4df5dc0f728] ActionController::RoutingError (No route matches [GET] "/wp/wp-includes/wlwmanifest.xml"):
|
274
|
+
# F, [2021-12-04T00:34:05.839209 #2735058] FATAL -- : [3a16162e-a6a5-435e-a9d8-c4df5dc0f728]
|
275
|
+
# F, [2021-12-04T00:34:05.839269 #2735058] FATAL -- : [3a16162e-a6a5-435e-a9d8-c4df5dc0f728] actionpack (5.2.4.4) lib/action_dispatch/middleware/debug_exceptions.rb:65:in `call'
|
276
|
+
FATAL_REGEXP = /F, \[#{TIMESTAMP} #[0-9]+\] FATAL -- : \[#{ID}\] (?<comment>.*)$/
|
277
|
+
|
278
|
+
def self.match_and_process_fatal line
|
279
|
+
matchdata = FATAL_REGEXP.match line
|
280
|
+
if matchdata
|
281
|
+
{
|
282
|
+
exit_status: "F",
|
283
|
+
log_id: matchdata[:id],
|
284
|
+
comment: matchdata[:comment]
|
285
|
+
}
|
286
|
+
else
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
175
291
|
end
|
176
292
|
|
177
293
|
end
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</tr>
|
26
26
|
<tr>
|
27
27
|
<th class="avg-hits-per-unique-visits">Unique Visits</th>
|
28
|
-
<td class="avg-hits-per-unique-visits"><%= data[:total_hits] / data[:total_unique_visits] %></td>
|
28
|
+
<td class="avg-hits-per-unique-visits"><%= data[:total_unique_visits] != 0 ? data[:total_hits] / data[:total_unique_visits] : "N/A" %></td>
|
29
29
|
</tr>
|
30
30
|
<tr>
|
31
31
|
<th class="tx">Tx</th>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
["Days", data[:total_days_in_analysis] ],
|
5
5
|
["Events", data[:events] ],
|
6
6
|
["Unique Visits", data[:total_unique_visits] ],
|
7
|
-
["Avg. Events per Visit", data[:events] / data[:total_unique_visits] ]
|
7
|
+
["Avg. Events per Visit", data[:total_unique_visits] != 0 ? data[:events] / data[:total_unique_visits] : "N/A" ]
|
8
8
|
]
|
9
9
|
table
|
10
10
|
%>
|
@@ -44,6 +44,12 @@ table.align_column(4, :right)
|
|
44
44
|
table
|
45
45
|
%>
|
46
46
|
|
47
|
+
** Fatal Events
|
48
|
+
|
49
|
+
<%= table = Terminal::Table.new headings: ['Date', 'IP', 'URL', 'Log ID'], rows: @data[:fatal]
|
50
|
+
table
|
51
|
+
%>
|
52
|
+
|
47
53
|
** Command Invocation
|
48
54
|
|
49
55
|
<%= render "command_invocation.txt.erb", data: data %>
|
data/lib/log_sense/version.rb
CHANGED