request-log-analyzer 1.0.2 → 1.6.3

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.
Files changed (144) hide show
  1. data/.gitignore +10 -0
  2. data/DESIGN.rdoc +41 -0
  3. data/LICENSE +4 -4
  4. data/README.rdoc +38 -0
  5. data/Rakefile +6 -3
  6. data/bin/request-log-analyzer +70 -72
  7. data/lib/cli/command_line_arguments.rb +53 -53
  8. data/lib/cli/database_console.rb +26 -0
  9. data/lib/cli/database_console_init.rb +43 -0
  10. data/lib/cli/progressbar.rb +166 -189
  11. data/lib/cli/tools.rb +49 -0
  12. data/lib/request_log_analyzer/aggregator/database_inserter.rb +83 -0
  13. data/lib/request_log_analyzer/aggregator/echo.rb +17 -12
  14. data/lib/request_log_analyzer/aggregator/summarizer.rb +101 -63
  15. data/lib/request_log_analyzer/{aggregator/base.rb → aggregator.rb} +17 -13
  16. data/lib/request_log_analyzer/controller.rb +251 -98
  17. data/lib/request_log_analyzer/database/base.rb +114 -0
  18. data/lib/request_log_analyzer/database/connection.rb +38 -0
  19. data/lib/request_log_analyzer/database/request.rb +22 -0
  20. data/lib/request_log_analyzer/database/source.rb +13 -0
  21. data/lib/request_log_analyzer/database/warning.rb +14 -0
  22. data/lib/request_log_analyzer/database.rb +102 -0
  23. data/lib/request_log_analyzer/file_format/amazon_s3.rb +74 -0
  24. data/lib/request_log_analyzer/file_format/apache.rb +147 -0
  25. data/lib/request_log_analyzer/file_format/delayed_job.rb +55 -0
  26. data/lib/request_log_analyzer/file_format/merb.rb +65 -29
  27. data/lib/request_log_analyzer/file_format/mysql.rb +101 -0
  28. data/lib/request_log_analyzer/file_format/postgresql.rb +68 -0
  29. data/lib/request_log_analyzer/file_format/rack.rb +9 -0
  30. data/lib/request_log_analyzer/file_format/rails.rb +164 -78
  31. data/lib/request_log_analyzer/file_format/rails3.rb +86 -0
  32. data/lib/request_log_analyzer/file_format/rails_development.rb +12 -0
  33. data/lib/request_log_analyzer/file_format.rb +252 -58
  34. data/lib/request_log_analyzer/filter/anonymize.rb +39 -0
  35. data/lib/request_log_analyzer/filter/field.rb +19 -13
  36. data/lib/request_log_analyzer/filter/timespan.rb +25 -12
  37. data/lib/request_log_analyzer/filter.rb +30 -0
  38. data/lib/request_log_analyzer/line_definition.rb +69 -96
  39. data/lib/request_log_analyzer/log_processor.rb +31 -53
  40. data/lib/request_log_analyzer/mailer.rb +65 -0
  41. data/lib/request_log_analyzer/output/fancy_html.rb +49 -0
  42. data/lib/request_log_analyzer/output/fixed_width.rb +220 -0
  43. data/lib/request_log_analyzer/output/html.rb +187 -0
  44. data/lib/request_log_analyzer/output.rb +117 -0
  45. data/lib/request_log_analyzer/request.rb +125 -40
  46. data/lib/request_log_analyzer/source/database_loader.rb +87 -0
  47. data/lib/request_log_analyzer/source/log_parser.rb +297 -0
  48. data/lib/request_log_analyzer/source.rb +72 -0
  49. data/lib/request_log_analyzer/tracker/duration.rb +28 -64
  50. data/lib/request_log_analyzer/tracker/frequency.rb +108 -0
  51. data/lib/request_log_analyzer/tracker/hourly_spread.rb +76 -49
  52. data/lib/request_log_analyzer/tracker/numeric_value.rb +223 -0
  53. data/lib/request_log_analyzer/tracker/timespan.rb +54 -27
  54. data/lib/request_log_analyzer/tracker/traffic.rb +40 -0
  55. data/lib/request_log_analyzer/tracker.rb +101 -0
  56. data/lib/request_log_analyzer.rb +43 -13
  57. data/request-log-analyzer.gemspec +41 -0
  58. data/spec/database.yml +23 -0
  59. data/spec/fixtures/apache_combined.log +5 -0
  60. data/spec/fixtures/apache_common.log +10 -0
  61. data/spec/fixtures/decompression.log +12 -0
  62. data/spec/fixtures/decompression.log.bz2 +0 -0
  63. data/spec/fixtures/decompression.log.gz +0 -0
  64. data/spec/fixtures/decompression.log.zip +0 -0
  65. data/spec/fixtures/decompression.tar.gz +0 -0
  66. data/spec/fixtures/decompression.tgz +0 -0
  67. data/spec/fixtures/header_and_footer.log +6 -0
  68. data/spec/fixtures/merb_prefixed.log +9 -0
  69. data/spec/fixtures/mysql_slow_query.log +110 -0
  70. data/spec/fixtures/postgresql.log +2980 -0
  71. data/spec/fixtures/rails.db +0 -0
  72. data/spec/fixtures/rails_22.log +1 -1
  73. data/spec/fixtures/sinatra.log +99 -0
  74. data/spec/integration/command_line_usage_spec.rb +84 -0
  75. data/spec/integration/mailer_spec.rb +179 -0
  76. data/spec/integration/munin_plugins_rails_spec.rb +58 -0
  77. data/spec/integration/scout_spec.rb +152 -0
  78. data/spec/lib/helpers.rb +72 -0
  79. data/spec/lib/macros.rb +18 -0
  80. data/spec/lib/matchers.rb +77 -0
  81. data/spec/lib/mocks.rb +77 -0
  82. data/spec/lib/testing_format.rb +46 -0
  83. data/spec/spec_helper.rb +16 -59
  84. data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
  85. data/spec/unit/aggregator/summarizer_spec.rb +26 -0
  86. data/spec/unit/controller/controller_spec.rb +41 -0
  87. data/spec/unit/controller/log_processor_spec.rb +18 -0
  88. data/spec/unit/database/base_class_spec.rb +183 -0
  89. data/spec/unit/database/connection_spec.rb +34 -0
  90. data/spec/unit/database/database_spec.rb +133 -0
  91. data/spec/unit/file_format/amazon_s3_format_spec.rb +67 -0
  92. data/spec/unit/file_format/apache_format_spec.rb +203 -0
  93. data/spec/unit/file_format/common_regular_expressions_spec.rb +53 -0
  94. data/spec/unit/file_format/delayed_job_format_spec.rb +83 -0
  95. data/spec/unit/file_format/file_format_api_spec.rb +69 -0
  96. data/spec/unit/file_format/format_autodetection_spec.rb +40 -0
  97. data/spec/unit/file_format/line_definition_spec.rb +75 -0
  98. data/spec/unit/file_format/merb_format_spec.rb +52 -0
  99. data/spec/unit/file_format/mysql_format_spec.rb +154 -0
  100. data/spec/unit/file_format/postgresql_format_spec.rb +65 -0
  101. data/spec/unit/file_format/rack_format_spec.rb +50 -0
  102. data/spec/unit/file_format/rails3_format_spec.rb +120 -0
  103. data/spec/unit/file_format/rails_format_spec.rb +180 -0
  104. data/spec/unit/filter/anonymize_filter_spec.rb +21 -0
  105. data/spec/unit/filter/field_filter_spec.rb +66 -0
  106. data/spec/unit/filter/filter_spec.rb +17 -0
  107. data/spec/unit/filter/timespan_filter_spec.rb +58 -0
  108. data/spec/unit/mailer_spec.rb +42 -0
  109. data/spec/unit/request_spec.rb +111 -0
  110. data/spec/unit/source/log_parser_spec.rb +119 -0
  111. data/spec/unit/tracker/duration_tracker_spec.rb +49 -0
  112. data/spec/unit/tracker/frequency_tracker_spec.rb +88 -0
  113. data/spec/unit/tracker/hourly_spread_spec.rb +79 -0
  114. data/spec/unit/tracker/numeric_value_tracker_spec.rb +166 -0
  115. data/spec/unit/tracker/timespan_tracker_spec.rb +73 -0
  116. data/spec/unit/tracker/tracker_api_spec.rb +125 -0
  117. data/spec/unit/tracker/traffic_tracker_spec.rb +28 -0
  118. data/tasks/github-gem.rake +290 -139
  119. data/tasks/request_log_analyzer.rake +23 -7
  120. metadata +221 -94
  121. data/DESIGN +0 -14
  122. data/HACKING +0 -7
  123. data/README.textile +0 -36
  124. data/lib/cli/bashcolorizer.rb +0 -60
  125. data/lib/request_log_analyzer/aggregator/database.rb +0 -148
  126. data/lib/request_log_analyzer/filter/base.rb +0 -29
  127. data/lib/request_log_analyzer/log_parser.rb +0 -173
  128. data/lib/request_log_analyzer/source/base.rb +0 -42
  129. data/lib/request_log_analyzer/source/log_file.rb +0 -170
  130. data/lib/request_log_analyzer/tracker/base.rb +0 -54
  131. data/lib/request_log_analyzer/tracker/category.rb +0 -71
  132. data/spec/controller_spec.rb +0 -40
  133. data/spec/database_inserter_spec.rb +0 -101
  134. data/spec/file_format_spec.rb +0 -78
  135. data/spec/file_formats/spec_format.rb +0 -26
  136. data/spec/filter_spec.rb +0 -137
  137. data/spec/line_definition_spec.rb +0 -124
  138. data/spec/log_parser_spec.rb +0 -68
  139. data/spec/log_processor_spec.rb +0 -57
  140. data/spec/merb_format_spec.rb +0 -38
  141. data/spec/rails_format_spec.rb +0 -76
  142. data/spec/request_spec.rb +0 -72
  143. data/spec/summarizer_spec.rb +0 -9
  144. data/tasks/rspec.rake +0 -6
@@ -7,230 +7,207 @@
7
7
  #
8
8
  # You can redistribute it and/or modify it under the terms
9
9
  # of Ruby's license.
10
- #
11
10
 
12
- class ProgressBar
13
- VERSION = "0.9"
14
-
15
- def initialize (title, total, out = STDERR)
16
- @title = title
17
- @total = total
18
- @out = out
19
- @terminal_width = 80
20
- @bar_mark = '='
21
- @current = 0
22
- @previous = 0
23
- @finished_p = false
24
- @start_time = Time.now
25
- @previous_time = @start_time
26
- @title_width = 24
27
- @format = "%-#{@title_width}s %3d%% %s %s"
28
- @format_arguments = [:title, :percentage, :bar, :stat]
29
- clear
30
- show
31
- end
32
- attr_reader :title
33
- attr_reader :current
34
- attr_reader :total
35
- attr_accessor :start_time
36
-
37
- private
38
- def fmt_bar
39
- bar_width = do_percentage * @terminal_width / 100
40
- sprintf("[%s%s]",
41
- @bar_mark * bar_width,
42
- " " * (@terminal_width - bar_width))
43
- end
11
+ module CommandLine
12
+ class ProgressBar
13
+ VERSION = "0.9"
14
+
15
+ def initialize (title, total, out = STDERR)
16
+ @title = title
17
+ @total = total
18
+ @out = out
19
+ @terminal_width = 80
20
+ @bar_mark = '='
21
+ @current = 0
22
+ @previous = 0
23
+ @finished_p = false
24
+ @start_time = Time.now
25
+ @previous_time = @start_time
26
+ @title_width = 24
27
+ @format = "%-#{@title_width}s %3d%% %s %s"
28
+ @format_arguments = [:title, :percentage, :bar, :stat]
29
+ clear
30
+ show
31
+ end
32
+ attr_reader :title
33
+ attr_reader :current
34
+ attr_reader :total
35
+ attr_accessor :start_time
36
+
37
+ private
38
+ def fmt_bar
39
+ bar_width = do_percentage * @terminal_width / 100
40
+ sprintf("[%s%s]",
41
+ @bar_mark * bar_width,
42
+ " " * (@terminal_width - bar_width))
43
+ end
44
44
 
45
- def fmt_percentage
46
- do_percentage
47
- end
45
+ def fmt_percentage
46
+ do_percentage
47
+ end
48
48
 
49
- def fmt_stat
50
- if @finished_p then elapsed else eta end
51
- end
49
+ def fmt_stat
50
+ if @finished_p then elapsed else eta end
51
+ end
52
52
 
53
- def fmt_stat_for_file_transfer
54
- if @finished_p then
55
- sprintf("%s %s %s", bytes, transfer_rate, elapsed)
56
- else
57
- sprintf("%s %s %s", bytes, transfer_rate, eta)
53
+ def fmt_stat_for_file_transfer
54
+ if @finished_p then
55
+ sprintf("%s %s %s", bytes, transfer_rate, elapsed)
56
+ else
57
+ sprintf("%s %s %s", bytes, transfer_rate, eta)
58
+ end
58
59
  end
59
- end
60
60
 
61
- def fmt_title
62
- @title[0,(@title_width - 1)] + ":"
63
- end
61
+ def fmt_title
62
+ @title[0,(@title_width - 1)] + ":"
63
+ end
64
+
65
+ def convert_bytes (bytes)
66
+ if bytes < 1024
67
+ sprintf("%6dB", bytes)
68
+ elsif bytes < 1024 * 1000 # 1000kb
69
+ sprintf("%5.1fKB", bytes.to_f / 1024)
70
+ elsif bytes < 1024 * 1024 * 1000 # 1000mb
71
+ sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
72
+ else
73
+ sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
74
+ end
75
+ end
64
76
 
65
- def convert_bytes (bytes)
66
- if bytes < 1024
67
- sprintf("%6dB", bytes)
68
- elsif bytes < 1024 * 1000 # 1000kb
69
- sprintf("%5.1fKB", bytes.to_f / 1024)
70
- elsif bytes < 1024 * 1024 * 1000 # 1000mb
71
- sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
72
- else
73
- sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
77
+ def transfer_rate
78
+ bytes_per_second = @current.to_f / (Time.now - @start_time)
79
+ sprintf("%s/s", convert_bytes(bytes_per_second))
74
80
  end
75
- end
76
81
 
77
- def transfer_rate
78
- bytes_per_second = @current.to_f / (Time.now - @start_time)
79
- sprintf("%s/s", convert_bytes(bytes_per_second))
80
- end
82
+ def bytes
83
+ convert_bytes(@current)
84
+ end
81
85
 
82
- def bytes
83
- convert_bytes(@current)
84
- end
86
+ def format_time (t)
87
+ t = t.to_i
88
+ sec = t % 60
89
+ min = (t / 60) % 60
90
+ hour = t / 3600
91
+ sprintf("%02d:%02d:%02d", hour, min, sec);
92
+ end
85
93
 
86
- def format_time (t)
87
- t = t.to_i
88
- sec = t % 60
89
- min = (t / 60) % 60
90
- hour = t / 3600
91
- sprintf("%02d:%02d:%02d", hour, min, sec);
92
- end
94
+ # ETA stands for Estimated Time of Arrival.
95
+ def eta
96
+ if @current == 0
97
+ "ETA: --:--:--"
98
+ else
99
+ elapsed = Time.now - @start_time
100
+ eta = elapsed * @total / @current - elapsed;
101
+ sprintf("ETA: %s", format_time(eta))
102
+ end
103
+ end
93
104
 
94
- # ETA stands for Estimated Time of Arrival.
95
- def eta
96
- if @current == 0
97
- "ETA: --:--:--"
98
- else
105
+ def elapsed
99
106
  elapsed = Time.now - @start_time
100
- eta = elapsed * @total / @current - elapsed;
101
- sprintf("ETA: %s", format_time(eta))
107
+ sprintf("Time: %s", format_time(elapsed))
102
108
  end
103
- end
104
-
105
- def elapsed
106
- elapsed = Time.now - @start_time
107
- sprintf("Time: %s", format_time(elapsed))
108
- end
109
-
110
- def eol
111
- if @finished_p then "\n" else "\r" end
112
- end
113
109
 
114
- def do_percentage
115
- if @total.zero?
116
- 100
117
- else
118
- @current * 100 / @total
110
+ def eol
111
+ if @finished_p then "\n" else "\r" end
119
112
  end
120
- end
121
113
 
122
- def get_width
123
- # FIXME: I don't know how portable it is.
124
- default_width = 80
125
- begin
126
- tiocgwinsz = 0x5413
127
- data = [0, 0, 0, 0].pack("SSSS")
128
- if @out.ioctl(tiocgwinsz, data) >= 0 then
129
- rows, cols, xpixels, ypixels = data.unpack("SSSS")
130
- if cols >= 0 then cols else default_width end
114
+ def do_percentage
115
+ if @total.zero?
116
+ 100
131
117
  else
132
- default_width
118
+ @current * 100 / @total
133
119
  end
134
- rescue Exception
135
- default_width
136
120
  end
137
- end
138
121
 
139
- def show
140
- arguments = @format_arguments.map {|method|
141
- method = sprintf("fmt_%s", method)
142
- send(method)
143
- }
144
- line = sprintf(@format, *arguments)
145
-
146
- width = get_width
147
- if line.length == width - 1
148
- @out.print(line + eol)
149
- @out.flush
150
- elsif line.length >= width
151
- @terminal_width = [@terminal_width - (line.length - width + 1), 0].max
152
- if @terminal_width == 0 then @out.print(line + eol) else show end
153
- else # line.length < width - 1
154
- @terminal_width += width - line.length + 1
155
- show
122
+ def show
123
+ arguments = @format_arguments.map {|method|
124
+ method = sprintf("fmt_%s", method)
125
+ send(method)
126
+ }
127
+ line = sprintf(@format, *arguments)
128
+
129
+ width = terminal_width(80)
130
+ if line.length == width - 1
131
+ @out.print(line + eol)
132
+ @out.flush
133
+ elsif line.length >= width
134
+ @terminal_width = [@terminal_width - (line.length - width + 1), 0].max
135
+ if @terminal_width == 0 then @out.print(line + eol) else show end
136
+ else # line.length < width - 1
137
+ @terminal_width += width - line.length + 1
138
+ show
139
+ end
140
+ @previous_time = Time.now
156
141
  end
157
- @previous_time = Time.now
158
- end
159
142
 
160
- def show_if_needed
161
- if @total.zero?
162
- cur_percentage = 100
163
- prev_percentage = 0
164
- else
165
- cur_percentage = (@current * 100 / @total).to_i
166
- prev_percentage = (@previous * 100 / @total).to_i
167
- end
143
+ def show_if_needed
144
+ if @total.zero?
145
+ cur_percentage = 100
146
+ prev_percentage = 0
147
+ else
148
+ cur_percentage = (@current * 100 / @total).to_i
149
+ prev_percentage = (@previous * 100 / @total).to_i
150
+ end
168
151
 
169
- # Use "!=" instead of ">" to support negative changes
170
- if cur_percentage != prev_percentage ||
171
- Time.now - @previous_time >= 1 || @finished_p
172
- show
152
+ # Use "!=" instead of ">" to support negative changes
153
+ if cur_percentage != prev_percentage ||
154
+ Time.now - @previous_time >= 1 || @finished_p
155
+ show
156
+ end
173
157
  end
174
- end
175
158
 
176
- public
177
- def clear
178
- @out.print "\r"
179
- @out.print(" " * (get_width - 1))
180
- @out.print "\r"
181
- end
159
+ public
160
+ def clear
161
+ @out.print "\r"
162
+ @out.print(" " * (terminal_width(80) - 1))
163
+ @out.print "\r"
164
+ end
182
165
 
183
- def finish
184
- @current = @total
185
- @finished_p = true
186
- show
187
- end
166
+ def finish
167
+ @current = @total
168
+ @finished_p = true
169
+ show
170
+ end
188
171
 
189
- def finished?
190
- @finished_p
191
- end
172
+ def finished?
173
+ @finished_p
174
+ end
192
175
 
193
- def file_transfer_mode
194
- @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
195
- end
176
+ def file_transfer_mode
177
+ @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
178
+ end
196
179
 
197
- def format= (format)
198
- @format = format
199
- end
180
+ def format= (format)
181
+ @format = format
182
+ end
200
183
 
201
- def format_arguments= (arguments)
202
- @format_arguments = arguments
203
- end
184
+ def format_arguments= (arguments)
185
+ @format_arguments = arguments
186
+ end
204
187
 
205
- def halt
206
- @finished_p = true
207
- show
208
- end
188
+ def halt
189
+ @finished_p = true
190
+ show
191
+ end
209
192
 
210
- def inc (step = 1)
211
- @current += step
212
- @current = @total if @current > @total
213
- show_if_needed
214
- @previous = @current
215
- end
193
+ def inc (step = 1)
194
+ @current += step
195
+ @current = @total if @current > @total
196
+ show_if_needed
197
+ @previous = @current
198
+ end
216
199
 
217
- def set (count)
218
- count = 0 if count < 0
219
- count = @total if count > @total
220
-
221
- @current = count
222
- show_if_needed
223
- @previous = @current
224
- end
200
+ def set (count)
201
+ count = 0 if count < 0
202
+ count = @total if count > @total
225
203
 
226
- def inspect
227
- "#<ProgressBar:#{@current}/#{@total}>"
228
- end
229
- end
204
+ @current = count
205
+ show_if_needed
206
+ @previous = @current
207
+ end
230
208
 
231
- class ReversedProgressBar < ProgressBar
232
- def do_percentage
233
- 100 - super
209
+ def inspect
210
+ "#<ProgressBar:#{@current}/#{@total}>"
211
+ end
234
212
  end
235
213
  end
236
-
data/lib/cli/tools.rb ADDED
@@ -0,0 +1,49 @@
1
+ # Try to determine the terminal with.
2
+ # If it is not possible to to so, it returns the default_width.
3
+ # <tt>default_width</tt> Defaults to 81
4
+ def terminal_width(default_width = 81)
5
+
6
+ begin
7
+ tiocgwinsz = 0x5413
8
+ data = [0, 0, 0, 0].pack("SSSS")
9
+ if !RUBY_PLATFORM.include?('java') && @out.ioctl(tiocgwinsz, data) >= 0 # JRuby crashes on ioctl
10
+ rows, cols, xpixels, ypixels = data.unpack("SSSS")
11
+ raise unless cols > 0
12
+ cols
13
+ else
14
+ raise
15
+ end
16
+ rescue
17
+ begin
18
+ IO.popen('stty -a 2>&1') do |pipe|
19
+ column_line = pipe.detect { |line| /(\d+) columns/ =~ line }
20
+ raise unless column_line
21
+ $1.to_i
22
+ end
23
+ rescue
24
+ default_width
25
+ end
26
+ end
27
+ end
28
+
29
+ # Copies request-log-analyzer analyzer rake tasks into the /lib/tasks folder of a project, for easy access and
30
+ # environment integration.
31
+ # <tt>install_type</tt> Type of project to install into. Defaults to :rails.
32
+ # Raises if it cannot find the project folder or if the install_type is now known.
33
+ def install_rake_tasks(install_type = :rails)
34
+ if install_type.to_sym == :rails
35
+ require 'ftools'
36
+ if File.directory?('./lib/tasks/')
37
+ File.copy(File.dirname(__FILE__) + '/../../tasks/request_log_analyzer.rake', './lib/tasks/request_log_analyze.rake')
38
+ puts "Installed rake tasks."
39
+ puts "To use, run: rake rla:report"
40
+ else
41
+ puts "Cannot find /lib/tasks folder. Are you in your Rails directory?"
42
+ puts "Installation aborted."
43
+ end
44
+ else
45
+ raise "Cannot perform this install type! (#{install_type.to_s})"
46
+ end
47
+ end
48
+
49
+
@@ -0,0 +1,83 @@
1
+
2
+ module RequestLogAnalyzer::Aggregator
3
+
4
+ # The database aggregator will create an SQLite3 database with all parsed request information.
5
+ #
6
+ # The prepare method will create a database schema according to the file format definitions.
7
+ # It will also create ActiveRecord::Base subclasses to interact with the created tables.
8
+ # Then, the aggregate method will be called for every parsed request. The information of
9
+ # these requests is inserted into the tables using the ActiveRecord classes.
10
+ #
11
+ # A requests table will be created, in which a record is inserted for every parsed request.
12
+ # For every line type, a separate table will be created with a request_id field to point to
13
+ # the request record, and a field for every parsed value. Finally, a warnings table will be
14
+ # created to log all parse warnings.
15
+ class DatabaseInserter < Base
16
+
17
+ attr_reader :request_count, :sources, :database
18
+
19
+ # Establishes a connection to the database and creates the necessary database schema for the
20
+ # current file format
21
+ def prepare
22
+ @sources = {}
23
+ @database = RequestLogAnalyzer::Database.new(options[:database])
24
+ @database.file_format = source.file_format
25
+
26
+ database.drop_database_schema! if options[:reset_database]
27
+ database.create_database_schema!
28
+ end
29
+
30
+ # Aggregates a request into the database
31
+ # This will create a record in the requests table and create a record for every line that has been parsed,
32
+ # in which the captured values will be stored.
33
+ def aggregate(request)
34
+ @request_object = RequestLogAnalyzer::Database::Request.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
35
+ request.lines.each do |line|
36
+ class_columns = database.get_class(line[:line_type]).column_names.reject { |column| ['id', 'source_id', 'request_id'].include?(column) }
37
+ attributes = Hash[*line.select { |(k, v)| class_columns.include?(k.to_s) }.flatten]
38
+ attributes[:source_id] = @sources[line[:source]].id if @sources[line[:source]]
39
+ @request_object.send("#{line[:line_type]}_lines").build(attributes)
40
+ end
41
+ @request_object.save!
42
+ rescue SQLite3::SQLException => e
43
+ raise Interrupt, e.message
44
+ end
45
+
46
+ # Finalizes the aggregator by closing the connection to the database
47
+ def finalize
48
+ @request_count = RequestLogAnalyzer::Database::Request.count
49
+ database.disconnect
50
+ database.remove_orm_classes!
51
+ end
52
+
53
+ # Records w warining in the warnings table.
54
+ def warning(type, message, lineno)
55
+ RequestLogAnalyzer::Database::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
56
+ end
57
+
58
+ # Records source changes in the sources table
59
+ def source_change(change, filename)
60
+ if File.exist?(filename)
61
+ case change
62
+ when :started
63
+ @sources[filename] = RequestLogAnalyzer::Database::Source.create!(:filename => filename)
64
+ when :finished
65
+ @sources[filename].update_attributes!(:filesize => File.size(filename), :mtime => File.mtime(filename))
66
+ end
67
+ end
68
+ end
69
+
70
+ # Prints a short report of what has been inserted into the database
71
+ def report(output)
72
+ output.title('Request database created')
73
+
74
+ output << "A database file has been created with all parsed request information.\n"
75
+ output << "#{@request_count} requests have been added to the database.\n"
76
+ output << "\n"
77
+ output << "To open a Ruby console to inspect the database, run the following command.\n"
78
+ output << output.colorize(" $ request-log-analyzer console -d #{options[:database]}\n", :bold)
79
+ output << "\n"
80
+ end
81
+
82
+ end
83
+ end
@@ -1,24 +1,29 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
2
 
3
+ # Echo Aggregator. Writes everything to the screen when it is passed to this aggregator
3
4
  class Echo < Base
4
-
5
+
6
+ attr_accessor :warnings
7
+
5
8
  def prepare
6
- @warnings = ""
9
+ @warnings = []
7
10
  end
8
-
11
+
12
+ # Display every parsed line immediately to the terminal
9
13
  def aggregate(request)
10
- puts "\nRequest: " + request.inspect
14
+ puts "\nRequest: \n" + request.lines.map { |l|
15
+ "\t#{l[:lineno]}:#{l[:line_type]}: #{l.reject { |(k,v)| [:lineno, :line_type].include?(k) }.inspect}" }.join("\n")
11
16
  end
12
-
17
+
18
+ # Capture all warnings during parsing
13
19
  def warning(type, message, lineno)
14
- @warnings << "WARNING #{type.inspect} on line #{lineno}: #{message}\n"
20
+ @warnings << "WARNING #{type.inspect} on line #{lineno}: #{message}"
15
21
  end
16
-
17
- def report(output=STDOUT, report_width = 80, color = false)
18
- output << "\n"
19
- output << "Warnings during parsing:\n"
20
- output << green("━" * report_width, color) + "\n"
21
- output << @warnings + "\n"
22
+
23
+ # Display every warning in the report when finished parsing
24
+ def report(output)
25
+ output.title("Warnings during parsing")
26
+ @warnings.each { |w| output.puts(w) }
22
27
  end
23
28
 
24
29
  end