request-log-analyzer 1.7.0 → 1.10.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.
Files changed (88) hide show
  1. data/.gitignore +4 -1
  2. data/DESIGN.rdoc +0 -1
  3. data/Gemfile +2 -0
  4. data/README.rdoc +16 -5
  5. data/bin/request-log-analyzer +4 -2
  6. data/lib/cli/database_console_init.rb +1 -1
  7. data/lib/cli/tools.rb +2 -1
  8. data/lib/mixins/gets_memory_protection.rb +1 -1
  9. data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -2
  10. data/lib/request_log_analyzer/aggregator.rb +3 -3
  11. data/lib/request_log_analyzer/controller.rb +42 -36
  12. data/lib/request_log_analyzer/database.rb +5 -3
  13. data/lib/request_log_analyzer/file_format/apache.rb +19 -28
  14. data/lib/request_log_analyzer/file_format/delayed_job2.rb +38 -0
  15. data/lib/request_log_analyzer/file_format/delayed_job21.rb +39 -0
  16. data/lib/request_log_analyzer/file_format/haproxy.rb +138 -0
  17. data/lib/request_log_analyzer/file_format/oink.rb +96 -0
  18. data/lib/request_log_analyzer/file_format/postgresql.rb +7 -6
  19. data/lib/request_log_analyzer/file_format/rails.rb +4 -4
  20. data/lib/request_log_analyzer/file_format/rails3.rb +34 -11
  21. data/lib/request_log_analyzer/file_format/w3c.rb +56 -0
  22. data/lib/request_log_analyzer/file_format.rb +33 -10
  23. data/lib/request_log_analyzer/filter.rb +3 -5
  24. data/lib/request_log_analyzer/output/fancy_html.rb +0 -5
  25. data/lib/request_log_analyzer/output.rb +6 -7
  26. data/lib/request_log_analyzer/request.rb +17 -3
  27. data/lib/request_log_analyzer/source/log_parser.rb +3 -1
  28. data/lib/request_log_analyzer/source.rb +2 -6
  29. data/lib/request_log_analyzer/tracker/duration.rb +7 -0
  30. data/lib/request_log_analyzer/tracker/numeric_value.rb +123 -12
  31. data/lib/request_log_analyzer/tracker/traffic.rb +7 -0
  32. data/lib/request_log_analyzer/tracker.rb +6 -5
  33. data/lib/request_log_analyzer.rb +36 -17
  34. data/request-log-analyzer.gemspec +9 -6
  35. data/spec/fixtures/oink_22.log +19 -0
  36. data/spec/fixtures/oink_22_failure.log +17 -0
  37. data/spec/fixtures/postgresql.log +29 -2980
  38. data/spec/integration/command_line_usage_spec.rb +4 -4
  39. data/spec/integration/mailer_spec.rb +20 -4
  40. data/spec/integration/munin_plugins_rails_spec.rb +1 -1
  41. data/spec/integration/scout_spec.rb +1 -1
  42. data/spec/lib/helpers.rb +2 -2
  43. data/spec/lib/macros.rb +1 -1
  44. data/spec/lib/matchers.rb +1 -1
  45. data/spec/lib/mocks.rb +1 -1
  46. data/spec/spec_helper.rb +10 -10
  47. data/spec/unit/aggregator/database_inserter_spec.rb +1 -1
  48. data/spec/unit/aggregator/summarizer_spec.rb +1 -1
  49. data/spec/unit/controller/controller_spec.rb +1 -1
  50. data/spec/unit/controller/log_processor_spec.rb +1 -1
  51. data/spec/unit/database/base_class_spec.rb +1 -1
  52. data/spec/unit/database/connection_spec.rb +1 -1
  53. data/spec/unit/database/database_spec.rb +1 -1
  54. data/spec/unit/file_format/amazon_s3_format_spec.rb +1 -1
  55. data/spec/unit/file_format/apache_format_spec.rb +18 -1
  56. data/spec/unit/file_format/common_regular_expressions_spec.rb +1 -1
  57. data/spec/unit/file_format/delayed_job21_format_spec.rb +60 -0
  58. data/spec/unit/file_format/delayed_job2_format_spec.rb +60 -0
  59. data/spec/unit/file_format/delayed_job_format_spec.rb +2 -2
  60. data/spec/unit/file_format/file_format_api_spec.rb +2 -2
  61. data/spec/unit/file_format/format_autodetection_spec.rb +7 -7
  62. data/spec/unit/file_format/haproxy_format_spec.rb +84 -0
  63. data/spec/unit/file_format/line_definition_spec.rb +1 -1
  64. data/spec/unit/file_format/merb_format_spec.rb +1 -1
  65. data/spec/unit/file_format/mysql_format_spec.rb +1 -1
  66. data/spec/unit/file_format/oink_format_spec.rb +105 -0
  67. data/spec/unit/file_format/postgresql_format_spec.rb +24 -46
  68. data/spec/unit/file_format/rack_format_spec.rb +1 -1
  69. data/spec/unit/file_format/rails3_format_spec.rb +41 -14
  70. data/spec/unit/file_format/rails_format_spec.rb +11 -1
  71. data/spec/unit/file_format/w3c_format_spec.rb +46 -0
  72. data/spec/unit/filter/anonymize_filter_spec.rb +1 -1
  73. data/spec/unit/filter/field_filter_spec.rb +1 -1
  74. data/spec/unit/filter/filter_spec.rb +1 -1
  75. data/spec/unit/filter/timespan_filter_spec.rb +1 -1
  76. data/spec/unit/mailer_spec.rb +1 -1
  77. data/spec/unit/request_spec.rb +1 -1
  78. data/spec/unit/source/log_parser_spec.rb +1 -1
  79. data/spec/unit/tracker/duration_tracker_spec.rb +4 -2
  80. data/spec/unit/tracker/frequency_tracker_spec.rb +1 -1
  81. data/spec/unit/tracker/hourly_spread_spec.rb +1 -1
  82. data/spec/unit/tracker/numeric_value_tracker_spec.rb +38 -17
  83. data/spec/unit/tracker/timespan_tracker_spec.rb +1 -1
  84. data/spec/unit/tracker/tracker_api_spec.rb +1 -1
  85. data/spec/unit/tracker/traffic_tracker_spec.rb +1 -1
  86. data/tasks/github-gem.rake +97 -60
  87. data/tasks/request_log_analyzer.rake +102 -0
  88. metadata +198 -153
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'rake/tasklib'
4
4
  require 'date'
5
- require 'git'
5
+ require 'set'
6
6
 
7
7
  module GithubGem
8
8
 
@@ -24,7 +24,7 @@ module GithubGem
24
24
 
25
25
  class RakeTasks
26
26
 
27
- attr_reader :gemspec, :modified_files, :git
27
+ attr_reader :gemspec, :modified_files
28
28
  attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
29
29
 
30
30
  # Initializes the settings, yields itself for configuration
@@ -33,7 +33,7 @@ module GithubGem
33
33
  @gemspec_file = GithubGem.detect_gemspec_file
34
34
  @task_namespace = task_namespace
35
35
  @main_include = GithubGem.detect_main_include
36
- @modified_files = []
36
+ @modified_files = Set.new
37
37
  @root_dir = Dir.pwd
38
38
  @test_pattern = 'test/**/*_test.rb'
39
39
  @spec_pattern = 'spec/**/*_spec.rb'
@@ -43,13 +43,16 @@ module GithubGem
43
43
 
44
44
  yield(self) if block_given?
45
45
 
46
- @git = Git.open(@root_dir)
47
46
  load_gemspec!
48
47
  define_tasks!
49
48
  end
50
49
 
51
50
  protected
52
51
 
52
+ def git
53
+ @git ||= ENV['GIT'] || 'git'
54
+ end
55
+
53
56
  # Define Unit test tasks
54
57
  def define_test_tasks!
55
58
  require 'rake/testtask'
@@ -68,23 +71,23 @@ module GithubGem
68
71
 
69
72
  # Defines RSpec tasks
70
73
  def define_rspec_tasks!
71
- require 'spec/rake/spectask'
74
+ require 'rspec/core/rake_task'
72
75
 
73
76
  namespace(:spec) do
74
77
  desc "Verify all RSpec examples for #{gemspec.name}"
75
- Spec::Rake::SpecTask.new(:basic) do |t|
76
- t.spec_files = FileList[spec_pattern]
78
+ RSpec::Core::RakeTask.new(:basic) do |t|
79
+ t.pattern = spec_pattern
77
80
  end
78
81
 
79
82
  desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
80
- Spec::Rake::SpecTask.new(:specdoc) do |t|
81
- t.spec_files = FileList[spec_pattern]
82
- t.spec_opts << '--format' << 'specdoc' << '--color'
83
+ RSpec::Core::RakeTask.new(:specdoc) do |t|
84
+ t.pattern = spec_pattern
85
+ t.rspec_opts = ['--format', 'documentation', '--color']
83
86
  end
84
87
 
85
88
  desc "Run RCov on specs for #{gemspec.name}"
86
- Spec::Rake::SpecTask.new(:rcov) do |t|
87
- t.spec_files = FileList[spec_pattern]
89
+ RSpec::Core::RakeTask.new(:rcov) do |t|
90
+ t.pattern = spec_pattern
88
91
  t.rcov = true
89
92
  t.rcov_opts = ['--exclude', '"spec/*,gems/*"', '--rails']
90
93
  end
@@ -127,8 +130,22 @@ module GithubGem
127
130
  release_tasks = [:release_checks, :set_version, :build, :github_release, :gemcutter_release]
128
131
  # release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
129
132
 
130
- desc "Release a new verison of the gem"
133
+ desc "Release a new version of the gem using the VERSION environment variable"
131
134
  task(:release => release_tasks) { release_task }
135
+
136
+ namespace(:release) do
137
+ desc "Release the next version of the gem, by incrementing the last version segment by 1"
138
+ task(:next => [:next_version] + release_tasks) { release_task }
139
+
140
+ desc "Release the next version of the gem, using a patch increment (0.0.1)"
141
+ task(:patch => [:next_patch_version] + release_tasks) { release_task }
142
+
143
+ desc "Release the next version of the gem, using a minor increment (0.1.0)"
144
+ task(:minor => [:next_minor_version] + release_tasks) { release_task }
145
+
146
+ desc "Release the next version of the gem, using a major increment (1.0.0)"
147
+ task(:major => [:next_major_version] + release_tasks) { release_task }
148
+ end
132
149
 
133
150
  # task(:check_rubyforge) { check_rubyforge_task }
134
151
  # task(:rubyforge_release) { rubyforge_release_task }
@@ -137,6 +154,11 @@ module GithubGem
137
154
  task(:tag_version) { tag_version_task }
138
155
  task(:commit_modified_files) { commit_modified_files_task }
139
156
 
157
+ task(:next_version) { next_version_task }
158
+ task(:next_patch_version) { next_version_task(:patch) }
159
+ task(:next_minor_version) { next_version_task(:minor) }
160
+ task(:next_major_version) { next_version_task(:major) }
161
+
140
162
  desc "Updates the gem release tasks with the latest version on Github"
141
163
  task(:update_tasks) { update_tasks_task }
142
164
  end
@@ -146,7 +168,7 @@ module GithubGem
146
168
  # in the repository and the spec/test file pattern.
147
169
  def manifest_task
148
170
  # Load all the gem's files using "git ls-files"
149
- repository_files = git.ls_files.keys
171
+ repository_files = `#{git} ls-files`.split("\n")
150
172
  test_files = Dir[test_pattern] + Dir[spec_pattern]
151
173
 
152
174
  update_gemspec(:files, repository_files)
@@ -160,6 +182,32 @@ module GithubGem
160
182
  sh "mv #{gemspec.name}-#{gemspec.version}.gem pkg/#{gemspec.name}-#{gemspec.version}.gem"
161
183
  end
162
184
 
185
+ def newest_version
186
+ `#{git} tag`.split("\n").map { |tag| tag.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max || Gem::Version.new('0.0.0')
187
+ end
188
+
189
+ def next_version(increment = nil)
190
+ next_version = newest_version.segments
191
+ increment_index = case increment
192
+ when :micro then 3
193
+ when :patch then 2
194
+ when :minor then 1
195
+ when :major then 0
196
+ else next_version.length - 1
197
+ end
198
+
199
+ next_version[increment_index] ||= 0
200
+ next_version[increment_index] = next_version[increment_index].succ
201
+ ((increment_index + 1)...next_version.length).each { |i| next_version[i] = 0 }
202
+
203
+ Gem::Version.new(next_version.join('.'))
204
+ end
205
+
206
+ def next_version_task(increment = nil)
207
+ ENV['VERSION'] = next_version(increment).version
208
+ puts "Releasing version #{ENV['VERSION']}..."
209
+ end
210
+
163
211
  # Updates the version number in the gemspec file, the VERSION constant in the main
164
212
  # include file and the contents of the VERSION file.
165
213
  def version_task
@@ -172,74 +220,58 @@ module GithubGem
172
220
 
173
221
  def check_version_task
174
222
  raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION'])
175
- proposed_version = Gem::Version.new(ENV['VERSION'] || gemspec.version)
176
- # Loads the latest version number using the created tags
177
- newest_version = git.tags.map { |tag| tag.name.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max
178
- raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version && newest_version >= proposed_version
223
+ proposed_version = Gem::Version.new((ENV['VERSION'] || gemspec.version).dup)
224
+ raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version >= proposed_version
179
225
  end
180
226
 
181
227
  # Checks whether the current branch is not diverged from the remote branch
182
228
  def check_not_diverged_task
183
- raise "The current branch is diverged from the remote branch!" if git.log.between('HEAD', git.remote(remote).branch(remote_branch).gcommit).any?
229
+ raise "The current branch is diverged from the remote branch!" if `#{git} rev-list HEAD..#{remote}/#{remote_branch}`.split("\n").any?
184
230
  end
185
231
 
186
232
  # Checks whether the repository status ic clean
187
233
  def check_clean_status_task
188
- raise "The current working copy contains modifications" if git.status.changed.any?
234
+ raise "The current working copy contains modifications" if `#{git} ls-files -m`.split("\n").any?
189
235
  end
190
236
 
191
237
  # Checks whether the current branch is correct
192
238
  def check_current_branch_task
193
- raise "Currently not on #{local_branch} branch!" unless git.branch.name == local_branch.to_s
239
+ raise "Currently not on #{local_branch} branch!" unless `#{git} branch`.split("\n").detect { |b| /^\* / =~ b } == "* #{local_branch}"
194
240
  end
195
241
 
196
242
  # Fetches the latest updates from Github
197
243
  def fetch_origin_task
198
- git.fetch('origin')
244
+ sh git, 'fetch', remote
199
245
  end
200
246
 
201
247
  # Commits every file that has been changed by the release task.
202
248
  def commit_modified_files_task
203
- if modified_files.any?
204
- modified_files.each { |file| git.add(file) }
205
- git.commit("Released #{gemspec.name} gem version #{gemspec.version}")
249
+ really_modified = `#{git} ls-files -m #{modified_files.entries.join(' ')}`.split("\n")
250
+ if really_modified.any?
251
+ really_modified.each { |file| sh git, 'add', file }
252
+ sh git, 'commit', '-m', "Released #{gemspec.name} gem version #{gemspec.version}."
206
253
  end
207
254
  end
208
255
 
209
256
  # Adds a tag for the released version
210
257
  def tag_version_task
211
- git.add_tag("#{gemspec.name}-#{gemspec.version}")
258
+ sh git, 'tag', '-a', "#{gemspec.name}-#{gemspec.version}", '-m', "Released #{gemspec.name} gem version #{gemspec.version}."
212
259
  end
213
260
 
214
261
  # Pushes the changes and tag to github
215
262
  def github_release_task
216
- git.push(remote, remote_branch, true)
263
+ sh git, 'push', '--tags', remote, remote_branch
217
264
  end
218
265
 
219
- # # Checks whether Rubyforge is configured properly
220
- # def check_rubyforge_task
221
- # # Login no longer necessary when using rubyforge 2.0.0 gem
222
- # # raise "Could not login on rubyforge!" unless `rubyforge login 2>&1`.strip.empty?
223
- # output = `rubyforge names`.split("\n")
224
- # raise "Rubyforge group not found!" unless output.any? { |line| %r[^groups\s*\:.*\b#{Regexp.quote(gemspec.rubyforge_project)}\b.*] =~ line }
225
- # raise "Rubyforge package not found!" unless output.any? { |line| %r[^packages\s*\:.*\b#{Regexp.quote(gemspec.name)}\b.*] =~ line }
226
- # end
227
-
228
- # # Task to release the .gem file toRubyforge.
229
- # def rubyforge_release_task
230
- # sh 'rubyforge', 'add_release', gemspec.rubyforge_project, gemspec.name, gemspec.version.to_s, "pkg/#{gemspec.name}-#{gemspec.version}.gem"
231
- # end
232
-
233
266
  def gemcutter_release_task
234
- sh "gem push pkg/#{gemspec.name}-#{gemspec.version}.gem"
267
+ sh "gem", 'push', "pkg/#{gemspec.name}-#{gemspec.version}.gem"
235
268
  end
236
269
 
237
270
  # Gem release task.
238
271
  # All work is done by the task's dependencies, so just display a release completed message.
239
272
  def release_task
240
273
  puts
241
- puts '------------------------------------------------------------'
242
- puts "Released #{gemspec.name} version #{gemspec.version}"
274
+ puts "Release successful."
243
275
  end
244
276
 
245
277
  private
@@ -299,30 +331,35 @@ module GithubGem
299
331
 
300
332
  # Reload the gemspec so the changes are incorporated
301
333
  load_gemspec!
334
+
335
+ # Also mark the Gemfile.lock file as changed because of the new version.
336
+ modified_files << 'Gemfile.lock' if File.exist?(File.join(root_dir, 'Gemfile.lock'))
302
337
  end
303
338
  end
304
339
 
305
340
  # Updates the tasks file using the latest file found on Github
306
341
  def update_tasks_task
307
- require 'net/http'
308
-
309
- server = 'github.com'
310
- path = '/wvanbergen/github-gem/raw/master/tasks/github-gem.rake'
311
-
312
- Net::HTTP.start(server) do |http|
313
- response = http.get(path)
342
+ require 'net/https'
343
+ require 'uri'
344
+
345
+ uri = URI.parse('https://github.com/wvanbergen/github-gem/raw/master/tasks/github-gem.rake')
346
+ http = Net::HTTP.new(uri.host, uri.port)
347
+ http.use_ssl = true
348
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
349
+ response = http.request(Net::HTTP::Get.new(uri.path))
350
+
351
+ if Net::HTTPSuccess === response
314
352
  open(__FILE__, "w") { |file| file.write(response.body) }
315
- end
316
-
317
- relative_file = File.expand_path(__FILE__).sub(%r[^#{git.dir.path}/], '')
318
- if git.status[relative_file] && git.status[relative_file].type == 'M'
319
- git.add(relative_file)
320
- git.commit("Updated to latest gem release management tasks.")
321
- puts "Updated to latest version of gem release management tasks."
353
+ relative_file = File.expand_path(__FILE__).sub(%r[^#{@root_dir}/], '')
354
+ if `#{git} ls-files -m #{relative_file}`.split("\n").any?
355
+ sh git, 'add', relative_file
356
+ sh git, 'commit', '-m', "Updated to latest gem release management tasks."
357
+ else
358
+ puts "Release managament tasks already are at the latest version."
359
+ end
322
360
  else
323
- puts "Release managament tasks already are at the latest version."
361
+ raise "Download failed with HTTP status #{response.code}!"
324
362
  end
325
363
  end
326
-
327
364
  end
328
365
  end
@@ -23,4 +23,106 @@ namespace :rla do
23
23
  end
24
24
  end
25
25
 
26
+ # Split a single logfile into multiple multiple logfiles based on PID information
27
+ # provided in the log lines.
28
+ #
29
+ # Usage:
30
+ # rake rla:split_log FILE=logfile
31
+ #
32
+ # Example:
33
+ # $> rake rla:split_log FILE=log/development.log
34
+ # Splitting the Rails log file by pid using the request-log-analyzer gem.
35
+ #
36
+ # Log file was split into the following files:
37
+ # split_log_development.catchall.log # <- log lines without a pid
38
+ # split_log_development.14634.log
39
+ # split_log_development.31277.log
40
+ # split_log_development.31279.log
41
+ #
42
+ # To analyze type:
43
+ # request-log-analyzer /log/split_log_development.*.log
44
+ desc "Split a logfile into seperate files by PID"
45
+ task :split do
46
+
47
+ if ENV['FILE']
48
+ logfile = ENV['FILE']
49
+ if logfile.nil?
50
+ puts "Please provide a logfile to split"
51
+ exit(0)
52
+ elsif !File.exist?(logfile)
53
+ puts "the logfile name you provided can not be found"
54
+ exit(0)
55
+ end
56
+
57
+ # Inline class def. Ugly, yet portable.
58
+ class LogSplitter
59
+ attr_reader :files_by_pid, :catchall, :filename, :rla_call_string
60
+
61
+ # All generated files should contain this prefix to allow for easy glob file matches
62
+ PREFIX = 'split_log_'
63
+ # The logfile pattern that captures the pid, this will be log format specific. Using Logging::Logger
64
+ # we define: Logging::Layouts::Pattern(:pattern => "%d pid:%p [%c:%l] %m [%F:%L]\n")
65
+ # PID_PATTERN = Regexp.union(/.*\[(\d+)\]\:/, /pid:(\d+)/)
66
+ PID_PATTERN = /(?-mix:.*\[(\d+)\]\:)|(?-mix:pid:(\d+))/ #
67
+
68
+ # Currently expects the filename to exist in the local directory for ease of implementation
69
+ def initialize(filename_to_split)
70
+ @filename = filename_to_split
71
+ directory = File.dirname(@filename) + '/'
72
+ directory = '' if @directory == './'
73
+ basename = @filename.split('/').last.gsub('.log', '')
74
+ @rla_call_string = "#{directory}#{PREFIX}#{basename}.*.log"
75
+
76
+ @files_by_pid =
77
+ Hash.new {|hash, pid_key| hash[pid_key] = File.open("#{directory}#{PREFIX}#{basename}.#{pid_key}.log", 'w') }
78
+ @catchall = File.open("#{directory}#{PREFIX}#{basename}.catchall.log", 'w')
79
+ end
80
+
81
+ def split
82
+ last_pid = nil
83
+ File.open(filename, 'r') do |f|
84
+ while(line = f.gets)
85
+ outfile =
86
+ if match_data = line.match(PID_PATTERN)
87
+ pid = match_data.captures[0]
88
+ last_pid = pid
89
+ files_by_pid[pid]
90
+ elsif last_pid
91
+ # handle cases where a single log call results in multiple lines of output.
92
+ files_by_pid[last_pid]
93
+ else
94
+ catchall
95
+ end
96
+ outfile.puts line
97
+ end
98
+ end
99
+ end
100
+
101
+ def close_files
102
+ @files_by_pid.values.map(&:close)
103
+ @catchall.close
104
+ end
105
+ end
106
+ # End inline class def
107
+
108
+ puts "Splitting the Rails log file by pid using the request-log-analyzer gem."
109
+
110
+ log_splitter = LogSplitter.new(logfile)
111
+ log_splitter.split
112
+ log_splitter.close_files
113
+
114
+ puts ''
115
+ puts ''
116
+ puts 'Log file was split into the following files:'
117
+ puts ' ' + log_splitter.catchall.path
118
+ log_splitter.files_by_pid.values.each {|f| puts ' ' + f.path }
119
+ puts ''
120
+ puts 'To analyze type:'
121
+ puts " request-log-analyzer #{log_splitter.rla_call_string}"
122
+ puts ''
123
+ puts ''
124
+ end
125
+
126
+ end
127
+
26
128
  end