log_sense 1.3.2 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6498507bb6ae7e6ba5505609421154358790f095bd9cfe5ab912920b2409f7d1
4
- data.tar.gz: 0ccb5fa005b8f1e47545bf98ce05273f07bd452d3be54c5bd1a7f124c96558d9
3
+ metadata.gz: 266e20972553f6d409814398dab832334a4c01bfa12e90c74acfdc75ee0b7c8d
4
+ data.tar.gz: 228e6bdc2d931e5190d82fc5ba66660ff6f0de0277a876746154de81a1ffe4e2
5
5
  SHA512:
6
- metadata.gz: e12760ccdfc518c7221afa337f4ac1c8a77219cd3ed65510486e3ce945e6129519aa3fe93b05845a5430b9bc52359d70591e0fcbd346e971527af1760c304e5c
7
- data.tar.gz: 8d38d8ed84287722b77f51599598b84a2257f9f86d2dd3815faf25dfb7db4ab16e68dbf737c7d005519ac5f9fe1d4b41cd896dfaf862eabb6a7dc4f033d2bb13
6
+ metadata.gz: f1454d78cfec258ff3bc69359be29178ebab4cf7ffd2869d736c29f2cffd6efe209f65be59298864bf94de30bd022a3397c91446b043c49e704b6d38ced59357
7
+ data.tar.gz: aa7239af4bb17270a23d9931194859b01a8ff50ebb9cc3c3ed37aeac1702aef413051b0381c57208dcffedd31ccbff5bd0a9485c0fe18947f540cda9f4463acd
data/CHANGELOG.org CHANGED
@@ -2,6 +2,29 @@
2
2
  #+AUTHOR: Adolfo Villafiorita
3
3
  #+STARTUP: showall
4
4
 
5
+ * 1.4.0
6
+
7
+ - [User] The Apache Log report now organizes page requests in four
8
+ tables:
9
+ - success on HTML pages
10
+ - success on other resources
11
+ - failures on HTML pages
12
+ - failures on other resources
13
+ - [User] Increased the default limit of pages in reports to 900
14
+ - [User] The return status in now included in the page and resources
15
+ reports
16
+ - [User] The "Attack" table has been removed, since the data can be
17
+ gotten from the previous tables
18
+ - [Fixed] HTML pages are those with extension ".html" and ".htm"
19
+ - [Fixed] Wrong data on summary table of the apache report has
20
+ been fixed
21
+ - [Fixed] Better JavaScript escaping to avoid log poisoning
22
+ - [Fixed] Strengthened the Apache log parser
23
+
24
+ * 1.3.3 and 1.3.4
25
+
26
+ - [Gem] Moved repository to Github and fixes to gemspec
27
+
5
28
  * 1.3.2
6
29
 
7
30
  - [Code] HTML reports now generate JSON data which is shared between
data/README.org CHANGED
@@ -43,7 +43,7 @@ stored on your computer and owned by you (like it should be)[fn:1].
43
43
  LogSense is also inspired by *static websites generators*: statistics
44
44
  are generated from the command line and accessed as static HTML files.
45
45
  LogSense thus significantly reduces the attack surface of your
46
- webserver and installation headaches. We have, for instance, a Cron
46
+ web server and installation headaches. We have, for instance, a cron
47
47
  job running on our servers, generating statistics at night. The
48
48
  generated files are then made available on a private area on the web.
49
49
 
@@ -76,22 +76,23 @@ generated files are then made available on a private area on the web.
76
76
  -v, --version Prints version information
77
77
  -h, --help Prints this help
78
78
 
79
- This is version 1.1.1
79
+ This is version 1.3.1
80
80
 
81
81
  Output formats
82
- apache parsing can produce the following outputs:
83
- - sqlite
84
- - html
85
82
  rails parsing can produce the following outputs:
86
83
  - sqlite
87
84
  - txt
85
+ - html
86
+ apache parsing can produce the following outputs:
87
+ - sqlite
88
+ - html
88
89
  #+end_example
89
90
 
90
91
  Examples:
91
92
 
92
93
  #+begin_example sh
93
94
  log_sense -f apache -i access.log -t txt > access-data.txt
94
- log_sense -f rails -i production.log -t html > performance.txt
95
+ log_sense -f rails -i production.log -t html -o performance.txt
95
96
  #+end_example
96
97
 
97
98
  * Change Log
@@ -6,7 +6,7 @@ module LogSense
6
6
  # @ variables are automatically put in the returned data
7
7
  #
8
8
 
9
- def self.crunch db, options = { limit: 30 }
9
+ def self.crunch db, options = { limit: 900 }
10
10
  first_day_s = db.execute "SELECT datetime from LogLine order by datetime limit 1"
11
11
  last_day_s = db.execute "SELECT datetime from LogLine order by datetime desc limit 1"
12
12
 
@@ -89,16 +89,18 @@ module LogSense
89
89
 
90
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
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
- @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]}"
93
- @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]}"
94
- @missed_pages = db.execute "SELECT path, count(path), count(distinct(unique_visitor)) from LogLine where status == '404' and extension == '.html' and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
95
- @missed_resources = db.execute "SELECT path, count(path), count(distinct(unique_visitor)) from LogLine where status == '404' and #{filter} group by path order by count(path) desc limit #{options[:limit]}"
96
92
 
97
- @reasonable_requests_exts = [ ".html", ".css", ".js", ".jpg", ".svg", ".png", ".woff", ".xml", ".ttf", ".ico", ".pdf", ".htm", ".txt", ".org" ].map { |x|
98
- "extension != '#{x}'"
99
- }.join " and "
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]}"
100
103
 
101
- @attacks = db.execute "SELECT path, count(path), count(distinct(unique_visitor)) from LogLine where status == '404' and #{filter} and (#{@reasonable_requests_exts}) group by path order by count(path) desc limit #{options[:limit]}"
102
104
  @statuses = db.execute "SELECT status, count(status) from LogLine where #{filter} group by status order by status"
103
105
 
104
106
  @by_day_4xx = db.execute "SELECT date(datetime), count(datetime) from LogLine where substr(status, 1,1) == '4' and #{filter} group by date(datetime)"
@@ -33,20 +33,19 @@ module LogSense
33
33
 
34
34
  HTTP_METHODS=/GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH/
35
35
  WEBDAV_METHODS=/COPY|LOCK|MKCOL|MOVE|PROPFIND|PROPPATCH|UNLOCK/
36
- OTHER_METHODS=/SEARCH|REPORT/
36
+ OTHER_METHODS=/SEARCH|REPORT|PRI|HEAD\/robots.txt/
37
37
  METHOD=/(?<method>#{HTTP_METHODS}|#{WEBDAV_METHODS}|#{OTHER_METHODS})/
38
- PROTOCOL=/(?<protocol>HTTP\/[0-9]\.[0-9])/
38
+ PROTOCOL=/(?<protocol>HTTP\/[0-9]\.[0-9]|-|.*)/
39
39
  URL=/(?<url>[^ ]+)/
40
- REFERER=/(?<referer>[^ ]+)/
40
+ REFERER=/(?<referer>[^"]*)/
41
41
  RETURN_CODE=/(?<status>[1-5][0-9][0-9])/
42
42
  SIZE=/(?<size>[0-9]+|-)/
43
-
44
- USER_AGENT = /(?<user_agent>[^"]+)/
43
+ USER_AGENT = /(?<user_agent>[^"]*)/
45
44
 
46
45
  attr_reader :format
47
46
 
48
47
  def initialize
49
- @format = /#{IP} #{IDENT} #{USERID} \[#{TIMESTAMP}\] "#{METHOD} #{URL} #{PROTOCOL}" #{RETURN_CODE} #{SIZE} "#{REFERER}" "#{USER_AGENT}"/
48
+ @format = /#{IP} #{IDENT} #{USERID} \[#{TIMESTAMP}\] "(#{METHOD} #{URL} #{PROTOCOL}|-|.+)" #{RETURN_CODE} #{SIZE} "#{REFERER}" "#{USER_AGENT}"/
50
49
  end
51
50
 
52
51
  def parse line
@@ -40,5 +40,25 @@ module LogSense
40
40
  ERB.new(erb_template).result(OpenStruct.new(vars).instance_eval { binding })
41
41
  end
42
42
 
43
+ def self.escape_javascript(string)
44
+ js_escape_map = {
45
+ "<script" => "&lt;script",
46
+ "</script" => "&lt;/script",
47
+ "<" => "&lt;",
48
+ "</" => '&lt;\/',
49
+ "\\" => "\\\\",
50
+ "\r\n" => '\\r\\n',
51
+ "\n" => '\\n',
52
+ "\r" => '\\r',
53
+ '"' => ' \\"',
54
+ "'" => " \\'",
55
+ "`" => " \\`",
56
+ "$" => " \\$"
57
+ }
58
+ js_escape_map.each do |k, v|
59
+ string = string.gsub(k, v)
60
+ end
61
+ string
62
+ end
43
63
  end
44
64
  end
@@ -8,7 +8,7 @@ module LogSense
8
8
  # parse command line options
9
9
  #
10
10
  def self.parse options
11
- limit = 30
11
+ limit = 900
12
12
  args = {}
13
13
 
14
14
  opt_parser = OptionParser.new do |opts|
@@ -7,7 +7,7 @@ module LogSense
7
7
  # @ variables are automatically put in the returned data
8
8
  #
9
9
 
10
- def self.crunch db, options = { limit: 30 }
10
+ def self.crunch db, options = { limit: 900 }
11
11
  first_day_s = db.execute "SELECT started_at from Event where started_at not NULL order by started_at limit 1"
12
12
  # we could use ended_at to cover the full activity period, but I prefer started_at
13
13
  # with the meaning that the monitor event initiation
@@ -19,6 +19,7 @@ end
19
19
  $(document).ready(function(){
20
20
  $('#table-<%= index %>').dataTable({
21
21
  data: data_<%= index %>,
22
+ <%= report[:datatable_options] + "," if report[:datatable_options] %>
22
23
  columns: [
23
24
  <% report[:header].each do |header| %>
24
25
  { data: '<%= header %>', className: '<%= slugify(header) %>' },
@@ -4,7 +4,8 @@
4
4
  <% report[:rows].each do |row| %>
5
5
  {
6
6
  <% report[:header].each_with_index do |h, i| %>
7
- "<%= h %>": <%= (row[i].class == Integer or row[i].class == Float) ? row[i] : "\"#{row[i]}\"" %>,
7
+ <% resized_row = (row[i] || '').size > 150 ? "#{row[i][0..150]...}" : (row[i] || "") %>
8
+ "<%= h %>": <%= (row[i].class == Integer or row[i].class == Float) ? row[i] : "\"#{Emitter::escape_javascript(resized_row)}\"" %>,
8
9
  <% end %>
9
10
  },
10
11
  <% end %>
@@ -17,7 +17,12 @@
17
17
  <%= data[:total_unique_visits] %> <span class="stats-list-label">Unique Visits</span>
18
18
  </li>
19
19
  <li class="stats-list-negative">
20
- <%= data[:total_unique_visits] != 0 ? data[:total_hits] / data[:total_unique_visits] : "N/A" %>
20
+ <% days = data[:last_day_in_analysis] - data[:first_day_in_analysis] %>
21
+ <%= days > 0 ? "%.2f" % (data[:total_unique_visits] / days.to_f) : "N/A" %>
21
22
  <span class="stats-list-label">Unique Visits / Day</span>
22
23
  </li>
24
+ <li class="stats-list-negative">
25
+ <%= data[:total_unique_visits] != 0 ? data[:total_hits] / data[:total_unique_visits] : "N/A" %>
26
+ <span class="stats-list-label">Page Visited / Unique Visitor</span>
27
+ </li>
23
28
  </ul>
@@ -157,11 +157,10 @@
157
157
  "Log Structure",
158
158
  "Daily Distribution",
159
159
  "Time Distribution",
160
- "Most Requested Pages",
161
- "Most Requested Resources",
162
- "404 on HTML Files",
163
- "404 on other Resources",
164
- "Attacks",
160
+ "20_ and 30_ on HTML pages",
161
+ "20_ and 30_ on other resources",
162
+ "40_ and 50_ on HTML pages",
163
+ "40_ and 50_ on other Resources",
165
164
  "Statuses",
166
165
  "Daily Statuses",
167
166
  "Browsers",
@@ -319,14 +318,26 @@
319
318
  }
320
319
  }
321
320
  },
322
- { title: "Most Requested Pages",
323
- header: ["Path", "Hits", "Visits", "Size"],
321
+ { title: "20_ and 30_ on HTML pages",
322
+ header: ["Path", "Hits", "Visits", "Size", "Status"],
324
323
  rows: data[:most_requested_pages],
324
+ datatable_options: "columnDefs: [{ width: \"40%\", targets: 0 } ]"
325
+ },
326
+ { title: "20_ and 30_ on other resources",
327
+ header: ["Path", "Hits", "Visits", "Size", "Status"],
328
+ rows: data[:most_requested_resources],
329
+ datatable_options: "columnDefs: [{ width: \"40%\", targets: 0 } ]"
330
+ },
331
+ { title: "40_ and 50_x on HTML pages",
332
+ header: ["Path", "Hits", "Visits", "Status"],
333
+ rows: data[:missed_pages],
334
+ datatable_options: "columnDefs: [{ width: \"40%\", targets: 0 } ]"
335
+ },
336
+ { title: "40_ and 50_ on other resources",
337
+ header: ["Path", "Hits", "Visits", "Status"],
338
+ rows: data[:missed_resources],
339
+ datatable_options: "columnDefs: [{ width: \"40%\", targets: 0 } ]"
325
340
  },
326
- { title: "Most Requested Resources", header: ["Path", "Hits", "Visits", "Size"], rows: data[:most_requested_resources] },
327
- { title: "404 on HTML Files", header: ["Path", "Hits", "Visits"], rows: data[:missed_pages] },
328
- { title: "404 on other Resources", header: ["Path", "Hits", "Visits"], rows: data[:missed_resources] },
329
- { title: "Attacks", header: ["Path", "Hits", "Visits"], rows: data[:attacks], col: "small-12 cell" },
330
341
  { title: "Statuses",
331
342
  header: ["Status", "Count"],
332
343
  rows: data[:statuses],
@@ -494,10 +505,10 @@
494
505
  <th>IP</th>
495
506
  <th>
496
507
  <div class="grid-x grid-margin-x">
497
- <div class="col-2 cell">
508
+ <div class="small-2 cell">
498
509
  Day
499
510
  </div>
500
- <div class="col-10 cell">
511
+ <div class="small-10 cell">
501
512
  Resources
502
513
  </div>
503
514
  </div>
@@ -513,26 +524,25 @@
513
524
  <td class="streaks">
514
525
  <div class="grid-x grid-margin-x">
515
526
  <% date_urls.group_by { |x| x[1] }.each do |date, urls| %>
516
- <div class="col-2 cell">
527
+ <div class="small-12 medium-1 cell">
517
528
  <span class="date"><%= date %></span>
518
529
  </div>
519
- <div class="col-10 cell grid-x">
520
- <div class="small-12 medium-6 cell">
521
- <span class="res-title">HTML:</span>
522
- <ul>
523
- <% urls.map { |x| x[2] }.compact.select { |x| x.match /.*\.html?/ }.each do |url| %>
524
- <li><%= url %></li>
525
- <% end %>
526
- </ul>
527
- </div>
528
- <div class=" small-12 medium-6 cell">
529
- <span class="res-title small-12 medium-6 cell">Other Resources:</span>
530
- <ul>
531
- <% urls.map { |x| x[2] }.compact.sort.select { |x| x and not x.match /.*\.html?/ }.each do |url| %>
532
- <li><%= url %></li>
533
- <% end %>
534
- </ul>
535
- </div>
530
+ <div class="small-12 medium-5 cell">
531
+ <span class="res-title">HTML:</span>
532
+ <% unique_with_count = urls.map { |x| x[2] }.compact.group_by{|e| e}.map{|k, v| [k, v.length]} %>
533
+ <ul class="no-bullet">
534
+ <% unique_with_count.select { |x| x[0].match /.*\.html?/ }.each do |url| %>
535
+ <li>[<%= url[1] %>] <%= Emitter::escape_javascript url[0] %></li>
536
+ <% end %>
537
+ </ul>
538
+ </div>
539
+ <div class=" small-12 medium-5 cell">
540
+ <span class="res-title">Other Resources:</span>
541
+ <ul class="no-bullet">
542
+ <% unique_with_count.select { |x| x[0] and ! x[0].match /.*\.html?/ }.each do |url| %>
543
+ <li>[<%= url[1] %>] <%= Emitter::escape_javascript url[0] %></li>
544
+ <% end %>
545
+ </ul>
536
546
  </div>
537
547
  <% end %>
538
548
  </div>
@@ -308,7 +308,24 @@
308
308
  vega_spec: {
309
309
  "layer": [
310
310
  {
311
- "mark": "point"
311
+ "mark": {
312
+ "type": "point",
313
+ "name": "data_points"
314
+ }
315
+ },
316
+ {
317
+ "mark": {
318
+ "name": "label",
319
+ "type": "text",
320
+ "align": "left",
321
+ "baseline": "middle",
322
+ "dx": 5,
323
+ "yOffset": 0
324
+ },
325
+ "encoding": {
326
+ "text": {"field": "Controller"},
327
+ "fontSize": {"value": 8}
328
+ },
312
329
  },
313
330
  ],
314
331
  "encoding": {
@@ -1,3 +1,3 @@
1
1
  module LogSense
2
- VERSION = "1.3.2"
2
+ VERSION = "1.4.0"
3
3
  end
data/log_sense.gemspec CHANGED
@@ -1,38 +1,38 @@
1
1
  require_relative 'lib/log_sense/version'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
- spec.name = "log_sense"
4
+ spec.name = 'log_sense'
5
5
  spec.version = LogSense::VERSION
6
- spec.authors = ["Adolfo Villafiorita"]
7
- spec.email = ["adolfo.villafiorita@ict4g.net"]
6
+ spec.authors = ['Adolfo Fibrillation']
7
+ spec.email = ['adolfo@shair.tech']
8
8
 
9
- spec.summary = %q{Generate analytics from an Apache and Rails log file.}
10
- spec.description = %q{Generate analystics in HTML, txt, and SQLite format from an Apache and Rails log files.}
11
- spec.homepage = "https://www.ict4g.net/gitea/adolfo/log_sense"
12
- spec.license = "MIT"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.6.9")
9
+ spec.summary = %q{Generate analytics for Apache and Rails log file.}
10
+ spec.description = %q{Generate analytics in HTML, txt, and SQLite format for Apache and Rails log files.}
11
+ spec.homepage = 'https://github.com/shair-tech/log_sense/log_sense'
12
+ spec.license = 'MIT'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.9')
14
14
 
15
- spec.metadata["allowed_push_host"] = "https://rubygems.org/"
15
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
16
16
 
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://www.ict4g.net/gitea/adolfo/log_sense"
19
- spec.metadata["changelog_uri"] = "https://www.ict4g.net/gitea/adolfo/log_sense/CHANGELOG.org"
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/shair-tech/log_sense/log_sense'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/shair-tech/log_sense/blob/main/CHANGELOG.org'
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
23
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
25
  end
26
- spec.bindir = "exe"
26
+ spec.bindir = 'exe'
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
28
+ spec.require_paths = ['lib']
29
29
 
30
- spec.add_dependency "browser"
31
- spec.add_dependency "ipaddr"
32
- spec.add_dependency "iso_country_codes"
33
- spec.add_dependency "sqlite3"
34
- spec.add_dependency "terminal-table"
30
+ spec.add_dependency 'browser'
31
+ spec.add_dependency 'ipaddr'
32
+ spec.add_dependency 'iso_country_codes'
33
+ spec.add_dependency 'sqlite3'
34
+ spec.add_dependency 'terminal-table'
35
35
 
36
36
  spec.add_development_dependency 'byebug'
37
- spec.add_development_dependency "minitest"
37
+ spec.add_development_dependency 'minitest'
38
38
  end
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.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
- - Adolfo Villafiorita
7
+ - Adolfo Fibrillation
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: browser
@@ -108,10 +108,10 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- description: Generate analystics in HTML, txt, and SQLite format from an Apache and
112
- Rails log files.
111
+ description: Generate analytics in HTML, txt, and SQLite format for Apache and Rails
112
+ log files.
113
113
  email:
114
- - adolfo.villafiorita@ict4g.net
114
+ - adolfo@shair.tech
115
115
  executables:
116
116
  - log_sense
117
117
  extensions: []
@@ -155,14 +155,14 @@ files:
155
155
  - sample_logs/empty_log.log
156
156
  - sample_logs/safety-critical_org.log
157
157
  - sample_logs/spmbook_com.log
158
- homepage: https://www.ict4g.net/gitea/adolfo/log_sense
158
+ homepage: https://github.com/shair-tech/log_sense/log_sense
159
159
  licenses:
160
160
  - MIT
161
161
  metadata:
162
162
  allowed_push_host: https://rubygems.org/
163
- homepage_uri: https://www.ict4g.net/gitea/adolfo/log_sense
164
- source_code_uri: https://www.ict4g.net/gitea/adolfo/log_sense
165
- changelog_uri: https://www.ict4g.net/gitea/adolfo/log_sense/CHANGELOG.org
163
+ homepage_uri: https://github.com/shair-tech/log_sense/log_sense
164
+ source_code_uri: https://github.com/shair-tech/log_sense/log_sense
165
+ changelog_uri: https://github.com/shair-tech/log_sense/blob/main/CHANGELOG.org
166
166
  post_install_message:
167
167
  rdoc_options: []
168
168
  require_paths:
@@ -181,5 +181,5 @@ requirements: []
181
181
  rubygems_version: 3.0.3.1
182
182
  signing_key:
183
183
  specification_version: 4
184
- summary: Generate analytics from an Apache and Rails log file.
184
+ summary: Generate analytics for Apache and Rails log file.
185
185
  test_files: []