log_sense 1.5.2 → 1.6.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 +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
|
-
|