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
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .svn/
2
+ .DS_Store
3
+ request-log-analyzer-*.gem
4
+ requests.db
5
+ /pkg
6
+ /doc
7
+ /tmp
8
+ /classes
9
+ /files
10
+ /coverage
data/DESIGN.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ === Request-log-analyzer
2
+ RLA is set up like a simple pipe and filter system.
3
+
4
+ This allows you to easily add extra reports, filters and outputs.
5
+ -> Aggregator (database)
6
+ Source -> Filter -> Filter -> Aggregator (summary report) -> Output
7
+ -> Aggregator (...)
8
+
9
+ When the pipeline has been constructed, we Start chunk producer (source) and push requests through pipeline.
10
+
11
+ Controller.start
12
+
13
+ === Source
14
+ RequestLogAnalyzer::Source is an Object that pushes requests into the chain.
15
+ At the moment you can only use the log-parser as a source.
16
+ It accepts files or stdin and can parse then into request objects using a RequestLogAnalyzer::FileFormat definition.
17
+ In the future we want to be able to have a generated request database as source as this will make interactive
18
+ down drilling possible.
19
+
20
+ === Filter
21
+ The filters are all subclasses of the RequestLogAnalyzer::Filter class.
22
+ They accept a request object, manipulate or drop it, and then pass the request object on to the next filter
23
+ in the chain.
24
+ At the moment there are three types of filters available: Anonymize, Field and Timespan.
25
+
26
+ === Aggregator
27
+ The Aggregators all inherit from the RequestLogAnalyzer::Aggregator class.
28
+ All the requests that come out of the Filterchain are fed into all the aggregators in parallel.
29
+ These aggregators can do anything what they want with the given request.
30
+ For example: the Database aggregator will just store all the requests into a SQLite database while the Summarizer will
31
+ generate a wide range of statistical reports from them.
32
+
33
+ === Running the pipeline
34
+ All Aggregators are asked to report what they have done. For example the database will report: I stuffed x requests
35
+ into SQLite database Y. The Summarizer will output its reports.
36
+
37
+ Controller.report
38
+
39
+ The output is pushed to a RequestLogAnalyzer::Output object, which takes care of the output.
40
+ It can generate either ASCII, UTF8 or even HTML output.
41
+
data/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
- Copyright (c) 2008 Willem van Bergen / Bart ten Brinke
2
-
1
+ Copyright (c) 2008-2009 Willem van Bergen & Bart ten Brinke
2
+
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
5
5
  "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@ without limitation the rights to use, copy, modify, merge, publish,
7
7
  distribute, sublicense, and/or sell copies of the Software, and to
8
8
  permit persons to whom the Software is furnished to do so, subject to
9
9
  the following conditions:
10
-
10
+
11
11
  The above copyright notice and this permission notice shall be
12
12
  included in all copies or substantial portions of the Software.
13
-
13
+
14
14
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
data/README.rdoc ADDED
@@ -0,0 +1,38 @@
1
+ = Request-log-analyzer
2
+
3
+ This is a simple command line tool to analyze request log files in various formats to produce a performance report. Its purpose is to find what actions are best candidates for optimization.
4
+
5
+ * Analyzes log files. Currently supports: Amazon S3, Apache, Delayed::Job, Merb, Mysql, PostgreSQL, Rack, Rails and more.
6
+ * Combines multiple files and decompresses compressed files, which comes in handy if you are using logrotate.
7
+ * Uses several metrics, including cumulative request time, mean request time, process blockers, database and rendering time, HTTP methods and statuses, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
8
+ * Low memory footprint and reasonably fast, so it is safe to run on a production server.
9
+ * MIT licensed
10
+
11
+ See the project wiki at http://wiki.github.com/wvanbergen/request-log-analyzer for documentation and additional information.
12
+
13
+ == Installation & basic usage
14
+
15
+ Install request-log-analyzer as a Ruby gem (you might need to run this command
16
+ as root by prepending +sudo+ to it):
17
+
18
+ $ gem install request-log-analyzer
19
+
20
+ To analyze a Rails log file and produce a performance report, run
21
+ request-log-analyzer like this:
22
+
23
+ $ request-log-analyzer log/production.log
24
+
25
+ For more details, other file formats, and available command line options, see the project's wiki at http://wiki.github.com/wvanbergen/request-log-analyzer
26
+
27
+ == Additional information
28
+
29
+ Request-log-analyzer was designed and built by Willem van Bergen and Bart ten
30
+ Brinke.
31
+
32
+ Do you have a rails application that is not performing as it should? If you need
33
+ an expert to analyze your application, feel free to contact either Willem van
34
+ Bergen (willem@railsdoctors.com) or Bart ten Brinke (bart@railsdoctors.com).
35
+
36
+ * Project wiki at GitHub: http://wiki.github.com/wvanbergen/request-log-analyzer
37
+ * railsdoctors homepage: http://railsdoctors.com
38
+ * wvanbergen's blog posts: http://techblog.floorplanner.com/tag/request-log-analyzer
data/Rakefile CHANGED
@@ -1,5 +1,8 @@
1
1
  Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
-
3
- desc 'Default: run RSpec for request-log-analyzer.'
4
- task :default => :spec
5
2
 
3
+ # Create rake tasks for a gem manages by github. The tasks are created in the
4
+ # gem namespace
5
+ GithubGem::RakeTasks.new(:gem)
6
+
7
+ # Set the RSpec runner with specdoc output as default task.
8
+ task :default => "spec:specdoc"
@@ -1,15 +1,11 @@
1
- #!/usr/bin/ruby
2
- require File.dirname(__FILE__) + '/../lib/request_log_analyzer'
3
- require File.dirname(__FILE__) + '/../lib/cli/command_line_arguments'
4
-
5
- def terminal_width(default = 81)
6
- IO.popen('stty -a') do |pipe|
7
- column_line = pipe.detect { |line| /(\d+) columns/ =~ line }
8
- width = column_line ? $1.to_i : default
9
- end
10
- rescue
11
- default
12
- end
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+ require 'request_log_analyzer'
6
+ require 'cli/command_line_arguments'
7
+ require 'cli/progressbar'
8
+ require 'cli/tools'
13
9
 
14
10
  # Parse the arguments given via commandline
15
11
  begin
@@ -18,106 +14,108 @@ begin
18
14
  command_line.command(:install) do |install|
19
15
  install.parameters = 1
20
16
  end
21
-
17
+
18
+ command_line.command(:console) do |cons|
19
+ cons.option(:database, :alias => :d, :required => true)
20
+ end
21
+
22
22
  command_line.command(:strip) do |strip|
23
23
  strip.minimum_parameters = 1
24
- strip.option(:format, :alias => :f, :default => 'rails')
24
+ strip.option(:format, :alias => :f, :default => 'rails')
25
25
  strip.option(:output, :alias => :o)
26
26
  strip.switch(:discard_teaser_lines, :t)
27
- strip.switch(:keep_junk_lines, :j)
28
- end
29
-
30
- command_line.command(:anonymize) do |anonymize|
31
- anonymize.minimum_parameters = 1
32
- anonymize.option(:format, :alias => :f, :default => 'rails')
33
- anonymize.option(:output, :alias => :o)
34
- anonymize.switch(:discard_teaser_lines, :t)
35
- anonymize.switch(:keep_junk_lines, :j)
27
+ strip.switch(:keep_junk_lines, :j)
36
28
  end
37
-
38
- command_line.option(:format, :alias => :f, :default => 'rails')
29
+
30
+ command_line.option(:format, :alias => :f)
31
+ command_line.option(:apache_format)
32
+ command_line.option(:rails_format)
33
+
39
34
  command_line.option(:file, :alias => :e)
40
- command_line.switch(:assume_correct_order)
41
-
35
+ command_line.option(:mail, :alias => :m)
36
+ command_line.option(:mailhost, :default => 'localhost')
37
+ command_line.option(:parse_strategy, :default => 'assume-correct')
38
+ command_line.option(:yaml)
39
+ command_line.option(:dump) # To be deprecated
40
+
42
41
  command_line.option(:aggregator, :alias => :a, :multiple => true)
43
- command_line.option(:database, :alias => :d)
42
+
43
+ command_line.option(:database, :alias => :d)
44
+ command_line.switch(:reset_database)
44
45
 
45
46
  # filtering options
46
47
  command_line.option(:select, :multiple => true, :parameters => 2)
47
48
  command_line.option(:reject, :multiple => true, :parameters => 2)
48
49
  command_line.option(:after)
49
- command_line.option(:before)
50
-
50
+ command_line.option(:before)
51
+
51
52
  command_line.switch(:boring, :b)
52
- command_line.option(:report_width, :default => terminal_width - 1)
53
-
53
+ command_line.option(:output, :alias => :o, :default => 'fixedwidth')
54
+ command_line.option(:report_width, :default => terminal_width - 1)
55
+ command_line.option(:report_amount, :default => 20)
56
+ command_line.option(:report_sort, :default => 'sum,mean')
57
+
54
58
  command_line.switch(:debug)
55
-
56
- command_line.minimum_parameters = 1
59
+ command_line.switch(:no_progress)
60
+
61
+ command_line.minimum_parameters = 1
57
62
  end
58
-
63
+
59
64
  rescue CommandLine::Error => e
65
+ puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
66
+ puts "Website: http://railsdoctors.com"
67
+ puts
60
68
  puts "ARGUMENT ERROR: " + e.message if e.message
61
69
  puts
62
70
  puts "Usage: request-log-analyzer [LOGFILES*] <OPTIONS>"
63
71
  puts
64
72
  puts "Input options:"
65
- puts " --format <format>, -f: Uses the specified log file format. Defaults to rails."
66
73
  puts " --after <date> Only consider requests from <date> or later."
67
- puts " --before <date> Only consider requests before <date>."
68
- puts " --select <field> <value> Only consider requests where <field> matches <value>."
69
- puts " --reject <field> <value> Only consider requests where <field> does not match <value>."
74
+ puts " --before <date> Only consider requests before <date>."
75
+ puts " --format <format>, -f: Log file format. amazon_s3, apache, merb, mysql, rack or rails."
76
+ puts " --reject <field> <value> Only consider requests where <field> does not match <value>."
77
+ puts " --select <field> <value> Only consider requests where <field> matches <value>."
70
78
  puts
71
79
  puts "Output options:"
72
80
  puts " --boring, -b Output reports without ASCII colors."
73
81
  puts " --database <filename>, -d: Creates an SQLite3 database of all the parsed request information."
74
82
  puts " --debug Print debug information while parsing."
75
- puts " --file <filename> Output to file."
76
- puts
83
+ puts " --file <filename> Redirect output to file."
84
+ puts " --mail <emailaddress> Send report to an email address."
85
+ puts " --mailhost <server> Use the given server as the SMTP server for sending email."
86
+ puts " --no-progress Hide the progress bar."
87
+ puts " --output <format> Output format. Supports 'html' and 'fixed_width'."
88
+ puts " --report-width <amount> Width of ASCII report. Defaults to terminal width."
89
+ puts " --report-amount <amount> Maximum numer of results per report."
90
+ puts " --yaml <filename> Dump the results in YAML format in the given file."
91
+ puts
77
92
  puts "Examples:"
78
- puts " request-log-analyzer development.log"
79
- puts " request-log-analyzer -b mongrel.0.log mongrel.1.log mongrel.2.log "
93
+ puts " request-log-analyzer production.log"
94
+ puts " request-log-analyzer mongrel.0.log mongrel.1.log --output HTML --mail root@localhost"
80
95
  puts " request-log-analyzer --format merb -d requests.db production.log"
96
+ puts " request-log-analyzer mysql_slow_query.log --reject query /SQL_NO_CACHE/"
81
97
  puts
82
98
  puts "To install rake tasks in your Rails application, "
83
99
  puts "run the following command in your application's root directory:"
84
100
  puts
85
101
  puts " request-log-analyzer install rails"
86
- exit(0)
87
- end
88
-
89
- def install_rake_tasks(install_type)
90
- if install_type == 'rails'
91
- require 'ftools'
92
- if File.directory?('./lib/tasks/')
93
- File.copy(File.dirname(__FILE__) + '/../tasks/request_log_analyzer.rake', './lib/tasks/request_log_analyze.rake')
94
- puts "Installed rake tasks."
95
- puts "To use, run: rake log:analyze"
96
- else
97
- puts "Cannot find /lib/tasks folder. Are you in your Rails directory?"
98
- puts "Installation aborted."
99
- end
100
- else
101
- raise "Cannot perform this install type! (#{install_type})"
102
- end
102
+ exit(0)
103
103
  end
104
104
 
105
-
106
105
  case arguments.command
107
106
  when :install
108
107
  install_rake_tasks(arguments.parameters[0])
108
+ when :console
109
+ require 'cli/database_console'
110
+ DatabaseConsole.new(arguments).run!
109
111
  when :strip
110
- require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
112
+ require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
111
113
  RequestLogAnalyzer::LogProcessor.build(:strip, arguments).run!
112
- when :anonymize
113
- require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
114
- RequestLogAnalyzer::LogProcessor.build(:anonymize, arguments).run!
115
- else
116
- puts "Request log analyzer, by Willem van Bergen and Bart ten Brinke - Version 1.0\n\n"
117
-
118
- # Run the request_log_analyzer!
119
- RequestLogAnalyzer::Controller.build(arguments, terminal_width).run!
114
+ else
115
+ puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
116
+ puts "Website: http://railsdoctors.com"
117
+ puts
120
118
 
121
- puts
122
- puts "Thanks for using request-log-analyzer"
119
+ # Run the request_log_analyzer!
120
+ RequestLogAnalyzer::Controller.build_from_arguments(arguments).run!
123
121
  end
@@ -71,7 +71,7 @@ module CommandLine
71
71
  def required?
72
72
  @required
73
73
  end
74
-
74
+
75
75
  # Check if flag is optional
76
76
  def optional?
77
77
  !@required
@@ -85,22 +85,22 @@ module CommandLine
85
85
  !@default_value.nil?
86
86
  end
87
87
  end
88
-
88
+
89
89
  class Arguments
90
90
 
91
91
  class Definition
92
-
92
+
93
93
  ENDLESS_PARAMETERS = 99999
94
-
94
+
95
95
  attr_reader :commands, :options, :parameters
96
-
96
+
97
97
  def initialize(parent)
98
98
  @parent = parent
99
99
  @options = {}
100
100
  @commands = {}
101
101
  @parameters = nil
102
102
  end
103
-
103
+
104
104
  def [](option_name)
105
105
  option_symbol = CommandLine::Option.rewrite(option_name)
106
106
  if the_option = @options.detect { |(name, odef)| odef =~ option_symbol }
@@ -109,22 +109,22 @@ module CommandLine
109
109
  raise CommandLine::UnknownOption, option_name
110
110
  end
111
111
  end
112
-
112
+
113
113
  def minimum_parameters=(count_specifier)
114
114
  @parameters = count_specifier..ENDLESS_PARAMETERS
115
115
  end
116
-
116
+
117
117
  def parameters=(count_specifier)
118
118
  @parameters = count_specifier
119
119
  end
120
-
121
- alias :files= :parameters=
122
-
120
+
121
+ alias :files= :parameters=
122
+
123
123
  def option(name, options = {})
124
124
  clo = CommandLine::Option.new(name, options)
125
125
  @options[clo.name] = clo
126
126
  end
127
-
127
+
128
128
  def switch(name, switch_alias = nil)
129
129
  option(name, :alias => switch_alias, :parameters => 0)
130
130
  end
@@ -134,35 +134,35 @@ module CommandLine
134
134
  yield(command_definition) if block_given?
135
135
  @commands[CommandLine::Option.rewrite(name)] = command_definition
136
136
  end
137
-
137
+
138
138
  def has_command?(command)
139
139
  @commands[CommandLine::Option.rewrite(command)]
140
140
  end
141
141
  end
142
-
143
- OPTION_REGEXP = /^\-\-([A-z0-9-]+)$/;
144
- ALIASES_REGEXP = /^\-([A-z0-9]+)$/
145
-
142
+
143
+ OPTION_REGEXP = /^\-\-([A-Za-z0-9-]+)$/;
144
+ ALIASES_REGEXP = /^\-([A-Aa-z0-9]+)$/
145
+
146
146
  attr_reader :definition
147
147
  attr_reader :tokens
148
148
  attr_reader :command, :options, :parameters
149
-
149
+
150
150
  def self.parse(tokens = $*, &block)
151
151
  cla = Arguments.new
152
152
  cla.define(&block)
153
- return cla.parse!(tokens)
153
+ return cla.parse!(tokens)
154
154
  end
155
-
155
+
156
156
  def initialize
157
157
  @tokens = []
158
- @definition = Definition.new(self)
159
- @current_definition = @definition
158
+ @definition = Definition.new(self)
159
+ @current_definition = @definition
160
160
  end
161
-
161
+
162
162
  def define(&block)
163
163
  yield(@definition)
164
164
  end
165
-
165
+
166
166
  def [](option)
167
167
  if the_option = @options.detect { |(key, value)| key =~ option }
168
168
  the_option[1]
@@ -170,31 +170,31 @@ module CommandLine
170
170
  @current_definition[option].default_value
171
171
  end
172
172
  end
173
-
173
+
174
174
  def next_token
175
175
  @current_token = @tokens.shift
176
176
  return @current_token
177
177
  end
178
-
178
+
179
179
  def next_parameter
180
180
  parameter_candidate = @tokens.first
181
181
  parameter = (parameter_candidate.nil? || OPTION_REGEXP =~ parameter_candidate || ALIASES_REGEXP =~ parameter_candidate) ? nil : @tokens.shift
182
182
  return parameter
183
183
  end
184
-
184
+
185
185
  def parse!(tokens)
186
- @current_definition = @definition
186
+ @current_definition = @definition
187
187
  @first_token = true
188
188
  @tokens = tokens.clone
189
-
189
+
190
190
  @options = {}
191
191
  @parameters = []
192
192
  @command = nil
193
-
193
+
194
194
  prepare_result!
195
-
195
+
196
196
  while next_token
197
-
197
+
198
198
  if @first_token && command_definition = @definition.has_command?(@current_token)
199
199
  @current_definition = command_definition
200
200
  @command = CommandLine::Option.rewrite(@current_token)
@@ -204,34 +204,34 @@ module CommandLine
204
204
  when OPTION_REGEXP; handle_option($1)
205
205
  else; handle_other_parameter(@current_token)
206
206
  end
207
- @first_token = false
207
+ @first_token = false
208
208
  end
209
-
209
+
210
210
  end
211
-
211
+
212
212
  validate_arguments!
213
-
214
- return self
213
+
214
+ return self
215
215
  end
216
-
216
+
217
217
  protected
218
-
218
+
219
219
  def prepare_result!
220
220
  multiple_options = Hash[*@current_definition.options.select { |name, o| o.multiple? }.flatten]
221
221
  multiple_options.each { |name, definition| @options[definition] = [] }
222
222
  end
223
-
223
+
224
224
  def validate_arguments!
225
225
  if @current_definition.parameters && !(@current_definition.parameters === @parameters.length)
226
226
  raise CommandLine::ParametersOutOfRange.new(@current_definition.parameters, @parameters.length)
227
227
  end
228
-
228
+
229
229
  required_options = Hash[*@current_definition.options.select { |name, o| o.required? }.flatten]
230
230
  required_options.each do |name, definition|
231
- raise CommandLine::RequiredOptionMissing, definition unless self[name]
231
+ raise CommandLine::RequiredOptionMissing, definition unless self[name]
232
232
  end
233
233
  end
234
-
234
+
235
235
  def handle_alias_expansion(aliases)
236
236
  aliases.reverse.scan(/./) do |alias_char|
237
237
  if option_definition = @current_definition[alias_char]
@@ -241,24 +241,24 @@ module CommandLine
241
241
  end
242
242
  end
243
243
  end
244
-
244
+
245
245
  def handle_other_parameter(parameter)
246
246
  @parameters << parameter
247
247
  end
248
-
248
+
249
249
  def handle_option(option_name)
250
250
  option_definition = @current_definition[option_name]
251
251
  raise CommandLine::UnknownOption, option_name if option_definition.nil?
252
-
252
+
253
253
  if option_definition.multiple?
254
- @options[option_definition] << option_definition.parse(self)
254
+ @options[option_definition] << option_definition.parse(self)
255
255
  else
256
256
  @options[option_definition] = option_definition.parse(self)
257
257
  end
258
258
  end
259
-
259
+
260
260
  end
261
-
261
+
262
262
  # Commandline parsing errors and exceptions
263
263
  class Error < Exception
264
264
  end
@@ -267,7 +267,7 @@ module CommandLine
267
267
  class RequiredOptionMissing < CommandLine::Error
268
268
  def initialize(option)
269
269
  super("You have to provide the #{option.name} option!")
270
- end
270
+ end
271
271
  end
272
272
 
273
273
  # Missing a required file
@@ -282,14 +282,14 @@ module CommandLine
282
282
  else
283
283
  super("The command expected #{expected} parameters, but found #{actual}!")
284
284
  end
285
- end
285
+ end
286
286
  end
287
287
 
288
288
  # Missing a required flag argument
289
289
  class ParameterExpected < CommandLine::Error
290
290
  def initialize(option)
291
291
  super("The option #{option.inspect} expects a parameter!")
292
- end
292
+ end
293
293
  end
294
294
 
295
295
  # Encountered an unkown flag
@@ -297,5 +297,5 @@ module CommandLine
297
297
  def initialize(option_identifier)
298
298
  super("#{option_identifier.inspect} not recognized as a valid option!")
299
299
  end
300
- end
300
+ end
301
301
  end
@@ -0,0 +1,26 @@
1
+
2
+ class DatabaseConsole
3
+
4
+ IRB = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
5
+
6
+ def initialize(arguments)
7
+ @arguments = arguments
8
+ end
9
+
10
+ def run!
11
+ libraries = ['irb/completion', 'rubygems', './lib/request_log_analyzer', './lib/cli/database_console_init']
12
+ libaries_string = libraries.map { |l| "-r #{l}" }.join(' ')
13
+
14
+ ENV['RLA_DBCONSOLE_DATABASE'] = @arguments[:database]
15
+ if @arguments[:apache_format]
16
+ ENV['RLA_DBCONSOLE_FORMAT'] = 'apache'
17
+ ENV['RLA_DBCONSOLE_FORMAT_ARGUMENT'] = @arguments[:apache_format]
18
+ else
19
+ ENV['RLA_DBCONSOLE_FORMAT'] = @arguments[:format]
20
+ end
21
+ # ENV['RLA_DBCONSOLE_FORMAT_ARGS'] = arguments['database']
22
+
23
+ exec("#{IRB} #{libaries_string} --simple-prompt")
24
+ end
25
+ end
26
+
@@ -0,0 +1,43 @@
1
+ # Setup the include path
2
+ $:.unshift(File.dirname(__FILE__) + '/..')
3
+
4
+ $database = RequestLogAnalyzer::Database.new(ENV['RLA_DBCONSOLE_DATABASE'])
5
+ $database.load_database_schema!
6
+ $database.register_default_orm_classes!
7
+
8
+ require 'cli/tools'
9
+
10
+ def wordwrap(string, max = 80, indent = "")
11
+ strings = [""]
12
+ string.split(", ").each do |item|
13
+ if strings.last.length == 0 || strings.last.length + item.length <= max
14
+ strings.last << item << ', '
15
+ else
16
+ strings << (item + ', ')
17
+ end
18
+ end
19
+ strings.map(&:strip).join("\n#{indent}").slice(0..-2)
20
+ end
21
+
22
+ class Request
23
+ def inspect
24
+ request_inspect = "Request[id: #{id}]"
25
+ request_inspect << " <#{lines.first.source.filename}>" if lines.first.source
26
+
27
+ inspected_lines = lines.map do |line|
28
+ inspect_line = " - #{line.line_type} (line #{line.lineno})"
29
+ if (inspect_attributes = line.attributes.reject { |(k, v)| [:id, :source_id, :request_id, :lineno].include?(k.to_sym) }).any?
30
+ inspect_attributes = inspect_attributes.map { |(k,v)| "#{k} = #{v.inspect}" }.join(', ')
31
+ inspect_line << "\n " + wordwrap(inspect_attributes, terminal_width - 6, " ")
32
+ end
33
+ inspect_line
34
+ end
35
+
36
+ request_inspect << "\n" << inspected_lines.join("\n") << "\n\n"
37
+ end
38
+ end
39
+
40
+ puts "request-log-analyzer database console"
41
+ puts "-------------------------------------"
42
+ puts "The following ActiveRecord classes are available:"
43
+ puts $database.orm_classes.map { |k| k.name.split('::').last }.join(", ")