apache_log_report 1.1.2 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07ad311b79b7ad4888250d690af4857cc620b07a4fdc7206bbc40adf5b2fd00b
4
- data.tar.gz: 1ed81f7bd6324af49a24ad6d8abe9add71710813c051537f254f80d9c9ac6739
3
+ metadata.gz: 742584032338664834cd5c1b669289980e083e68d172827f6517ce040543aa4d
4
+ data.tar.gz: 1bf08e255feb434ded62589d5c70ea5a6eb83dc1f6a69e60a31cb520eea6b48f
5
5
  SHA512:
6
- metadata.gz: db323468d20cb50f870ac0dbe62cbfd42feb10e69da02d9d892dd206bcf9e5d1c3c5ad91a542f4f888bc04a9a6df3514ba186d67cc60b32e7647df6ff183e5d5
7
- data.tar.gz: cf33e4665e31a6f18fc346c80b6f8b7cae8456b0c9dbf2d8c658a383b3711e754f795d08963d5c3c5109bd34360c5bc00bb17c93b15e4c551a7a9a1b5f619023
6
+ metadata.gz: 955dbe90321c68f5694aaa892cae97926172ca47b684a0eee1b9f7644dc26a13f853b3b3d20e35cf06872b29db0c06bc16c4c86e69c740ea86fe8768ae92b2a1
7
+ data.tar.gz: e6d9ebc88435442bfb77faa3cb2eccb94a355e9ca7af44548a7b443531c9fae923e41f5d97201044f71414f2d9894162b593cd15170e255030ab49bd9992e3f0
data/README.org CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  * Introduction
6
6
 
7
+ ApacheLogReport is an Apache log analyzer.
8
+
7
9
  * Installation
8
10
 
9
11
  * Usage
@@ -14,8 +16,12 @@ See the [[file:CHANGELOG.org][CHANGELOG]] file.
14
16
 
15
17
  * Todo
16
18
 
19
+ ** TODO Referers should only include the hostname?
17
20
  ** TODO Graphs in HTML output
18
21
  ** TODO Countries
22
+ ** TODO Light and Dark Theme
23
+ ** TODO Embed CSS
24
+ ** TODO Declare datatypes in table outputs, so that we can format data
19
25
 
20
26
  * Compatibility
21
27
 
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["Adolfo Villafiorita"]
7
7
  spec.email = ["adolfo.villafiorita@ict4g.net"]
8
8
 
9
- spec.summary = %q{Generate a request report in OrgMode format from an Apache log file.}
10
- spec.description = %q{Generate a request report in OrgMode format from an Apache log file.}
9
+ spec.summary = %q{Generate analytics from an Apache log file.}
10
+ spec.description = %q{Generate requests reports in HTML, OrgMode, and SQLite format from an Apache log file.}
11
11
  spec.homepage = "https://www.ict4g.net/gitea/adolfo/apache_log_report"
12
12
  spec.license = "MIT"
13
13
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
@@ -1,17 +1,41 @@
1
+
1
2
  module ApacheLogReport
2
3
  module DataCruncher
3
4
 
4
5
  #
5
6
  # take a sqlite3 database and analyze data
6
7
  #
8
+ # @ variables are automatically put in the returned data
9
+ #
7
10
 
8
11
  def self.crunch db, options = {}
9
- @first_day = db.execute "SELECT datetime from LogLine order by datetime limit 1"
10
- @last_day = db.execute "SELECT datetime from LogLine order by datetime desc limit 1"
12
+ first_day_s = db.execute "SELECT datetime from LogLine order by datetime limit 1"
13
+ last_day_s = db.execute "SELECT datetime from LogLine order by datetime desc limit 1"
14
+
15
+ # make first and last day into dates or nil
16
+ @first_day = first_day_s.empty? ? nil : Date.parse(first_day_s[0][0])
17
+ @last_day = last_day_s.empty? ? nil : Date.parse(last_day_s[0][0])
18
+
19
+ @total_days = 0
20
+ if @first_day and @last_day
21
+ @total_days = (@last_day - @first_day).to_i
22
+ end
23
+
11
24
  @log_size = db.execute "SELECT count(datetime) from LogLine"
12
25
  @crawlers_size = db.execute "SELECT count(datetime) from LogLine where bot == 1"
13
26
  @selfpolls_size = db.execute "SELECT count(datetime) from LogLine where ip == '::1'"
14
27
 
28
+ @first_day_requested = options[:from_date]
29
+ @last_day_requested = options[:to_date]
30
+
31
+ @first_day_in_analysis = date_intersect options[:from_date], @first_day, :max
32
+ @last_day_in_analysis = date_intersect options[:to_date], @last_day, :min
33
+
34
+ @total_days_in_analysis = 0
35
+ if @first_day_in_analysis and @last_day_in_analysis
36
+ @total_days_in_analysis = (@last_day_in_analysis - @first_day_in_analysis).to_i
37
+ end
38
+
15
39
  #
16
40
  # generate the where clause corresponding to the command line options to filter data
17
41
  #
@@ -39,12 +63,23 @@ module ApacheLogReport
39
63
  END AS size
40
64
  EOS
41
65
 
66
+ human_readable_day = <<-EOS
67
+ case cast (strftime('%w', datetime) as integer)
68
+ when 0 then 'Sunday'
69
+ when 1 then 'Monday'
70
+ when 2 then 'Tuesday'
71
+ when 3 then 'Wednesday'
72
+ when 4 then 'Thursday'
73
+ when 5 then 'Friday'
74
+ else 'Saturday'
75
+ end as dow
76
+ EOS
77
+
42
78
  @total_hits = db.execute "SELECT count(datetime) from LogLine where #{filter}"
43
79
  @total_unique_visitors = db.execute "SELECT count(distinct(unique_visitor)) from LogLine where #{filter}"
44
80
  @total_size = db.execute "SELECT #{human_readable_size} from LogLine where #{filter}"
45
- @total_days = (Date.parse(@last_day[0][0]) - Date.parse(@first_day[0][0])).to_i
46
81
 
47
- @daily_distribution = db.execute "SELECT date(datetime), count(datetime), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by date(datetime)"
82
+ @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)"
48
83
  @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)"
49
84
  @most_requested_pages = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where extension == '.html' and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
50
85
  @most_requested_resources = db.execute "SELECT path, count(path), count(distinct(unique_visitor)), #{human_readable_size} from LogLine where #{filter} group by path order by count(path) desc limit #{options[:limit]}"
@@ -80,7 +115,20 @@ module ApacheLogReport
80
115
  end
81
116
  data
82
117
  end
83
- end
84
118
 
119
+ private
120
+
121
+ def self.date_intersect date1, date2, method
122
+ if date1 and date2
123
+ [date1, date2].send(method)
124
+ elsif date1
125
+ date1
126
+ else
127
+ date2
128
+ end
129
+ end
130
+
131
+
132
+ end
85
133
  end
86
134
 
@@ -18,11 +18,11 @@ module ApacheLogReport
18
18
  args[:limit] = n
19
19
  end
20
20
 
21
- opts.on("-bDATE", "--begin=DATE", DateTime, "Consider entries after or on DATE") do |n|
21
+ opts.on("-bDATE", "--begin=DATE", Date, "Consider entries after or on DATE") do |n|
22
22
  args[:from_date] = n
23
23
  end
24
24
 
25
- opts.on("-eDATE", "--end=DATE", DateTime, "Consider entries before or on DATE") do |n|
25
+ opts.on("-eDATE", "--end=DATE", Date, "Consider entries before or on DATE") do |n|
26
26
  args[:to_date] = n
27
27
  end
28
28
 
@@ -4,7 +4,7 @@ def slugify string
4
4
  end
5
5
  %>
6
6
 
7
- <table id="<%= slugify(title || "") %>" class="<%= slugify(title || "") %>">
7
+ <table id="<%= slugify(title || "") %>" class="table <%= slugify(title || "") %>">
8
8
  <thead>
9
9
  <tr>
10
10
  <% header.each do |heading| %>
@@ -4,194 +4,271 @@
4
4
  <meta name="author" content="apache_log_report">
5
5
 
6
6
  <link rel="stylesheet" href="alr-styles.css"></style>
7
+
8
+ <link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
9
+ <link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-exp.min.css">
10
+ <link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre-icons.min.css">
7
11
  </head>
8
12
 
9
13
  <body>
10
- <section>
11
- <h1>Apache Log Analysis: <%= data[:log_file] || "stdin" %></h1>
12
-
13
- <article>
14
- <h2>Summary</h2>
15
-
16
- <table class="pure-table summary">
17
- <tr>
18
- <th class="hits">Hits</th>
19
- <td class="hits"><%= data[:total_hits][0][0] %></td>
20
- </tr>
21
- <tr>
22
- <th class="unique-visitors">Unique Visitors</th>
23
- <td class="unique-visitors"><%= data[:total_unique_visitors][0][0] %></td>
24
- </tr>
25
- <tr>
26
- <th class="tx">Tx</th>
27
- <td class="tx"><%= data[:total_size][0][0] %></td>
28
- </tr>
29
- <tr>
30
- <th class="period">Period</th>
31
- <td class="period">
32
- <%= data[:first_day][0][0] %>
33
- --
34
- <%= data[:last_day][0][0] %>
35
- </td>
36
- </tr>
37
- <tr>
38
- <th class="days">Days </th>
39
- <td class="days"><%= data[:total_days] %></td>
40
- </tr>
41
- </table>
42
- </article>
43
-
44
- <% @reports = [
45
- { title: "Daily Distribution", header: ["Day", "Hits", "Visits", "Size"], rows: data[:daily_distribution] },
46
- { title: "Time Distribution", header: ["Hour", "Hits", "Visits", "Size"], rows: data[:time_distribution] },
47
- { title: "Most Requested Pages", header: ["Path", "Hits", "Visits", "Size"], rows: data[:most_requested_pages] },
48
- { title: "Most Requested Resources", header: ["Path", "Hits", "Visits", "Size"], rows: data[:most_requested_resources] },
49
- { title: "404 on HTML Files", header: ["Path", "Hits", "Visitors"], rows: data[:missed_pages] },
50
- { title: "404 on other Resources", header: ["Path", "Hits", "Visitors"], rows: data[:missed_resources] },
51
- { title: "Attacks", header: ["Path", "Hits", "Visitors"], rows: data[:attacks] },
52
- { title: "Statuses", header: ["Status", "Count"], rows: data[:statuses] },
53
- { title: "Daily Statuses", header: ["Status", "2xx", "3xx", "4xx"], rows: data[:statuses_by_day] },
54
- { title: "Browsers", header: ["Browser", "Hits", "Visitors", "Size"], rows: data[:browsers] },
55
- { title: "Platforms", header: ["Platform", "Hits", "Visitors", "Size"], rows: data[:platforms] },
56
- { title: "IPs", header: ["IPs", "Hits", "Visitors", "Size"], rows: data[:ips] },
57
- { title: "Referers", header: ["Referers", "Hits", "Visitors", "Size"], rows: data[:referers] },
58
- ]
59
- %>
60
- <% @reports.each do |report| %>
61
- <article>
62
- <h2><%= report[:title] %></h2>
63
- <%= render "output_table", report %>
64
- </article>
65
- <% end %>
66
-
67
- <article>
68
- <h2>Streaks</h2>
69
-
70
- <table class="streaks">
71
- <thead>
72
- <tr>
73
- <th>IP</th>
74
- <th>Day</th>
75
- <th>URL</th>
76
- </tr>
77
- </thead>
78
- <tbody>
79
- <% data[:streaks].group_by(&:first).each do |ip, date_urls| %>
14
+ <div class="container">
15
+ <nav>
16
+ <ul class="nav">
17
+ <li class="nav-item active">
18
+ <a href="#">Navigation</a>
19
+ <ul class="nav">
20
+ <% [ "Summary",
21
+ "Log Structure",
22
+ "Daily Distribution",
23
+ "Time Distribution",
24
+ "Most Requested Pages",
25
+ "Most Requested Resources",
26
+ "404 on HTML Files",
27
+ "404 on other Resources",
28
+ "Attacks",
29
+ "Statuses",
30
+ "Daily Statuses",
31
+ "Browsers",
32
+ "Platforms",
33
+ "Referers",
34
+ "IPs",
35
+ "Command Invocation",
36
+ "Performance"
37
+ ].each do |item| %>
38
+ <li class="nav-item">
39
+ <a href="#<%= item.downcase.gsub(' ', '-') %>"><%= item %></a>
40
+ </li>
41
+ <% end %>
42
+ </ul>
43
+ </li>
44
+ </ul>
45
+ <p>
46
+ Generated by<br />
47
+ <a href="https://www.ict4g.net/gitea/adolfo/apache_log_report">
48
+ Apache Log Report
49
+ </a> <br />
50
+ on <%= DateTime.now.strftime("%Y-%m-%d %H:%M") %>.<br />
51
+ The lean log analyzer.
52
+ </p>
53
+ </nav>
54
+
55
+ <section>
56
+ <h1>Apache Log Analysis: <%= data[:log_file] || "stdin" %></h1>
57
+
58
+ <div class="columns">
59
+ <article class="col-6 column">
60
+ <h2 id="summary">Summary</h2>
61
+
62
+ <table class="table summary">
80
63
  <tr>
81
- <td class="ip"><%= ip %></td>
82
- <td class="streaks">
83
- <% date_urls.group_by(&:first).each do |date, urls| %>
84
- <% urls.each do |url| %>
85
- <b><%= url[1] %>:</b> <%= url[2] %> <br />
86
- <% end %>
87
- <% end %>
64
+ <th>Input file</th>
65
+ <td><b><%= (data[:log_file] || "stdin") %></b></td>
66
+ </tr>
67
+ <tr>
68
+ <th class="period">Period Analyzed</th>
69
+ <td class="period">
70
+ <%= data[:first_day_in_analysis] %>
71
+ --
72
+ <%= data[:last_day_in_analysis] %>
88
73
  </td>
89
74
  </tr>
90
- <% end %>
91
- </tbody>
92
- </table>
93
- </article>
94
-
95
- <article>
96
- <h2>Command Invocation and Performance</h2>
97
-
98
- <h3>Command Invocation</h3>
99
-
100
- <code>
101
- </code>
102
-
103
- <table class="pure-table command-invocation">
104
- <tbody>
105
- <tr>
106
- <th>CLI Command</th>
107
- <td><pre><%= data[:command] %></pre></td>
108
- </tr>
109
- <tr>
110
- <th>Input file</th>
111
- <td><code><%= (data[:log_file] || "stdin") %></code></td>
112
- </tr>
113
- <tr>
114
- <th>Ignore crawlers</th>
115
- <td><code><%= options[:ignore_crawlers] %></code></td></tr>
116
- <tr>
117
- <th>Only crawlers</th>
118
- <td><code><%= options[:only_crawlers] %></code></td>
119
- </tr>
120
- <tr>
121
- <th>No selfpoll</th>
122
- <td><code><%= options[:no_selfpoll] %></code></td>
123
- </tr>
124
- <tr>
125
- <th>Filter by date</th>
126
- <td>
127
- <code><%= (options[:from_date] != nil or options[:to_date] != nil) %></code>
128
- </td>
129
- </tr>
130
- <tr>
131
- <th>Prefix</th>
132
- <td><code><%= @prefix %></code></td>
133
- </tr>
134
- <tr>
135
- <th>Suffix</th>
136
- <td><code><%= @suffix %></code></td>
137
- </tr>
138
- </tbody>
139
- </table>
140
-
141
- <h3> Log Structure</h3>
142
-
143
- <table class="pure-table log-structure">
144
- <tbody>
145
- <tr>
146
- <th>Log size</th>
147
- <td><%= data[:log_size][0][0] %></td>
148
- </tr>
149
- <tr>
150
- <th>Self poll entries</th>
151
- <td><%= data[:selfpolls_size][0][0] %></td>
152
- </tr>
153
- <tr>
154
- <th>Crawlers</th>
155
- <td><%= data[:crawlers_size][0][0] %></td>
156
- </tr>
157
- <tr>
158
- <th>Entries considered</th>
159
- <td><%= data[:total_hits][0][0] %></td>
160
- </tr>
161
- </tbody>
162
- </table>
163
-
164
- <h3> Performance</h3>
165
-
166
- <table class="pure-table performance">
167
- <tbody>
168
- <tr>
169
- <th>Analysis started at</th>
170
- <td><%= data[:started_at].to_s %></td>
171
- </tr>
172
- <tr>
173
- <th>Analysis ended at</th>
174
- <td><%= data[:ended_at].to_s %></td>
175
- </tr>
176
- <tr>
177
- <th>Duration (sec)</th>
178
- <td><%= "%.1f" % data[:duration] %></td>
179
- </tr>
180
- <tr>
181
- <th>Duration (min)</th>
182
- <td><%= "%d" % (data[:duration] / 60 ) %></td>
183
- </tr>
184
- <tr>
185
- <th>Log size</th>
186
- <td><%= data[:log_size][0][0] %></td>
187
- </tr>
188
- <tr>
189
- <th>Lines/sec</th>
190
- <td><%= "%.2f" % (data[:log_size][0][0] / data[:duration]) %></td></tr>
191
- </tbody>
192
- </table>
193
- </article>
194
- </section>
75
+ <tr>
76
+ <th class="days">Days </th>
77
+ <td class="days"><%= data[:total_days_in_analysis] %></td>
78
+ </tr>
79
+ <tr>
80
+ <th class="hits">Hits</th>
81
+ <td class="hits"><%= data[:total_hits][0][0] %></td>
82
+ </tr>
83
+ <tr>
84
+ <th class="unique-visitors">Unique Visitors</th>
85
+ <td class="unique-visitors"><%= data[:total_unique_visitors][0][0] %></td>
86
+ </tr>
87
+ <tr>
88
+ <th class="tx">Tx</th>
89
+ <td class="tx"><%= data[:total_size][0][0] %></td>
90
+ </tr>
91
+ </table>
92
+ </article>
93
+ <article class="column col-6">
94
+ <h2 id="log-structure">Log Structure</h2>
95
+
96
+ <table class="table log-structure">
97
+ <tbody>
98
+ <tr>
99
+ <th>Input file</th>
100
+ <td><b><%= (data[:log_file] || "stdin") %></b></td>
101
+ </tr>
102
+ <tr>
103
+ <th>Period in Log</th>
104
+ <td><%= data[:first_day] %> -- <%= data[:last_day] %></td>
105
+ </tr>
106
+ <tr>
107
+ <th>Total days</th>
108
+ <td><%= data[:total_days] %></td>
109
+ </tr>
110
+ <tr>
111
+ <th>Log size</th>
112
+ <td><%= data[:log_size][0][0] %></td>
113
+ </tr>
114
+ <tr>
115
+ <th>Self poll entries</th>
116
+ <td><%= data[:selfpolls_size][0][0] %></td>
117
+ </tr>
118
+ <tr>
119
+ <th>Crawlers</th>
120
+ <td><%= data[:crawlers_size][0][0] %></td>
121
+ </tr>
122
+ <tr>
123
+ <th>Entries considered</th>
124
+ <td><%= data[:total_hits][0][0] %></td>
125
+ </tr>
126
+ </tbody>
127
+ </table>
128
+ </article>
129
+ </div>
130
+
131
+ <% @reports = [
132
+ { title: "Daily Distribution", header: ["Day", "DOW", "Hits", "Visits", "Size"], rows: data[:daily_distribution] },
133
+ { title: "Time Distribution", header: ["Hour", "Hits", "Visits", "Size"], rows: data[:time_distribution] },
134
+ { title: "Most Requested Pages", header: ["Path", "Hits", "Visits", "Size"], rows: data[:most_requested_pages] },
135
+ { title: "Most Requested Resources", header: ["Path", "Hits", "Visits", "Size"], rows: data[:most_requested_resources] },
136
+ { title: "404 on HTML Files", header: ["Path", "Hits", "Visitors"], rows: data[:missed_pages] },
137
+ { title: "404 on other Resources", header: ["Path", "Hits", "Visitors"], rows: data[:missed_resources] },
138
+ { title: "Attacks", header: ["Path", "Hits", "Visitors"], rows: data[:attacks] },
139
+ { },
140
+ { title: "Statuses", header: ["Status", "Count"], rows: data[:statuses] },
141
+ { title: "Daily Statuses", header: ["Status", "2xx", "3xx", "4xx"], rows: data[:statuses_by_day] },
142
+ { title: "Browsers", header: ["Browser", "Hits", "Visitors", "Size"], rows: data[:browsers] },
143
+ { title: "Platforms", header: ["Platform", "Hits", "Visitors", "Size"], rows: data[:platforms] },
144
+ { title: "Referers", header: ["Referers", "Hits", "Visitors", "Size"], rows: data[:referers], col: "col-12" },
145
+ { title: "IPs", header: ["IPs", "Hits", "Visitors", "Size"], rows: data[:ips] },
146
+ { },
147
+ ]
148
+ %>
149
+ <div class="columns">
150
+ <% @reports.each do |report| %>
151
+ <div class="column <%= report[:col] || "col-6" %>">
152
+ <article>
153
+ <% if report[:title] != nil %>
154
+ <h2 id="<%= report[:title].downcase.gsub(/ +/, '-') %>">
155
+ <%= report[:title] %>
156
+ </h2>
157
+ <%= render "output_table", report %>
158
+ <% end %>
159
+ </article>
160
+ </div>
161
+ <% end %>
162
+ </div>
163
+
164
+ <article>
165
+ <h2 id="streaks">Streaks</h2>
166
+
167
+ <table class="table streaks">
168
+ <thead>
169
+ <tr>
170
+ <th>IP</th>
171
+ <th>Day and URL</th>
172
+ </tr>
173
+ </thead>
174
+ <tbody>
175
+ <% data[:streaks].group_by(&:first).each do |ip, date_urls| %>
176
+ <tr>
177
+ <td class="ip"><%= ip %></td>
178
+ <td class="streaks">
179
+ <% date_urls.group_by(&:first).each do |date, urls| %>
180
+ <% urls.each do |url| %>
181
+ <b><%= url[1] %>:</b> <%= url[2] %> <br />
182
+ <% end %>
183
+ <% end %>
184
+ </td>
185
+ </tr>
186
+ <% end %>
187
+ </tbody>
188
+ </table>
189
+ </article>
190
+
191
+ <div class="columns">
192
+ <div class="column col-6">
193
+ <article>
194
+ <h2 id="command-invocation">Command Invocation</h2>
195
+
196
+ <table class="table command-invocation">
197
+ <tbody>
198
+ <tr>
199
+ <th>CLI Command</th>
200
+ <td><code><%= data[:command] %></code></td>
201
+ </tr>
202
+ <tr>
203
+ <th>Input file</th>
204
+ <td><code><%= (data[:log_file] || "stdin") %></code></td>
205
+ </tr>
206
+ <tr>
207
+ <th>Ignore crawlers</th>
208
+ <td><code><%= options[:ignore_crawlers] %></code></td></tr>
209
+ <tr>
210
+ <th>Only crawlers</th>
211
+ <td><code><%= options[:only_crawlers] %></code></td>
212
+ </tr>
213
+ <tr>
214
+ <th>No selfpoll</th>
215
+ <td><code><%= options[:no_selfpoll] %></code></td>
216
+ </tr>
217
+ <tr>
218
+ <th>Filter by date</th>
219
+ <td>
220
+ <code><%= (options[:from_date] != nil or options[:to_date] != nil) %></code>
221
+ </td>
222
+ </tr>
223
+ <tr>
224
+ <th>Prefix</th>
225
+ <td><code><%= @prefix %></code></td>
226
+ </tr>
227
+ <tr>
228
+ <th>Suffix</th>
229
+ <td><code><%= @suffix %></code></td>
230
+ </tr>
231
+ </tbody>
232
+ </table>
233
+ </article>
234
+ </div>
235
+
236
+ <div class="column col-6">
237
+ <article>
238
+ <h2 id="performance"> Performance</h2>
239
+
240
+ <table class="table performance">
241
+ <tbody>
242
+ <tr>
243
+ <th>Analysis started at</th>
244
+ <td><%= data[:started_at].to_s %></td>
245
+ </tr>
246
+ <tr>
247
+ <th>Analysis ended at</th>
248
+ <td><%= data[:ended_at].to_s %></td>
249
+ </tr>
250
+ <tr>
251
+ <th>Duration (sec)</th>
252
+ <td><%= "%.1f" % data[:duration] %></td>
253
+ </tr>
254
+ <tr>
255
+ <th>Duration (min)</th>
256
+ <td><%= "%d" % (data[:duration] / 60 ) %></td>
257
+ </tr>
258
+ <tr>
259
+ <th>Log size</th>
260
+ <td><%= data[:log_size][0][0] %></td>
261
+ </tr>
262
+ <tr>
263
+ <th>Lines/sec</th>
264
+ <td><%= "%.2f" % (data[:log_size][0][0] / data[:duration]) %></td></tr>
265
+ </tbody>
266
+ </table>
267
+ </article>
268
+ </div>
269
+ </div>
270
+ </section>
271
+ </div>
195
272
  </body>
196
273
  </html>
197
274
 
@@ -10,7 +10,11 @@
10
10
  | Hits | <%= "%10d" % data[:total_hits][0][0] %> |
11
11
  | Unique Visitors | <%= "%10d" % data[:total_unique_visitors][0][0] %> |
12
12
  | Tx | <%= "%10s" % data[:total_size][0][0] %> |
13
- | Days | <%= "%10d" % data[:total_days][0][0] %> |
13
+ | Logged Period | <%= data[:first_day] %> -- <%= data[:last_day] %> |
14
+ | Days | <%= "%10d" % data[:total_days] %> |
15
+ | Period Requested | <%= data[:first_day_requested] %> -- <%= data[:last_day_requested] %> |
16
+ | Period Analyzed | <%= data[:first_day_in_analysis] %> -- <%= data[:last_day_in_analysis] %> |
17
+ | Days in Analysis | <%= data[:total_days_in_analysis] %> |
14
18
 
15
19
  * Daily Distribution
16
20
 
@@ -1,3 +1,3 @@
1
1
  module ApacheLogReport
2
- VERSION = "1.1.2"
2
+ VERSION = "1.1.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apache_log_report
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adolfo Villafiorita
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-31 00:00:00.000000000 Z
11
+ date: 2021-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: apache_log-parser
@@ -66,7 +66,8 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: Generate a request report in OrgMode format from an Apache log file.
69
+ description: Generate requests reports in HTML, OrgMode, and SQLite format from an
70
+ Apache log file.
70
71
  email:
71
72
  - adolfo.villafiorita@ict4g.net
72
73
  executables:
@@ -121,5 +122,5 @@ requirements: []
121
122
  rubygems_version: 3.2.22
122
123
  signing_key:
123
124
  specification_version: 4
124
- summary: Generate a request report in OrgMode format from an Apache log file.
125
+ summary: Generate analytics from an Apache log file.
125
126
  test_files: []