log_sense 1.4.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.org +45 -0
  3. data/Gemfile.lock +15 -8
  4. data/LICENSE.txt +9 -2
  5. data/README.org +33 -16
  6. data/Rakefile +17 -3
  7. data/exe/log_sense +22 -5
  8. data/ip_locations/dbip-country-lite.sqlite3 +0 -0
  9. data/lib/log_sense/apache_data_cruncher.rb +23 -19
  10. data/lib/log_sense/apache_log_line_parser.rb +1 -1
  11. data/lib/log_sense/apache_log_parser.rb +1 -1
  12. data/lib/log_sense/emitter.rb +199 -67
  13. data/lib/log_sense/ip_locator.rb +26 -19
  14. data/lib/log_sense/options_parser.rb +16 -2
  15. data/lib/log_sense/rails_data_cruncher.rb +3 -0
  16. data/lib/log_sense/templates/_command_invocation.html.erb +4 -0
  17. data/lib/log_sense/templates/_command_invocation.txt.erb +1 -0
  18. data/lib/log_sense/templates/_log_structure.html.erb +6 -3
  19. data/lib/log_sense/templates/_navigation.html.erb +22 -0
  20. data/lib/log_sense/templates/_output_table.html.erb +49 -1
  21. data/lib/log_sense/templates/_output_table.txt.erb +6 -3
  22. data/lib/log_sense/templates/_report_data.html.erb +4 -4
  23. data/lib/log_sense/templates/_stylesheet.css +144 -0
  24. data/lib/log_sense/templates/_summary.html.erb +11 -4
  25. data/lib/log_sense/templates/_summary.txt.erb +1 -1
  26. data/lib/log_sense/templates/_warning.txt.erb +1 -0
  27. data/lib/log_sense/templates/apache.html.erb +51 -316
  28. data/lib/log_sense/templates/apache.txt.erb +2 -15
  29. data/lib/log_sense/templates/rails.html.erb +56 -216
  30. data/lib/log_sense/templates/rails.txt.erb +5 -6
  31. data/lib/log_sense/version.rb +1 -1
  32. data/log_sense.gemspec +21 -21
  33. metadata +9 -7
  34. data/sample_logs/empty_log.log +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ef1d35932ba8c7fe6e636f6cb507ea99fd6b6026170d62207dfa2606d62bbcb
4
- data.tar.gz: 725dc6e51ace6c9cbd366e3888387ef8f246327c9e1036c66d2eb6351b1f0791
3
+ metadata.gz: 5f37b2247014af9bccfb8bdd205b54eb51cbef35495904444765648a96e0b9ac
4
+ data.tar.gz: a9cd03afb6770bf854791b8ec93e87d09532828d894b28f5dde670f1af1b1b1d
5
5
  SHA512:
6
- metadata.gz: 592e80cd56f4740cc4003b494c9da960de228025377d630d070a08a495cffac7fd41850d469189510def48f9940700251bd84a141def9b1b15b32fbed967261f
7
- data.tar.gz: 1d802e95fd58c66c4904843478c5ccc8ffc1ce43e87dd199e5b21efc89bcff436b227c646d2e5a386bee22a3d1c67c0341c25fcb4058e48526560d05984f0148
6
+ metadata.gz: 62981216e38b92e1c3ea227726dccd592c441de32519a4df6f39bac127f55da32e82b4a1a14897b09b7032c7b3f9506a14e80e49dc43bfe8c9d86bfaa340da82
7
+ data.tar.gz: e5e6180008a12561d688668cffb2ef3d885d7733cf877aafaed0397b9fa0e91dd12a2998b19006dad4fe6b202bd203a00757f86d5d37efee777dbc7be43e5ab1
data/CHANGELOG.org CHANGED
@@ -2,6 +2,51 @@
2
2
  #+AUTHOR: Adolfo Villafiorita
3
3
  #+STARTUP: showall
4
4
 
5
+ * 1.5.2
6
+
7
+ - [User] Updated DB-IP country file.
8
+ - [User] Added reports "Missed Pages by IP" and "Missed Resources by
9
+ IP". It can help pinpoint attack sources.
10
+ - [User] Added report "Combined Platform", which puts together
11
+ Browser, OS, and IP.
12
+ - [User] Summary now shows total size transferred.
13
+ - [User] Added link to DB-IP page for IPs in some tables.
14
+ - [User] Added count of IPs by Country.
15
+ - [User] Improved textual report: values in cells holding multiple
16
+ values (e.g. IPs) are now shown in distinct lines in the cell. A new
17
+ option -r limits the number of lines shown per cell.
18
+ - [Default] The number of rows initially shown in HTML reports is now 25.
19
+ - [Default] Default for number of entries in textual report is now
20
+ 100 (used to be 900).
21
+ - [Fixed] The size column in HTML reports is now sorted numerically.
22
+ - [Code] Improved performances of DataTable rendering, using the
23
+ dataRender flag.
24
+ - [Code] Use trim_mode in ERB to avoid empty lines in HTML output.
25
+ - [Code] Moved to the debug gem.
26
+ - [Gem] Updated email and author's name.
27
+
28
+ * 1.5.1
29
+
30
+ - [User] Option --input-files allows to specify input files
31
+ in addition to passing filenames to the command line
32
+ - [User] Minor changes to the layout of HTML reports
33
+ - [User] Add version number in reports
34
+ - [Fixed] Duplicated entries in navigation
35
+ - [Code] Updated and added minitest(s)
36
+
37
+ * 1.5.0
38
+
39
+ - [User] Present Unique Visits / day as integer
40
+ - [User] Added Country and Streaks report for rails
41
+ - [User] Changed Streak report in Apache
42
+ - [Gem] Updated DB-IP
43
+ - [Gem] Updated Bundle
44
+ - [Code] Refactored all reports, so that they are specified
45
+ in the same way
46
+ - [Code] Refactor warning message in textual reports
47
+ - [Code] Build HTML menu for report specification
48
+ - [Code] Various refactoring passes on the code
49
+
5
50
  * 1.4.1
6
51
 
7
52
  - [User] New textual report for Apache
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- log_sense (1.3.1)
4
+ log_sense (1.5.2)
5
5
  browser
6
6
  ipaddr
7
7
  iso_country_codes
@@ -12,24 +12,31 @@ GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
14
  browser (5.3.1)
15
- byebug (11.1.3)
16
- ipaddr (1.2.3)
15
+ debug (1.6.2)
16
+ irb (>= 1.3.6)
17
+ reline (>= 0.3.1)
18
+ io-console (0.5.11)
19
+ ipaddr (1.2.4)
20
+ irb (1.4.1)
21
+ reline (>= 0.3.0)
17
22
  iso_country_codes (0.7.8)
18
- minitest (5.14.4)
23
+ minitest (5.15.0)
19
24
  rake (12.3.3)
20
- sqlite3 (1.4.2)
25
+ reline (0.3.1)
26
+ io-console (~> 0.5)
27
+ sqlite3 (1.4.4)
21
28
  terminal-table (3.0.2)
22
29
  unicode-display_width (>= 1.1.1, < 3)
23
- unicode-display_width (2.1.0)
30
+ unicode-display_width (2.2.0)
24
31
 
25
32
  PLATFORMS
26
33
  ruby
27
34
 
28
35
  DEPENDENCIES
29
- byebug
36
+ debug
30
37
  log_sense!
31
38
  minitest
32
39
  rake (~> 12.0)
33
40
 
34
41
  BUNDLED WITH
35
- 2.2.32
42
+ 2.3.3
data/LICENSE.txt CHANGED
@@ -1,5 +1,4 @@
1
- The MIT License (MIT)
2
-
1
+ The source code is distributed under the terms of the MIT License (MIT)
3
2
  Copyright (c) 2021 Shair.Tech
4
3
 
5
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -19,3 +18,11 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
18
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
19
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
20
  THE SOFTWARE.
21
+
22
+ ==============================================================================
23
+ LogSense uses data from The free DB-IP Lite database for geolocation purposes.
24
+
25
+ The DB-IP Lite Database is licensed under a Creative Commons Attribution 4.0
26
+ International License.
27
+
28
+ For more information: https://db-ip.com
data/README.org CHANGED
@@ -14,13 +14,13 @@ LogSense reports the following data:
14
14
  - Visitors, hits, unique visitors, bandwidth used
15
15
  - Most accessed HTML pages
16
16
  - Most accessed resources
17
+ - Missed resources (also by IP) which helps highlight
18
+ potential attacks
17
19
  - Response statuses
18
20
  - Referers
19
21
  - OS, browsers, and devices
20
- - IP Country location, thanks to the DPIP lite country DB
22
+ - IP Country location, thanks to the DP-IP lite country DB
21
23
  - Streaks: resources accessed by a given IP over time
22
- - Potential attacks: access to resources which are not meant to be
23
- served by a web server serving static websites
24
24
  - Performance of Rails requests
25
25
 
26
26
  Filters from the command line allow to analyze specific periods and
@@ -33,6 +33,18 @@ And, of course, the compulsory screenshot:
33
33
  #+ATTR_HTML: :width 80%
34
34
  [[file:./apache-screenshot.png]]
35
35
 
36
+
37
+ * An important word of warning
38
+
39
+ [[https://owasp.org/www-community/attacks/Log_Injection][Log poisoning]] is a technique whereby attackers send requests with invalidated
40
+ user input to forge log entries or inject malicious content into the logs.
41
+
42
+ log_sense sanitizes entries of HTML reports, to try and protect from log
43
+ poisoning. *Log entries and URLs in SQLite3, however, are not sanitized*:
44
+ they are stored and read from the log. This is not, in general, an issue,
45
+ unless you use the data from SQLite in environments in which URLs can be
46
+ opened or code executed.
47
+
36
48
  * Motivation
37
49
 
38
50
  LogSense moves along the lines of tools such as [[https://goaccess.io/][GoAccess]] (which
@@ -54,6 +66,7 @@ generated files are then made available on a private area on the web.
54
66
  gem install log_sense
55
67
  #+end_src
56
68
 
69
+
57
70
  * Usage
58
71
 
59
72
  #+begin_src bash :results raw output :wrap example
@@ -65,37 +78,41 @@ generated files are then made available on a private area on the web.
65
78
  Usage: log_sense [options] [logfile ...]
66
79
  --title=TITLE Title to use in the report
67
80
  -f, --input-format=FORMAT Input format (either rails or apache)
81
+ -i, --input-files=file,file, Input files (can also be passed directly)
68
82
  -t, --output-format=FORMAT Output format: html, org, txt, sqlite. See below for available formats
69
83
  -o, --output-file=OUTPUT_FILE Output file
70
84
  -b, --begin=DATE Consider entries after or on DATE
71
85
  -e, --end=DATE Consider entries before or on DATE
72
- -l, --limit=N Limit to the N most requested resources (defaults to 900)
73
- -w, --width=WIDTH Maximum width of URL and description columns in text reports
86
+ -l, --limit=N Limit to the N most requested resources (defaults to 100)
87
+ -w, --width=WIDTH Maximum width of long columns in textual reports
88
+ -r, --rows=ROWS Maximum number of rows for columns with multiple entries in textual reports
74
89
  -c, --crawlers=POLICY Decide what to do with crawlers (applies to Apache Logs)
75
90
  -n, --no-selfpolls Ignore self poll entries (requests from ::1; applies to Apache Logs)
91
+ --verbose Inform about progress (prints to STDERR)
76
92
  -v, --version Prints version information
77
93
  -h, --help Prints this help
78
94
 
79
- This is version 1.4.1
95
+ This is version 1.5.2
80
96
 
81
97
  Output formats
82
- rails parsing can produce the following outputs:
83
- - sqlite
84
- - txt
85
- - html
86
98
  apache parsing can produce the following outputs:
87
99
  - sqlite
100
+ - html
88
101
  - txt
102
+ rails parsing can produce the following outputs:
103
+ - sqlite
89
104
  - html
105
+ - txt
90
106
  #+end_example
91
107
 
92
108
  Examples:
93
109
 
94
110
  #+begin_example sh
95
111
  log_sense -f apache -i access.log -t txt > access-data.txt
96
- log_sense -f rails -i production.log -t html -o performance.txt
112
+ log_sense -f rails -i production.log -t html -o performance.html
97
113
  #+end_example
98
114
 
115
+
99
116
  * Change Log
100
117
 
101
118
  See the [[file:CHANGELOG.org][CHANGELOG]] file.
@@ -110,8 +127,8 @@ Concerning the outputs:
110
127
  - HTML reports use [[https://get.foundation/][Zurb Foundation]], [[https://www.datatables.net/][Data Tables]], and [[https://vega.github.io/vega-lite/][Vega Light]], which
111
128
  are all downloaded from a CDN
112
129
  - The textual format is compatible with [[https://orgmode.org/][Org Mode]] and can be further
113
- processed to any format [[https://orgmode.org/][Org Mode]] can be exported to (including HTML
114
- and PDF)
130
+ processed to any format [[https://orgmode.org/][Org Mode]] can be exported to, including HTML
131
+ and PDF, with the word of warning in the section above.
115
132
 
116
133
  * Author and Contributors
117
134
 
@@ -119,12 +136,12 @@ Concerning the outputs:
119
136
 
120
137
  * Known Bugs
121
138
 
122
- No known bugs; an unknown number of unknown bugs.
123
- (See the open issues for the known bugs.)
139
+ No known bugs; an unknown number of unknown bugs. (See the open issues for
140
+ the known bugs.)
124
141
 
125
142
  * License
126
143
 
127
- Distributed under the terms of the [[http://opensource.org/licenses/MIT][MIT License]].
144
+ Source code distributed under the terms of the [[http://opensource.org/licenses/MIT][MIT License]].
128
145
 
129
146
  Geolocation is made possible by the DB-IP.com IP to City database,
130
147
  released under a CC license.
data/Rakefile CHANGED
@@ -9,7 +9,21 @@ end
9
9
  require_relative './lib/log_sense/ip_locator.rb'
10
10
 
11
11
  desc "Convert Geolocation DB to sqlite"
12
- task :dbip_to_sqlite3, [:filename] do |tasks, args|
13
- filename = args[:filename]
14
- ApacheLogReport::IpLocator::dbip_to_sqlite filename
12
+ task :dbip_to_sqlite3, [:year_month] do |tasks, args|
13
+ filename = "./ip_locations/dbip-country-lite-#{args[:year_month]}.csv"
14
+
15
+ if !File.exist? filename
16
+ puts "Error. Could not find: #{filename}"
17
+ puts
18
+ puts 'I see the following files:'
19
+ puts Dir.glob("ip_locations/dbip-country-lite*").map { |x| "- #{x}\n" }
20
+ puts ''
21
+ puts '1. Download (if necessary) a more recent version from: https://db-ip.com/db/download/ip-to-country-lite'
22
+ puts '2. Save downloaded file to ip_locations/'
23
+ puts '3. Relaunch with YYYY-MM'
24
+
25
+ exit
26
+ else
27
+ LogSense::IpLocator::dbip_to_sqlite filename
28
+ end
15
29
  end
data/exe/log_sense CHANGED
@@ -11,11 +11,18 @@ require 'log_sense.rb'
11
11
  @options = LogSense::OptionsParser.parse ARGV
12
12
  @output_file = @options[:output_file]
13
13
 
14
- if ARGV.map { |x| File.exist?(x) }.include?(false)
15
- warn.puts "Error: input file(s) '#{ARGV.reject { |x| File.exist(x) }.join(', ')}' do not exist"
14
+ #
15
+ # Input files can be gotten from an option and from what remains in
16
+ # ARGV
17
+ #
18
+ @input_filenames = @options[:input_filenames] + ARGV
19
+ @non_existing = @input_filenames.reject { |x| File.exist?(x) }
20
+
21
+ unless @non_existing.empty?
22
+ $stderr.puts "Error: input file(s) '#{@non_existing.join(', ')}' do not exist"
16
23
  exit 1
17
24
  end
18
- @input_files = ARGV.empty? ? [$stdin] : ARGV.map { |x| File.open(x, 'r') }
25
+ @input_files = @input_filenames.empty? ? [$stdin] : @input_filenames.map { |x| File.open(x, 'r') }
19
26
 
20
27
  #
21
28
  # Parse Log and Track Statistics
@@ -31,35 +38,45 @@ when 'rails'
31
38
  parser_klass = LogSense::RailsLogParser
32
39
  cruncher_klass = LogSense::RailsDataCruncher
33
40
  else
34
- warn.puts "Error: input format #{@options[:input_format]} not understood."
41
+ $stderr.puts "Error: input format #{@options[:input_format]} not understood."
35
42
  exit 1
36
43
  end
37
44
 
45
+ $stderr.puts "Parsing input files..." if @options[:verbose]
38
46
  @db = parser_klass.parse @input_files
39
47
 
40
48
  if @options[:output_format] == 'sqlite'
49
+ $stderr.puts "Saving to SQLite3..." if @options[:verbose]
41
50
  ddb = SQLite3::Database.new(@output_file || 'db.sqlite3')
42
51
  b = SQLite3::Backup.new(ddb, 'main', @db, 'main')
43
52
  b.step(-1) #=> DONE
44
53
  b.finish
45
54
  else
55
+ $stderr.puts "Aggregating data..." if @options[:verbose]
46
56
  @data = cruncher_klass.crunch @db, @options
57
+
58
+ $stderr.puts "Geolocating..." if @options[:verbose]
47
59
  @data = LogSense::IpLocator.geolocate @data
48
60
 
61
+ $stderr.puts "Grouping by country..." if @options[:verbose]
62
+ country_col = @data[:ips][0].size - 1
63
+ @data[:countries] = @data[:ips].group_by { |x| x[country_col] }
64
+
49
65
  @ended_at = Time.now
50
66
  @duration = @ended_at - @started_at
51
67
 
52
68
  @data = @data.merge({
53
69
  command: @command_line,
70
+ filenames: ARGV,
54
71
  log_files: @input_files,
55
72
  started_at: @started_at,
56
73
  ended_at: @ended_at,
57
74
  duration: @duration,
58
75
  width: @options[:width]
59
76
  })
60
-
61
77
  #
62
78
  # Emit Output
63
79
  #
80
+ $stderr.puts "Emitting..." if @options[:verbose]
64
81
  puts LogSense::Emitter.emit @data, @options
65
82
  end
Binary file
@@ -17,15 +17,15 @@ module LogSense
17
17
  @total_days = 0
18
18
  @total_days = (@last_day - @first_day).to_i if @first_day && @last_day
19
19
 
20
- @source_files = db.execute "SELECT distinct(source_file) from LogLine"
20
+ @source_files = db.execute 'SELECT distinct(source_file) from LogLine'
21
21
 
22
- @log_size = db.execute "SELECT count(datetime) from LogLine"
22
+ @log_size = db.execute 'SELECT count(datetime) from LogLine'
23
23
  @log_size = @log_size[0][0]
24
24
 
25
25
  @selfpolls_size = db.execute "SELECT count(datetime) from LogLine where ip == '::1'"
26
26
  @selfpolls_size = @selfpolls_size[0][0]
27
27
 
28
- @crawlers_size = db.execute "SELECT count(datetime) from LogLine where bot == 1"
28
+ @crawlers_size = db.execute 'SELECT count(datetime) from LogLine where bot == 1'
29
29
  @crawlers_size = @crawlers_size[0][0]
30
30
 
31
31
  @first_day_requested = options[:from_date]
@@ -35,7 +35,7 @@ module LogSense
35
35
  @last_day_in_analysis = date_intersect options[:to_date], @last_day, :min
36
36
 
37
37
  @total_days_in_analysis = 0
38
- if @first_day_in_analysis and @last_day_in_analysis
38
+ if @first_day_in_analysis && @last_day_in_analysis
39
39
  @total_days_in_analysis = (@last_day_in_analysis - @first_day_in_analysis).to_i
40
40
  end
41
41
 
@@ -45,24 +45,24 @@ module LogSense
45
45
  filter = [
46
46
  (options[:from_date] ? "date(datetime) >= '#{options[:from_date]}'" : nil),
47
47
  (options[:to_date] ? "date(datetime) <= '#{options[:to_date]}'" : nil),
48
- (options[:only_crawlers] ? "bot == 1" : nil),
49
- (options[:ignore_crawlers] ? "bot == 0" : nil),
48
+ (options[:only_crawlers] ? 'bot == 1' : nil),
49
+ (options[:ignore_crawlers] ? 'bot == 0' : nil),
50
50
  (options[:no_selfpolls] ? "ip != '::1'" : nil),
51
- "true"
51
+ 'true'
52
52
  ].compact.join " and "
53
53
 
54
54
  mega = 1024 * 1024
55
55
  giga = mega * 1024
56
56
  tera = giga * 1024
57
-
57
+
58
58
  # in alternative to sum(size)
59
59
  human_readable_size = <<-EOS
60
- CASE
60
+ CASE
61
61
  WHEN sum(size) < 1024 THEN sum(size) || ' B'
62
62
  WHEN sum(size) >= 1024 AND sum(size) < (#{mega}) THEN ROUND((CAST(sum(size) AS REAL) / 1024), 2) || ' KB'
63
63
  WHEN sum(size) >= (#{mega}) AND sum(size) < (#{giga}) THEN ROUND((CAST(sum(size) AS REAL) / (#{mega})), 2) || ' MB'
64
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'
65
+ WHEN sum(size) >= (#{tera}) THEN ROUND((CAST(sum(size) AS REAL) / (#{tera})), 2) || ' TB'
66
66
  END AS size
67
67
  EOS
68
68
 
@@ -101,6 +101,9 @@ module LogSense
101
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
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
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
+
104
107
  @statuses = db.execute "SELECT status, count(status) from LogLine where #{filter} group by status order by status"
105
108
 
106
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)"
@@ -113,24 +116,26 @@ module LogSense
113
116
 
114
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"
115
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
+
116
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]}"
117
123
 
118
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]}"
119
125
 
120
- @streaks = db.execute "SELECT ip, substr(datetime, 1, 10), path from LogLine order by ip, datetime"
126
+ @streaks = db.execute 'SELECT ip, substr(datetime, 1, 10), path from LogLine order by ip, datetime'
121
127
  data = {}
122
128
 
123
- self.instance_variables.each do |variable|
124
- var_as_symbol = variable.to_s[1..-1].to_sym
125
- data[var_as_symbol] = eval(variable.to_s)
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)
126
132
  end
133
+
127
134
  data
128
135
  end
129
136
 
130
- private
131
-
132
- def self.date_intersect date1, date2, method
133
- if date1 and date2
137
+ def self.date_intersect(date1, date2, method)
138
+ if date1 && date2
134
139
  [date1, date2].send(method)
135
140
  elsif date1
136
141
  date1
@@ -140,4 +145,3 @@ module LogSense
140
145
  end
141
146
  end
142
147
  end
143
-
@@ -44,7 +44,7 @@ module LogSense
44
44
 
45
45
  attr_reader :format
46
46
 
47
- def initialize
47
+ def initialize
48
48
  @format = /#{IP} #{IDENT} #{USERID} \[#{TIMESTAMP}\] "(#{METHOD} #{URL} #{PROTOCOL}|-|.+)" #{RETURN_CODE} #{SIZE} "#{REFERER}" "#{USER_AGENT}"/
49
49
  end
50
50
 
@@ -82,7 +82,7 @@ module LogSense
82
82
  line_number
83
83
  )
84
84
  rescue StandardError => e
85
- warn.puts e.message
85
+ $stderr.puts e.message
86
86
  end
87
87
  end
88
88
  end