log_sense 1.5.2 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.org +27 -0
- data/Gemfile.lock +6 -4
- data/README.org +108 -34
- data/Rakefile +6 -6
- data/exe/log_sense +110 -39
- data/ip_locations/dbip-country-lite.sqlite3 +0 -0
- data/lib/log_sense/aggregator.rb +191 -0
- data/lib/log_sense/apache_aggregator.rb +122 -0
- data/lib/log_sense/apache_log_line_parser.rb +23 -21
- data/lib/log_sense/apache_log_parser.rb +15 -12
- data/lib/log_sense/apache_report_shaper.rb +309 -0
- data/lib/log_sense/emitter.rb +55 -553
- data/lib/log_sense/ip_locator.rb +24 -12
- data/lib/log_sense/options_checker.rb +24 -0
- data/lib/log_sense/options_parser.rb +81 -51
- data/lib/log_sense/rails_aggregator.rb +69 -0
- data/lib/log_sense/rails_log_parser.rb +82 -68
- data/lib/log_sense/rails_report_shaper.rb +183 -0
- data/lib/log_sense/report_shaper.rb +105 -0
- data/lib/log_sense/templates/_cdn_links.html.erb +11 -0
- data/lib/log_sense/templates/_command_invocation.html.erb +4 -0
- data/lib/log_sense/templates/_log_structure.html.erb +7 -1
- data/lib/log_sense/templates/_output_table.html.erb +6 -2
- data/lib/log_sense/templates/_rails.css.erb +7 -0
- data/lib/log_sense/templates/_summary.html.erb +9 -7
- data/lib/log_sense/templates/_summary.txt.erb +2 -2
- data/lib/log_sense/templates/{rails.html.erb → report_html.erb} +19 -37
- data/lib/log_sense/templates/{apache.txt.erb → report_txt.erb} +1 -1
- data/lib/log_sense/version.rb +1 -1
- data/lib/log_sense.rb +19 -9
- data/log_sense.gemspec +1 -1
- data/{apache-screenshot.png → screenshots/apache-screenshot.png} +0 -0
- data/screenshots/rails-screenshot.png +0 -0
- metadata +17 -11
- data/lib/log_sense/apache_data_cruncher.rb +0 -147
- data/lib/log_sense/rails_data_cruncher.rb +0 -141
- data/lib/log_sense/templates/apache.html.erb +0 -115
- data/lib/log_sense/templates/rails.txt.erb +0 -22
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: log_sense
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adolfo Villafiorita
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: browser
|
@@ -124,20 +124,25 @@ files:
|
|
124
124
|
- LICENSE.txt
|
125
125
|
- README.org
|
126
126
|
- Rakefile
|
127
|
-
- apache-screenshot.png
|
128
127
|
- bin/console
|
129
128
|
- bin/setup
|
130
129
|
- exe/log_sense
|
131
130
|
- ip_locations/dbip-country-lite.sqlite3
|
132
131
|
- lib/log_sense.rb
|
133
|
-
- lib/log_sense/
|
132
|
+
- lib/log_sense/aggregator.rb
|
133
|
+
- lib/log_sense/apache_aggregator.rb
|
134
134
|
- lib/log_sense/apache_log_line_parser.rb
|
135
135
|
- lib/log_sense/apache_log_parser.rb
|
136
|
+
- lib/log_sense/apache_report_shaper.rb
|
136
137
|
- lib/log_sense/emitter.rb
|
137
138
|
- lib/log_sense/ip_locator.rb
|
139
|
+
- lib/log_sense/options_checker.rb
|
138
140
|
- lib/log_sense/options_parser.rb
|
139
|
-
- lib/log_sense/
|
141
|
+
- lib/log_sense/rails_aggregator.rb
|
140
142
|
- lib/log_sense/rails_log_parser.rb
|
143
|
+
- lib/log_sense/rails_report_shaper.rb
|
144
|
+
- lib/log_sense/report_shaper.rb
|
145
|
+
- lib/log_sense/templates/_cdn_links.html.erb
|
141
146
|
- lib/log_sense/templates/_command_invocation.html.erb
|
142
147
|
- lib/log_sense/templates/_command_invocation.txt.erb
|
143
148
|
- lib/log_sense/templates/_log_structure.html.erb
|
@@ -146,25 +151,26 @@ files:
|
|
146
151
|
- lib/log_sense/templates/_output_table.txt.erb
|
147
152
|
- lib/log_sense/templates/_performance.html.erb
|
148
153
|
- lib/log_sense/templates/_performance.txt.erb
|
154
|
+
- lib/log_sense/templates/_rails.css.erb
|
149
155
|
- lib/log_sense/templates/_report_data.html.erb
|
150
156
|
- lib/log_sense/templates/_stylesheet.css
|
151
157
|
- lib/log_sense/templates/_summary.html.erb
|
152
158
|
- lib/log_sense/templates/_summary.txt.erb
|
153
159
|
- lib/log_sense/templates/_warning.txt.erb
|
154
|
-
- lib/log_sense/templates/
|
155
|
-
- lib/log_sense/templates/
|
156
|
-
- lib/log_sense/templates/rails.html.erb
|
157
|
-
- lib/log_sense/templates/rails.txt.erb
|
160
|
+
- lib/log_sense/templates/report_html.erb
|
161
|
+
- lib/log_sense/templates/report_txt.erb
|
158
162
|
- lib/log_sense/version.rb
|
159
163
|
- log_sense.gemspec
|
160
164
|
- sample_logs/safety-critical_org.log
|
161
165
|
- sample_logs/spmbook_com.log
|
162
|
-
|
166
|
+
- screenshots/apache-screenshot.png
|
167
|
+
- screenshots/rails-screenshot.png
|
168
|
+
homepage: https://github.com/shair-tech/log_sense/
|
163
169
|
licenses:
|
164
170
|
- MIT
|
165
171
|
metadata:
|
166
172
|
allowed_push_host: https://rubygems.org/
|
167
|
-
homepage_uri: https://github.com/shair-tech/log_sense/
|
173
|
+
homepage_uri: https://github.com/shair-tech/log_sense/
|
168
174
|
source_code_uri: https://github.com/shair-tech/log_sense/
|
169
175
|
changelog_uri: https://github.com/shair-tech/log_sense/blob/main/CHANGELOG.org
|
170
176
|
post_install_message:
|
@@ -1,147 +0,0 @@
|
|
1
|
-
module LogSense
|
2
|
-
module ApacheDataCruncher
|
3
|
-
#
|
4
|
-
# take a sqlite3 database and analyze data
|
5
|
-
#
|
6
|
-
# @ variables are automatically put in the returned data
|
7
|
-
#
|
8
|
-
|
9
|
-
def self.crunch db, options = { limit: 900 }
|
10
|
-
first_day_s = db.execute "SELECT datetime from LogLine order by datetime limit 1"
|
11
|
-
last_day_s = db.execute "SELECT datetime from LogLine order by datetime desc limit 1"
|
12
|
-
|
13
|
-
# make first and last day into dates or nil
|
14
|
-
@first_day = first_day_s&.first&.first ? Date.parse(first_day_s[0][0]) : nil
|
15
|
-
@last_day = last_day_s&.first&.first ? Date.parse(last_day_s[0][0]) : nil
|
16
|
-
|
17
|
-
@total_days = 0
|
18
|
-
@total_days = (@last_day - @first_day).to_i if @first_day && @last_day
|
19
|
-
|
20
|
-
@source_files = db.execute 'SELECT distinct(source_file) from LogLine'
|
21
|
-
|
22
|
-
@log_size = db.execute 'SELECT count(datetime) from LogLine'
|
23
|
-
@log_size = @log_size[0][0]
|
24
|
-
|
25
|
-
@selfpolls_size = db.execute "SELECT count(datetime) from LogLine where ip == '::1'"
|
26
|
-
@selfpolls_size = @selfpolls_size[0][0]
|
27
|
-
|
28
|
-
@crawlers_size = db.execute 'SELECT count(datetime) from LogLine where bot == 1'
|
29
|
-
@crawlers_size = @crawlers_size[0][0]
|
30
|
-
|
31
|
-
@first_day_requested = options[:from_date]
|
32
|
-
@last_day_requested = options[:to_date]
|
33
|
-
|
34
|
-
@first_day_in_analysis = date_intersect options[:from_date], @first_day, :max
|
35
|
-
@last_day_in_analysis = date_intersect options[:to_date], @last_day, :min
|
36
|
-
|
37
|
-
@total_days_in_analysis = 0
|
38
|
-
if @first_day_in_analysis && @last_day_in_analysis
|
39
|
-
@total_days_in_analysis = (@last_day_in_analysis - @first_day_in_analysis).to_i
|
40
|
-
end
|
41
|
-
|
42
|
-
#
|
43
|
-
# generate the where clause corresponding to the command line options to filter data
|
44
|
-
#
|
45
|
-
filter = [
|
46
|
-
(options[:from_date] ? "date(datetime) >= '#{options[:from_date]}'" : nil),
|
47
|
-
(options[:to_date] ? "date(datetime) <= '#{options[:to_date]}'" : nil),
|
48
|
-
(options[:only_crawlers] ? 'bot == 1' : nil),
|
49
|
-
(options[:ignore_crawlers] ? 'bot == 0' : nil),
|
50
|
-
(options[:no_selfpolls] ? "ip != '::1'" : nil),
|
51
|
-
'true'
|
52
|
-
].compact.join " and "
|
53
|
-
|
54
|
-
mega = 1024 * 1024
|
55
|
-
giga = mega * 1024
|
56
|
-
tera = giga * 1024
|
57
|
-
|
58
|
-
# in alternative to sum(size)
|
59
|
-
human_readable_size = <<-EOS
|
60
|
-
CASE
|
61
|
-
WHEN sum(size) < 1024 THEN sum(size) || ' B'
|
62
|
-
WHEN sum(size) >= 1024 AND sum(size) < (#{mega}) THEN ROUND((CAST(sum(size) AS REAL) / 1024), 2) || ' KB'
|
63
|
-
WHEN sum(size) >= (#{mega}) AND sum(size) < (#{giga}) THEN ROUND((CAST(sum(size) AS REAL) / (#{mega})), 2) || ' MB'
|
64
|
-
WHEN sum(size) >= (#{giga}) AND sum(size) < (#{tera}) THEN ROUND((CAST(sum(size) AS REAL) / (#{giga})), 2) || ' GB'
|
65
|
-
WHEN sum(size) >= (#{tera}) THEN ROUND((CAST(sum(size) AS REAL) / (#{tera})), 2) || ' TB'
|
66
|
-
END AS size
|
67
|
-
EOS
|
68
|
-
|
69
|
-
human_readable_day = <<-EOS
|
70
|
-
case cast (strftime('%w', datetime) as integer)
|
71
|
-
when 0 then 'Sunday'
|
72
|
-
when 1 then 'Monday'
|
73
|
-
when 2 then 'Tuesday'
|
74
|
-
when 3 then 'Wednesday'
|
75
|
-
when 4 then 'Thursday'
|
76
|
-
when 5 then 'Friday'
|
77
|
-
else 'Saturday'
|
78
|
-
end as dow
|
79
|
-
EOS
|
80
|
-
|
81
|
-
@total_hits = db.execute "SELECT count(datetime) from LogLine where #{filter}"
|
82
|
-
@total_hits = @total_hits[0][0]
|
83
|
-
|
84
|
-
@total_unique_visits = db.execute "SELECT count(distinct(unique_visitor)) from LogLine where #{filter}"
|
85
|
-
@total_unique_visits = @total_unique_visits[0][0]
|
86
|
-
|
87
|
-
@total_size = db.execute "SELECT #{human_readable_size} from LogLine where #{filter}"
|
88
|
-
@total_size = @total_size[0][0]
|
89
|
-
|
90
|
-
@daily_distribution = db.execute "SELECT date(datetime), #{human_readable_day}, count(datetime), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by date(datetime)"
|
91
|
-
@time_distribution = db.execute "SELECT strftime('%H', datetime), count(datetime), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by strftime('%H', datetime)"
|
92
|
-
|
93
|
-
good_statuses = "(status like '2%' or status like '3%')"
|
94
|
-
bad_statuses = "(status like '4%' or status like '5%')"
|
95
|
-
html_page = "(extension like '.htm%')"
|
96
|
-
non_html_page = "(extension not like '.htm%')"
|
97
|
-
|
98
|
-
@most_requested_pages = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), #{human_readable_size}, status from LogLine where #{good_statuses} and #{html_page} and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
|
99
|
-
@most_requested_resources = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), #{human_readable_size}, status from LogLine where #{good_statuses} and #{non_html_page} and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
|
100
|
-
|
101
|
-
@missed_pages = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), status from LogLine where #{bad_statuses} and #{html_page} and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
|
102
|
-
@missed_resources = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), status from LogLine where #{bad_statuses} and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
|
103
|
-
|
104
|
-
@missed_pages_by_ip = db.execute "SELECT ip, path, status from LogLine where #{bad_statuses} and #{html_page} and #{filter} limit #{options[:limit]}"
|
105
|
-
@missed_resources_by_ip = db.execute "SELECT ip, path, status from LogLine where #{bad_statuses} and #{filter} limit #{options[:limit]}"
|
106
|
-
|
107
|
-
@statuses = db.execute "SELECT status, count(status) from LogLine where #{filter} group by status order by status"
|
108
|
-
|
109
|
-
@by_day_4xx = db.execute "SELECT date(datetime), count(datetime) from LogLine where substr(status, 1,1) == '4' and #{filter} group by date(datetime)"
|
110
|
-
@by_day_3xx = db.execute "SELECT date(datetime), count(datetime) from LogLine where substr(status, 1,1) == '3' and #{filter} group by date(datetime)"
|
111
|
-
@by_day_2xx = db.execute "SELECT date(datetime), count(datetime) from LogLine where substr(status, 1,1) == '2' and #{filter} group by date(datetime)"
|
112
|
-
|
113
|
-
@statuses_by_day = (@by_day_2xx + @by_day_3xx + @by_day_4xx).group_by { |x| x[0] }.to_a.map { |x|
|
114
|
-
[x[0], x[1].map { |y| y[1] }].flatten
|
115
|
-
}
|
116
|
-
|
117
|
-
@browsers = db.execute "SELECT browser, count(browser), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by browser order by count(browser) desc"
|
118
|
-
@platforms = db.execute "SELECT platform, count(platform), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by platform order by count(platform) desc"
|
119
|
-
|
120
|
-
@combined_platforms = db.execute "SELECT browser, platform, ip, count(datetime), #{human_readable_size} from LogLine where #{filter} group by browser, platform, ip order by count(datetime) desc limit #{options[:limit]}"
|
121
|
-
|
122
|
-
@referers = db.execute "SELECT referer, count(referer), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by referer order by count(referer) desc limit #{options[:limit]}"
|
123
|
-
|
124
|
-
@ips = db.execute "SELECT ip, count(ip), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by ip order by count(ip) desc limit #{options[:limit]}"
|
125
|
-
|
126
|
-
@streaks = db.execute 'SELECT ip, substr(datetime, 1, 10), path from LogLine order by ip, datetime'
|
127
|
-
data = {}
|
128
|
-
|
129
|
-
instance_variables.each do |variable|
|
130
|
-
var_as_symbol = variable.to_s[1..].to_sym
|
131
|
-
data[var_as_symbol] = instance_variable_get(variable)
|
132
|
-
end
|
133
|
-
|
134
|
-
data
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.date_intersect(date1, date2, method)
|
138
|
-
if date1 && date2
|
139
|
-
[date1, date2].send(method)
|
140
|
-
elsif date1
|
141
|
-
date1
|
142
|
-
else
|
143
|
-
date2
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
module LogSense
|
2
|
-
module RailsDataCruncher
|
3
|
-
|
4
|
-
#
|
5
|
-
# take a sqlite3 database and analyze data
|
6
|
-
#
|
7
|
-
# @ variables are automatically put in the returned data
|
8
|
-
#
|
9
|
-
|
10
|
-
def self.crunch db, options = { limit: 900 }
|
11
|
-
first_day_s = db.execute "SELECT started_at from Event where started_at not NULL order by started_at limit 1"
|
12
|
-
# we could use ended_at to cover the full activity period, but I prefer started_at
|
13
|
-
# with the meaning that the monitor event initiation
|
14
|
-
last_day_s = db.execute "SELECT started_at from Event order by started_at desc limit 1"
|
15
|
-
|
16
|
-
# make first and last day into dates or nil
|
17
|
-
# TODO: bug possible value here: [[nil]], which is not empty
|
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
|
-
|
21
|
-
@total_days = 0
|
22
|
-
@total_days = (@last_day - @first_day).to_i if @first_day && @last_day
|
23
|
-
|
24
|
-
# TODO should also look into Error
|
25
|
-
@source_files = db.execute "SELECT distinct(source_file) from Event"
|
26
|
-
|
27
|
-
@log_size = db.execute "SELECT count(started_at) from Event"
|
28
|
-
@log_size = @log_size[0][0]
|
29
|
-
|
30
|
-
# TODO: I should make the names of events/size/etc uniform betweeen Apache and Rails Logs
|
31
|
-
# SAME AS ABOVE
|
32
|
-
@total_hits = @log_size
|
33
|
-
|
34
|
-
# SAME AS ABOVE (but log_size is wrong in the case of Rails
|
35
|
-
# logs, since an event takes more than one line)
|
36
|
-
@events = db.execute "SELECT count(started_at) from Event"
|
37
|
-
@events = @events[0][0]
|
38
|
-
|
39
|
-
@first_day_requested = options[:from_date]
|
40
|
-
@last_day_requested = options[:to_date]
|
41
|
-
|
42
|
-
@first_day_in_analysis = date_intersect options[:from_date], @first_day, :max
|
43
|
-
@last_day_in_analysis = date_intersect options[:to_date], @last_day, :min
|
44
|
-
|
45
|
-
@total_days_in_analysis = 0
|
46
|
-
if @first_day_in_analysis and @last_day_in_analysis
|
47
|
-
@total_days_in_analysis = (@last_day_in_analysis - @first_day_in_analysis).to_i
|
48
|
-
end
|
49
|
-
|
50
|
-
#
|
51
|
-
# generate the where clause corresponding to the command line options to filter data
|
52
|
-
#
|
53
|
-
filter = [
|
54
|
-
(options[:from_date] ? "date(started_at) >= '#{options[:from_date]}'" : nil),
|
55
|
-
(options[:to_date] ? "date(started_at) <= '#{options[:to_date]}'" : nil),
|
56
|
-
"true"
|
57
|
-
].compact.join " and "
|
58
|
-
|
59
|
-
mega = 1024 * 1024
|
60
|
-
giga = mega * 1024
|
61
|
-
tera = giga * 1024
|
62
|
-
|
63
|
-
# in alternative to sum(size)
|
64
|
-
human_readable_size = <<-EOS
|
65
|
-
CASE
|
66
|
-
WHEN sum(size) < 1024 THEN sum(size) || ' B'
|
67
|
-
WHEN sum(size) >= 1024 AND sum(size) < (#{mega}) THEN ROUND((CAST(sum(size) AS REAL) / 1024), 2) || ' KB'
|
68
|
-
WHEN sum(size) >= (#{mega}) AND sum(size) < (#{giga}) THEN ROUND((CAST(sum(size) AS REAL) / (#{mega})), 2) || ' MB'
|
69
|
-
WHEN sum(size) >= (#{giga}) AND sum(size) < (#{tera}) THEN ROUND((CAST(sum(size) AS REAL) / (#{giga})), 2) || ' GB'
|
70
|
-
WHEN sum(size) >= (#{tera}) THEN ROUND((CAST(sum(size) AS REAL) / (#{tera})), 2) || ' TB'
|
71
|
-
END AS size
|
72
|
-
EOS
|
73
|
-
|
74
|
-
human_readable_day = <<-EOS
|
75
|
-
case cast (strftime('%w', started_at) as integer)
|
76
|
-
when 0 then 'Sunday'
|
77
|
-
when 1 then 'Monday'
|
78
|
-
when 2 then 'Tuesday'
|
79
|
-
when 3 then 'Wednesday'
|
80
|
-
when 4 then 'Thursday'
|
81
|
-
when 5 then 'Friday'
|
82
|
-
else 'Saturday'
|
83
|
-
end as dow
|
84
|
-
EOS
|
85
|
-
|
86
|
-
@total_events = db.execute "SELECT count(started_at) from Event where #{filter}"
|
87
|
-
|
88
|
-
@total_unique_visits = db.execute "SELECT count(distinct(unique_visitor)) from Event where #{filter}"
|
89
|
-
@total_unique_visits = @total_unique_visits[0][0]
|
90
|
-
|
91
|
-
@daily_distribution = db.execute "SELECT date(started_at), #{human_readable_day}, count(started_at) from Event where #{filter} group by date(started_at)"
|
92
|
-
@time_distribution = db.execute "SELECT strftime('%H', started_at), count(started_at) from Event where #{filter} group by strftime('%H', started_at)"
|
93
|
-
|
94
|
-
@statuses = db.execute "SELECT status, count(status) from Event where #{filter} group by status order by status"
|
95
|
-
|
96
|
-
@by_day_5xx = db.execute "SELECT date(started_at), count(started_at) from Event where substr(status, 1,1) == '5' and #{filter} group by date(started_at)"
|
97
|
-
@by_day_4xx = db.execute "SELECT date(started_at), count(started_at) from Event where substr(status, 1,1) == '4' and #{filter} group by date(started_at)"
|
98
|
-
@by_day_3xx = db.execute "SELECT date(started_at), count(started_at) from Event where substr(status, 1,1) == '3' and #{filter} group by date(started_at)"
|
99
|
-
@by_day_2xx = db.execute "SELECT date(started_at), count(started_at) from Event where substr(status, 1,1) == '2' and #{filter} group by date(started_at)"
|
100
|
-
|
101
|
-
@statuses_by_day = (@by_day_2xx + @by_day_3xx + @by_day_4xx + @by_day_5xx).group_by { |x| x[0] }.to_a.map { |x|
|
102
|
-
[x[0], x[1].map { |y| y[1] }].flatten
|
103
|
-
}
|
104
|
-
|
105
|
-
@ips = db.execute "SELECT ip, count(ip) from Event where #{filter} group by ip order by count(ip) desc limit #{options[:limit]}"
|
106
|
-
|
107
|
-
@streaks = db.execute 'SELECT ip, substr(started_at, 1, 10), url from Event order by ip, started_at'
|
108
|
-
data = {}
|
109
|
-
|
110
|
-
@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"
|
111
|
-
|
112
|
-
@fatal = db.execute ("SELECT strftime(\"%Y-%m-%d %H:%M\", started_at), ip, url, error.description, event.log_id FROM Event JOIN Error ON event.log_id == error.log_id WHERE exit_status == 'F'") || [[]]
|
113
|
-
|
114
|
-
@internal_server_error = (db.execute "SELECT strftime(\"%Y-%m-%d %H:%M\", started_at), status, ip, url, error.description, event.log_id FROM Event JOIN Error ON event.log_id == error.log_id WHERE status is 500") || [[]]
|
115
|
-
|
116
|
-
@error = (db.execute "SELECT log_id, context, description, count(log_id) from Error GROUP BY description") || [[]]
|
117
|
-
|
118
|
-
data = {}
|
119
|
-
self.instance_variables.each do |variable|
|
120
|
-
var_as_symbol = variable.to_s[1..-1].to_sym
|
121
|
-
data[var_as_symbol] = eval(variable.to_s)
|
122
|
-
end
|
123
|
-
data
|
124
|
-
end
|
125
|
-
|
126
|
-
private
|
127
|
-
|
128
|
-
def self.date_intersect date1, date2, method
|
129
|
-
if date1 and date2
|
130
|
-
[date1, date2].send(method)
|
131
|
-
elsif date1
|
132
|
-
date1
|
133
|
-
else
|
134
|
-
date2
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
@@ -1,115 +0,0 @@
|
|
1
|
-
<!doctype html>
|
2
|
-
<html class="no-js" lang="en">
|
3
|
-
<head>
|
4
|
-
<title>
|
5
|
-
<%= options[:title] || "Log Sense: #{data[:filenames].empty? ? "stdin" : data[:filenames].join(", ")}" %>
|
6
|
-
</title>
|
7
|
-
|
8
|
-
<meta charset="utf-8" />
|
9
|
-
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
10
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
11
|
-
|
12
|
-
<meta name="author" content="Shair.Tech">
|
13
|
-
<meta name="description" content="Analysis of <%= data[:filenames].join(', ') %>">
|
14
|
-
|
15
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
16
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
17
|
-
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300;700&display=swap" rel="stylesheet">
|
18
|
-
|
19
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css">
|
20
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.4/dist/css/foundation.min.css">
|
21
|
-
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/zf/dt-1.11.3/datatables.min.css"/>
|
22
|
-
|
23
|
-
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
24
|
-
<script type="text/javascript" src="https://cdn.datatables.net/v/zf/dt-1.11.3/datatables.min.js"></script>
|
25
|
-
|
26
|
-
<script src="https://cdn.jsdelivr.net/npm/vega@5.21.0"></script>
|
27
|
-
<script src="https://cdn.jsdelivr.net/npm/vega-lite@5.2.0"></script>
|
28
|
-
<script src="https://cdn.jsdelivr.net/npm/vega-embed@6.20.2"></script>
|
29
|
-
|
30
|
-
<style>
|
31
|
-
<%= render "stylesheet.css" %>
|
32
|
-
</style>
|
33
|
-
</head>
|
34
|
-
|
35
|
-
<body>
|
36
|
-
<div class="off-canvas-wrapper">
|
37
|
-
<div class="off-canvas position-left" id="offCanvas" data-off-canvas>
|
38
|
-
<%= render "navigation.html.erb",
|
39
|
-
menus: Emitter::apache_report_specification.map { |x| x[:title] } %>
|
40
|
-
</div>
|
41
|
-
<div class="off-canvas-content" data-off-canvas-content>
|
42
|
-
<button id="toggle-button" type="button" data-toggle="offCanvas">
|
43
|
-
☰
|
44
|
-
</button>
|
45
|
-
|
46
|
-
<section class="main-section grid-container fluid">
|
47
|
-
<h1><%= options[:title] || "Log Sense Apache Log Report" %></h1>
|
48
|
-
|
49
|
-
<p><b>Input File(s):</b> <%= data[:filenames].empty? ? "stdin" : data[:filenames].join(", ") %></p>
|
50
|
-
|
51
|
-
<div class="grid-x grid-padding-x">
|
52
|
-
<article class="small-12 large-6 cell">
|
53
|
-
<h2 id="<%= Emitter::slugify "Summary" %>">Summary</h2>
|
54
|
-
<%= render "summary.html.erb", data: data %>
|
55
|
-
</article>
|
56
|
-
|
57
|
-
<article class="small-12 large-6 cell">
|
58
|
-
<h2 id="<%= Emitter::slugify "Summary" %>">Log Structure</h2>
|
59
|
-
<%= render "log_structure.html.erb", data: data %>
|
60
|
-
</article>
|
61
|
-
|
62
|
-
<% @reports.each_with_index do |report, index| %>
|
63
|
-
<article class="<%= report[:col] || "small-12 large-6" %> cell">
|
64
|
-
<h2 id="<%= Emitter::slugify report[:title] %>"><%= report[:title] %></h2>
|
65
|
-
|
66
|
-
<%= render "report_data.html.erb", report: report, index: index %>
|
67
|
-
<% if report[:vega_spec] %>
|
68
|
-
<div id="<%= "plot-#{index}" %>" class="plot-canvas">
|
69
|
-
</div>
|
70
|
-
<script>
|
71
|
-
plot_spec_<%= index %> = Object.assign(
|
72
|
-
<%= report[:vega_spec].to_json %>,
|
73
|
-
{ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
74
|
-
width: "container",
|
75
|
-
description: "<%= report[:title] %>",
|
76
|
-
data: {
|
77
|
-
values: data_<%= index %>
|
78
|
-
},
|
79
|
-
});
|
80
|
-
vegaEmbed('#<%= "plot-#{index}"%>', plot_spec_<%= index %>);
|
81
|
-
</script>
|
82
|
-
<% end %>
|
83
|
-
|
84
|
-
<%= render "output_table.html.erb", report: report, index: index %>
|
85
|
-
</article>
|
86
|
-
<% end %>
|
87
|
-
|
88
|
-
<article class="small-12 large-6 cell">
|
89
|
-
<h2 id="<%= Emitter::slugify "Command Invocation" %>">Command Invocation</h2>
|
90
|
-
<%= render "command_invocation.html.erb", data: data, options: options %>
|
91
|
-
</article>
|
92
|
-
|
93
|
-
<article class="small-12 large-6 cell">
|
94
|
-
<h2 id="<%= Emitter::slugify "Performance" %>">Performance</h2>
|
95
|
-
<%= render "performance.html.erb", data: data %>
|
96
|
-
</article>
|
97
|
-
</div>
|
98
|
-
</section>
|
99
|
-
</div>
|
100
|
-
</div>
|
101
|
-
|
102
|
-
<script type="text/javascript" src="js/vendor/what-input.js"></script>
|
103
|
-
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
|
104
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.4/dist/js/foundation.min.js" crossorigin="anonymous"></script>
|
105
|
-
<script>
|
106
|
-
$(document).foundation();
|
107
|
-
|
108
|
-
$(document).ready(function () {
|
109
|
-
$('.data-table').each(function () {
|
110
|
-
$(this).DataTable();
|
111
|
-
});
|
112
|
-
});
|
113
|
-
</script>
|
114
|
-
</body>
|
115
|
-
</html>
|
@@ -1,22 +0,0 @@
|
|
1
|
-
* Rails Log Analysis
|
2
|
-
|
3
|
-
<%= render "warning.txt.erb" %>
|
4
|
-
|
5
|
-
** Summary
|
6
|
-
|
7
|
-
<%= render "summary.txt.erb", data: data %>
|
8
|
-
|
9
|
-
<% @reports.reject { |x| x[:report] == :html }.each do |report| %>
|
10
|
-
** <%= report[:title] %>
|
11
|
-
|
12
|
-
<%= render "output_table.txt.erb", report: report, data: data %>
|
13
|
-
<% end %>
|
14
|
-
|
15
|
-
** Command Invocation
|
16
|
-
|
17
|
-
<%= render 'command_invocation.txt.erb', data: data %>
|
18
|
-
|
19
|
-
** Performance
|
20
|
-
|
21
|
-
<%= render 'performance.txt.erb', data: data %>
|
22
|
-
|