wvanbergen-request-log-analyzer 1.2.3 → 1.2.4
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.
- data/RELEASE_NOTES.rdoc +9 -0
- data/lib/request_log_analyzer/aggregator/database.rb +16 -14
- data/lib/request_log_analyzer/request.rb +2 -2
- data/spec/lib/mocks.rb +12 -1
- data/spec/unit/aggregator/database_spec.rb +15 -19
- data/spec/unit/source/request_spec.rb +90 -64
- data/tasks/github-gem.rake +30 -7
- metadata +3 -4
data/RELEASE_NOTES.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 1.2.3
|
2
|
+
* Refactored database functions
|
3
|
+
* Cleaned up specs and tried some heckle
|
4
|
+
* Interrupts are handled more gracefully
|
5
|
+
* Moved munin tracker to seperate Github project (http://github.com/barttenbrinke/munin-plugins-rails/)
|
6
|
+
|
7
|
+
=== 1.2.2
|
8
|
+
* Not released
|
9
|
+
|
1
10
|
=== 1.2.1
|
2
11
|
* Compressed logfile support
|
3
12
|
* Parsable YAML results as output (use --dump <filename> )
|
@@ -64,6 +64,11 @@ module RequestLogAnalyzer::Aggregator
|
|
64
64
|
output << "\n"
|
65
65
|
end
|
66
66
|
|
67
|
+
# Retreives the connection that is used for the database inserter
|
68
|
+
def connection
|
69
|
+
orm_module::Base.connection
|
70
|
+
end
|
71
|
+
|
67
72
|
protected
|
68
73
|
|
69
74
|
# Create a module and a default subclass of ActiveRecord::Base on which to establish the database connection
|
@@ -84,11 +89,11 @@ module RequestLogAnalyzer::Aggregator
|
|
84
89
|
# Established a connection with the database for this session
|
85
90
|
def establish_database_connection!
|
86
91
|
orm_module::Base.establish_connection(:adapter => 'sqlite3', :database => options[:database])
|
87
|
-
ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
|
92
|
+
#ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
|
88
93
|
end
|
89
94
|
|
90
95
|
def remove_database_connection!
|
91
|
-
ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
|
96
|
+
#ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
|
92
97
|
orm_module::Base.remove_connection
|
93
98
|
end
|
94
99
|
|
@@ -97,8 +102,7 @@ module RequestLogAnalyzer::Aggregator
|
|
97
102
|
# what line in the original file the line was found, and a request_id to link lines related
|
98
103
|
# to the same request. It will also create an index in the request_id field to speed up queries.
|
99
104
|
def create_database_table(definition)
|
100
|
-
|
101
|
-
ActiveRecord::Migration.create_table("#{definition.name}_lines") do |t|
|
105
|
+
connection.create_table("#{definition.name}_lines") do |t|
|
102
106
|
|
103
107
|
# Add default fields for every line type
|
104
108
|
t.column(:request_id, :integer)
|
@@ -114,7 +118,7 @@ module RequestLogAnalyzer::Aggregator
|
|
114
118
|
end
|
115
119
|
|
116
120
|
# Create an index on the request_id column to support faster querying
|
117
|
-
|
121
|
+
connection.add_index("#{definition.name}_lines", [:request_id])
|
118
122
|
end
|
119
123
|
|
120
124
|
# Creates an ActiveRecord class for a given line definition.
|
@@ -137,10 +141,9 @@ module RequestLogAnalyzer::Aggregator
|
|
137
141
|
# Creates a requests table, in which a record is created for every request. It also creates an
|
138
142
|
# ActiveRecord::Base class to communicate with this table.
|
139
143
|
def create_request_table_and_class
|
140
|
-
|
141
|
-
|
142
|
-
t.
|
143
|
-
t.integer :last_lineno
|
144
|
+
connection.create_table("requests") do |t|
|
145
|
+
t.column :first_lineno, :integer
|
146
|
+
t.column :last_lineno, :integer
|
144
147
|
end
|
145
148
|
|
146
149
|
orm_module.const_set('Request', Class.new(orm_module::Base)) unless orm_module.const_defined?('Request')
|
@@ -149,11 +152,10 @@ module RequestLogAnalyzer::Aggregator
|
|
149
152
|
|
150
153
|
# Creates a warnings table and a corresponding Warning class to communicate with this table using ActiveRecord.
|
151
154
|
def create_warning_table_and_class
|
152
|
-
|
153
|
-
|
154
|
-
t.
|
155
|
-
t.
|
156
|
-
t.integer :lineno
|
155
|
+
connection.create_table("warnings") do |t|
|
156
|
+
t.column :warning_type, :string, :limit => 30, :null => false
|
157
|
+
t.column :message, :string
|
158
|
+
t.column :lineno, :integer
|
157
159
|
end
|
158
160
|
|
159
161
|
orm_module.const_set('Warning', Class.new(orm_module::Base)) unless orm_module.const_defined?('Warning')
|
@@ -145,11 +145,11 @@ module RequestLogAnalyzer
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def first_lineno
|
148
|
-
@lines.
|
148
|
+
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.min
|
149
149
|
end
|
150
150
|
|
151
151
|
def last_lineno
|
152
|
-
@lines.
|
152
|
+
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.max
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
data/spec/lib/mocks.rb
CHANGED
@@ -38,10 +38,21 @@ module RequestLogAnalyzer::Spec::Mocks
|
|
38
38
|
output.stub!(:title)
|
39
39
|
output.stub!(:line)
|
40
40
|
output.stub!(:with_style)
|
41
|
-
output.stub!(:table)
|
41
|
+
output.stub!(:table).and_yield([])
|
42
42
|
output.stub!(:io).and_return(mock_io)
|
43
43
|
return output
|
44
44
|
end
|
45
45
|
|
46
|
+
def mock_migrator
|
47
|
+
table_creator = mock('ActiveRecord table creator')
|
48
|
+
table_creator.stub!(:column)
|
49
|
+
|
50
|
+
migrator = mock('ActiveRecord::Base.connection for migrations')
|
51
|
+
migrator.stub!(:add_index)
|
52
|
+
migrator.stub!(:create_table).and_yield(table_creator).and_return(true)
|
53
|
+
migrator.stub!(:table_creator).and_return(table_creator)
|
54
|
+
return migrator
|
55
|
+
end
|
56
|
+
|
46
57
|
|
47
58
|
end
|
@@ -8,7 +8,7 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
8
8
|
|
9
9
|
@line_definition = RequestLogAnalyzer::LineDefinition.new(:test, { :regexp => /Testing (\w+), tries\: (\d+)/,
|
10
10
|
:captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer },
|
11
|
-
{ :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
|
11
|
+
{ :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
|
12
12
|
end
|
13
13
|
|
14
14
|
# The prepare method is called before the parsing starts. It should establish a connection
|
@@ -36,43 +36,41 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
36
36
|
describe '#create_database_table' do
|
37
37
|
|
38
38
|
before(:each) do
|
39
|
-
@
|
40
|
-
@
|
41
|
-
ActiveRecord::Migration.stub!(:create_table).and_yield(@table_creator)
|
42
|
-
ActiveRecord::Migration.stub!(:add_index)
|
39
|
+
@connection = mock_migrator
|
40
|
+
@database_inserter.stub!(:connection).and_return(@connection)
|
43
41
|
end
|
44
42
|
|
45
43
|
it "should create a table based on the line type name" do
|
46
|
-
|
44
|
+
@connection.should_receive(:create_table).with('test_lines')
|
47
45
|
@database_inserter.send(:create_database_table, @line_definition)
|
48
46
|
end
|
49
47
|
|
50
48
|
it "should create an index on the request_id field" do
|
51
|
-
|
49
|
+
@connection.should_receive(:add_index).with('test_lines', [:request_id])
|
52
50
|
@database_inserter.send(:create_database_table, @line_definition)
|
53
51
|
end
|
54
52
|
|
55
53
|
it "should create a request_id field to link the requests together" do
|
56
|
-
@table_creator.should_receive(:column).with(:request_id, :integer)
|
54
|
+
@connection.table_creator.should_receive(:column).with(:request_id, :integer)
|
57
55
|
@database_inserter.send(:create_database_table, @line_definition)
|
58
56
|
end
|
59
57
|
|
60
58
|
it "should create a lineno field to save the location of the line in the original file" do
|
61
|
-
@table_creator.should_receive(:column).with(:lineno, :integer)
|
59
|
+
@connection.table_creator.should_receive(:column).with(:lineno, :integer)
|
62
60
|
@database_inserter.send(:create_database_table, @line_definition)
|
63
61
|
end
|
64
62
|
|
65
63
|
it "should create a field of the correct type for every defined field" do
|
66
|
-
@table_creator.should_receive(:column).with(:what, :string)
|
67
|
-
@table_creator.should_receive(:column).with(:tries, :integer)
|
64
|
+
@connection.table_creator.should_receive(:column).with(:what, :string)
|
65
|
+
@connection.table_creator.should_receive(:column).with(:tries, :integer)
|
68
66
|
# :hash capture type should map on a :text field type
|
69
|
-
@table_creator.should_receive(:column).with(:evaluated, :text)
|
67
|
+
@connection.table_creator.should_receive(:column).with(:evaluated, :text)
|
70
68
|
@database_inserter.send(:create_database_table, @line_definition)
|
71
69
|
end
|
72
70
|
|
73
71
|
it "should create a field of the correct type for every provided field" do
|
74
72
|
# :duration capture type should map on a :double field type
|
75
|
-
@table_creator.should_receive(:column).with(:evaluated_field, :double)
|
73
|
+
@connection.table_creator.should_receive(:column).with(:evaluated_field, :double)
|
76
74
|
@database_inserter.send(:create_database_table, @line_definition)
|
77
75
|
end
|
78
76
|
end
|
@@ -129,21 +127,19 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
129
127
|
before(:each) do
|
130
128
|
@line_type_cnt = testing_format.line_definitions.length
|
131
129
|
|
132
|
-
|
133
|
-
|
134
|
-
ActiveRecord::Migration.stub!(:create_table)
|
130
|
+
@connection = mock_migrator
|
131
|
+
@database_inserter.stub!(:connection).and_return(@connection)
|
135
132
|
|
136
133
|
# Stub the expected method calls for the preparation
|
137
134
|
@database_inserter.stub!(:create_database_table)
|
138
135
|
@database_inserter.stub!(:create_activerecord_class)
|
139
136
|
|
140
|
-
|
141
137
|
# Make sure the ORM module exists
|
142
138
|
@database_inserter.send(:initialize_orm_module!)
|
143
139
|
end
|
144
140
|
|
145
141
|
it "should create a requests table to join request lines" do
|
146
|
-
|
142
|
+
@connection.should_receive(:create_table).with("requests")
|
147
143
|
@database_inserter.send :create_database_schema!
|
148
144
|
end
|
149
145
|
|
@@ -153,7 +149,7 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
153
149
|
end
|
154
150
|
|
155
151
|
it "should create a warnings table for logging parse warnings" do
|
156
|
-
|
152
|
+
@connection.should_receive(:create_table).with("warnings")
|
157
153
|
@database_inserter.send :create_database_schema!
|
158
154
|
end
|
159
155
|
|
@@ -1,85 +1,111 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
2
|
|
3
|
-
describe RequestLogAnalyzer::Request
|
3
|
+
describe RequestLogAnalyzer::Request do
|
4
4
|
|
5
5
|
before(:each) do
|
6
|
-
@
|
7
|
-
@incomplete_request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should be single if only one line has been added" do
|
11
|
-
@incomplete_request.should_not be_empty
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should not be a completed request" do
|
15
|
-
@incomplete_request.should_not be_completed
|
6
|
+
@request = testing_format.request
|
16
7
|
end
|
17
8
|
|
18
|
-
it "should
|
19
|
-
@
|
20
|
-
@incomplete_request.should =~ :test
|
9
|
+
it "should be empty without any captured lines in it" do
|
10
|
+
@request.should be_empty
|
21
11
|
end
|
22
12
|
|
23
|
-
|
24
|
-
@incomplete_request[:test_capture].should == 'awesome!'
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should return nil if no such field is present" do
|
28
|
-
@incomplete_request[:nonexisting].should be_nil
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
describe RequestLogAnalyzer::Request, :completed_request do
|
13
|
+
context :incomplete do
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@completed_request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
|
39
|
-
@completed_request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
|
40
|
-
@completed_request << { :line_type => :last, :lineno => 10, :time => 0.03 }
|
41
|
-
end
|
15
|
+
before(:each) do
|
16
|
+
@request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
|
17
|
+
end
|
42
18
|
|
43
|
-
|
44
|
-
|
45
|
-
|
19
|
+
it "should be single if only one line has been added" do
|
20
|
+
@request.should_not be_empty
|
21
|
+
end
|
46
22
|
|
47
|
-
|
48
|
-
|
49
|
-
|
23
|
+
it "should not be a completed request" do
|
24
|
+
@request.should_not be_completed
|
25
|
+
end
|
50
26
|
|
51
|
-
|
52
|
-
|
53
|
-
|
27
|
+
it "should take the line type of the first line as global line_type" do
|
28
|
+
@request.lines[0][:line_type].should == :test
|
29
|
+
@request.should =~ :test
|
30
|
+
end
|
54
31
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
32
|
+
it "should return the first field value" do
|
33
|
+
@request[:test_capture].should == 'awesome!'
|
34
|
+
end
|
59
35
|
|
60
|
-
|
61
|
-
|
36
|
+
it "should return nil if no such field is present" do
|
37
|
+
@request[:nonexisting].should be_nil
|
38
|
+
end
|
62
39
|
end
|
63
40
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
41
|
+
context :completed do
|
42
|
+
|
43
|
+
before(:each) do
|
44
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
|
45
|
+
@request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
|
46
|
+
@request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
|
47
|
+
@request << { :line_type => :last, :lineno => 10, :time => 0.03 }
|
48
|
+
end
|
71
49
|
|
72
|
-
|
73
|
-
|
74
|
-
|
50
|
+
it "should not be empty when multiple liness are added" do
|
51
|
+
@request.should_not be_empty
|
52
|
+
end
|
75
53
|
|
76
|
-
|
77
|
-
|
78
|
-
|
54
|
+
it "should be a completed request" do
|
55
|
+
@request.should be_completed
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should recognize all line types" do
|
59
|
+
[:first, :test, :last].each { |type| @request.should =~ type }
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should detect the correct field value" do
|
63
|
+
@request[:name].should == 'first line!'
|
64
|
+
@request[:time].should == 0.03
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should detect the first matching field value" do
|
68
|
+
@request.first(:test_capture).should == 'testing'
|
69
|
+
end
|
79
70
|
|
80
|
-
|
81
|
-
|
82
|
-
|
71
|
+
it "should detect the every matching field value" do
|
72
|
+
@request.every(:test_capture).should == ['testing', "testing some more"]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set the first_lineno for a request to the lowest lineno encountered" do
|
76
|
+
@request.first_lineno.should eql(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should set the first_lineno for a request if a line with a lower lineno is added" do
|
80
|
+
@request << { :line_type => :test, :lineno => 0 }
|
81
|
+
@request.first_lineno.should eql(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should set the last_lineno for a request to the highest encountered lineno" do
|
85
|
+
@request.last_lineno.should eql(10)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not set the last_lineno for a request if a line with a lower lineno is added" do
|
89
|
+
@request << { :line_type => :test, :lineno => 7 }
|
90
|
+
@request.last_lineno.should eql(10)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not have a timestamp if no such field is captured" do
|
94
|
+
@request.timestamp.should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should set return a timestamp field if such a field is captured" do
|
98
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!', :timestamp => Time.now}
|
99
|
+
@request.timestamp.should_not be_nil
|
100
|
+
end
|
83
101
|
end
|
84
102
|
|
85
|
-
|
103
|
+
context 'single line' do
|
104
|
+
# combined is both a header and a footer line
|
105
|
+
before(:each) { @request << { :line_type => :combined, :lineno => 1 } }
|
106
|
+
|
107
|
+
it "should be a completed request if the line is both header and footer" do
|
108
|
+
@request.should be_completed
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/tasks/github-gem.rake
CHANGED
@@ -14,7 +14,8 @@ module Rake
|
|
14
14
|
def self.define_tasks!
|
15
15
|
gem_task_builder = Rake::GithubGem.new
|
16
16
|
gem_task_builder.register_all_tasks!
|
17
|
-
end
|
17
|
+
end
|
18
|
+
|
18
19
|
|
19
20
|
def initialize
|
20
21
|
reload_gemspec!
|
@@ -37,8 +38,18 @@ module Rake
|
|
37
38
|
desc "Releases a new version of #{@name}"
|
38
39
|
task(:release => release_dependencies) { release_task }
|
39
40
|
|
41
|
+
namespace(:release) do
|
42
|
+
release_checks = [:check_clean_master_branch, :check_version, :build]
|
43
|
+
release_checks.push 'doc:compile' if has_rdoc?
|
44
|
+
release_checks.unshift 'test' if has_tests?
|
45
|
+
release_checks.unshift 'spec' if has_specs?
|
46
|
+
|
47
|
+
desc "Test release conditions"
|
48
|
+
task(:check => release_checks) { release_check_task }
|
49
|
+
end
|
50
|
+
|
40
51
|
# helper task for releasing
|
41
|
-
task(:check_clean_master_branch) { verify_clean_status('master') }
|
52
|
+
task(:check_clean_master_branch) { verify_fast_forward('master', 'origin', 'master'); verify_clean_status('master') }
|
42
53
|
task(:check_version) { verify_version(ENV['VERSION'] || @specification.version) }
|
43
54
|
task(:version => [:check_version]) { set_gem_version! }
|
44
55
|
task(:create_tag) { create_version_tag! }
|
@@ -165,13 +176,17 @@ module Rake
|
|
165
176
|
|
166
177
|
def verify_current_branch(branch)
|
167
178
|
run_command('git branch').detect { |line| /^\* (.+)/ =~ line }
|
168
|
-
raise "You are currently not working in the
|
179
|
+
raise "You are currently not working in the #{branch} branch!" unless branch == $1
|
169
180
|
end
|
170
181
|
|
171
|
-
def
|
172
|
-
sh "git fetch"
|
182
|
+
def verify_fast_forward(local_branch = 'master', remote = 'origin', remote_branch = 'master')
|
183
|
+
sh "git fetch #{remote}"
|
184
|
+
lines = run_command("git rev-list #{local_branch}..remotes/#{remote}/#{remote_branch}")
|
185
|
+
raise "Remote branch #{remote}/#{remote_branch} has commits that are not yet incorporated in local #{local_branch} branch" unless lines.length == 0
|
186
|
+
end
|
187
|
+
|
188
|
+
def verify_clean_status(on_branch = nil)
|
173
189
|
lines = run_command('git status')
|
174
|
-
raise "You don't have the most recent version available. Run git pull first." if /^\# Your branch is behind/ =~ lines[1]
|
175
190
|
raise "You are currently not working in the #{on_branch} branch!" unless on_branch.nil? || (/^\# On branch (.+)/ =~ lines.first && $1 == on_branch)
|
176
191
|
raise "Your master branch contains modifications!" unless /^nothing to commit \(working directory clean\)/ =~ lines.last
|
177
192
|
end
|
@@ -243,7 +258,15 @@ module Rake
|
|
243
258
|
puts '------------------------------------------------------------'
|
244
259
|
puts "Released #{@name} - version #{@specification.version}"
|
245
260
|
end
|
261
|
+
|
262
|
+
def release_check_task
|
263
|
+
puts
|
264
|
+
puts '------------------------------------------------------------'
|
265
|
+
puts "Checked all conditions for a release of version #{ENV['VERSION'] || @specification.version}!"
|
266
|
+
puts 'You should be safe to do a release now.'
|
267
|
+
puts '------------------------------------------------------------'
|
268
|
+
end
|
246
269
|
end
|
247
270
|
end
|
248
271
|
|
249
|
-
Rake::GithubGem.define_tasks!
|
272
|
+
Rake::GithubGem.define_tasks!
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wvanbergen-request-log-analyzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-09-01 00:00:00 -07:00
|
14
14
|
default_executable: request-log-analyzer
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -132,7 +132,6 @@ files:
|
|
132
132
|
- tasks/rspec.rake
|
133
133
|
has_rdoc: true
|
134
134
|
homepage: http://github.com/wvanbergen/request-log-analyzer/wikis
|
135
|
-
licenses:
|
136
135
|
post_install_message:
|
137
136
|
rdoc_options:
|
138
137
|
- --title
|
@@ -158,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
157
|
requirements: []
|
159
158
|
|
160
159
|
rubyforge_project: r-l-a
|
161
|
-
rubygems_version: 1.
|
160
|
+
rubygems_version: 1.2.0
|
162
161
|
signing_key:
|
163
162
|
specification_version: 2
|
164
163
|
summary: A command line tool to analyze Rails logs
|