log_sense 1.0.7 → 1.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f2fcc8402c27ec959854e3cd032e9e75693e538d3ca0879de3f4cf0b6aae9c5
4
- data.tar.gz: e2530ff646c436ca88e674a698bf71876f2e62bc0b59f20ebbc4e38fdd787830
3
+ metadata.gz: 45cf68bf2165554a6392a9277c121952e05dd9a283fe59b881ef957f3682920e
4
+ data.tar.gz: 99ded91c60080ffbfda3e60f05ee4b058e215286adfccdb2a727a50d2c7d0467
5
5
  SHA512:
6
- metadata.gz: 30932a09a0a0d0717c4e5caa9a579bb60a3a930dc144dc318029945e0364e71e5ddf5d5868ccf758a11d3ed5f73f5d690f482521e3475f1f16a5a041fa4abd8a
7
- data.tar.gz: da8ac76f281cf9f8c67805621fe098d1480889f2fb5a55a378d1ffae3383c1913d572c28c9a68c876fb710b4e8bc3213b157c51cdf008f1505c320ef5fabedd0
6
+ metadata.gz: 45674016ae3c3110584e967dd60166391a07b1401186428e7e949c012bfc883686110e86afeec5450e03d34a8b7831c6bbc1d1b9393215808a2d1feafcd6422b
7
+ data.tar.gz: a4e9b7bf983d23ba4e8ac744621e34c5b83eee45076cf165ba9eb856d5687d47191ab048be6fed0ca4316448c84d8f80e1b7daedb518d94a90b52b7f94ee2077
data/.gitignore CHANGED
@@ -6,5 +6,5 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
-
9
+ node_modules
10
10
  *~
@@ -34,6 +34,8 @@ module LogSense
34
34
  end
35
35
 
36
36
  def self.locate_ip ip, db
37
+ return if not ip
38
+
37
39
  ip_n = IPAddr.new(ip).to_i
38
40
  res = db.execute "SELECT * FROM ip_location where from_ip_n <= #{ip_n} order by from_ip_n desc limit 1"
39
41
  begin
@@ -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. Defaults to org mode") do |n|
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 = ! first_day_s[0][0] ? nil : Date.parse(first_day_s[0][0])
19
- @last_day = ! last_day_s[0][0] ? nil : Date.parse(last_day_s[0][0])
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
- values (#{Array.new(13, '?').join(', ')})")
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 %>
@@ -1,3 +1,3 @@
1
1
  module LogSense
2
- VERSION = "1.0.7"
2
+ VERSION = "1.0.8"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: log_sense
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adolfo Villafiorita