nbogie-production_log_analyzer 1.5.1.1 → 1.5.1.2
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/.gemtest +0 -0
- data/History.txt +4 -0
- data/README.txt +27 -0
- data/Rakefile +1 -1
- data/test/test_report_differ.rb +178 -0
- data/test/test_report_parser.rb +140 -0
- metadata +22 -24
data/.gemtest
ADDED
File without changes
|
data/History.txt
CHANGED
data/README.txt
CHANGED
@@ -138,6 +138,33 @@ In the future, pl_analyze will be able to read from STDIN.
|
|
138
138
|
TeamsController#progress took 0.000s
|
139
139
|
TeamsController#progress took 0.000s
|
140
140
|
|
141
|
+
There's an experimental report-differ which you can invoke as follows:
|
142
|
+
|
143
|
+
ruby -Ilib report_differ.rb report_b.txt report_a.txt > report_diff.txt
|
144
|
+
|
145
|
+
Sample diff output
|
146
|
+
|
147
|
+
Request_Times_Summary: Count Avg Max
|
148
|
+
ALL_REQUESTS +1.4(16515->22909) -2.2(0.405->0.18) -1.6(59.678->37.721)
|
149
|
+
|
150
|
+
SleepwalkersController#update.PUT.xml +1.4(6249->8793) -1.1(0.079->0.07) -2.7(8.328->3.103)
|
151
|
+
SleepwalkersController#update.PUT.csv +1.4(6245->8807) -1.0(0.099->0.097) +1.2(2.536->3.02)
|
152
|
+
SleepwalkersController#show.GET +1.4(509->710) -1.2(0.072->0.061) -2.3(3.505->1.504)
|
153
|
+
SleepwalkersController#show.GET.json +1.4(496->702) -1.2(0.076->0.064) -7.3(4.874->0.663)
|
154
|
+
AccomplicesController#history.GET.csv +1.4(470->680) -3.3(5.35->1.618) -1.5(20.681->13.692)
|
155
|
+
WindsController#feeds.GET +1.4(237->320) -1.1(0.201->0.183) +1.5(1.304->1.989)
|
156
|
+
ScamsController#show.GET +1.3(236->317) -3.0(11.793->3.869) -1.6(59.678->37.721)
|
157
|
+
SleepwalkersController#update.PUT -1.1(9->8) -1.1(0.051->0.047) -1.2(0.09->0.076)
|
158
|
+
AccomplicesController#show.GET.xml 1.0(2->2) -1.0(0.102->0.1) -1.0(0.184->0.179)
|
159
|
+
ScamsController#map.GET +6.0(2->12) -3.5(1.075->0.305) +1.1(2.008->2.112)
|
160
|
+
WindsController#feeds.GET.atom 1.0(1->1) -1.1(0.061->0.058) -1.1(0.061->0.058)
|
161
|
+
ScamsController#tag.GET.rss 1.0(1->1) -1.0(0.134->0.129) -1.0(0.134->0.129)
|
162
|
+
|
163
|
+
Unmatched_Actions:
|
164
|
+
|
165
|
+
ScamsController#index.GET.json only in report_a.txt
|
166
|
+
Api::V1::MisinterpretationsController#destroy.DELETE. only in report_a.txt
|
167
|
+
|
141
168
|
== What's missing
|
142
169
|
|
143
170
|
* More reports
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.plugin :email, :perforce # not on minitest yet
|
|
8
8
|
Hoe.spec 'nbogie-production_log_analyzer' do
|
9
9
|
developer 'Eric Hodel', 'drbrain@segment7.net'
|
10
10
|
self.name = 'nbogie-production_log_analyzer'
|
11
|
-
self.version = '1.5.1.
|
11
|
+
self.version = '1.5.1.2'
|
12
12
|
|
13
13
|
extra_deps << ['rails_analyzer_tools', '>= 1.4.0']
|
14
14
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'report/report_parser'
|
6
|
+
require 'report/report_differ'
|
7
|
+
|
8
|
+
class TestReportDiffer < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def file_data(filename)
|
11
|
+
'test/example_data/' + filename
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@differ = ReportDiffer.new
|
16
|
+
report_filenames = ['report_a', 'report_b'].map do |keyname|
|
17
|
+
"test/example_data/#{keyname}.txt"
|
18
|
+
end
|
19
|
+
create_reports()
|
20
|
+
#ReportDiffer.compare_files(report_filenames[0], report_filenames[1])
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_initialization
|
25
|
+
differ = ReportDiffer.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_compute_difference_in_values()
|
29
|
+
data = [
|
30
|
+
#when increasing
|
31
|
+
[100, 1000, 10],
|
32
|
+
[100, 200, 2],
|
33
|
+
[100, 130, 1.3],
|
34
|
+
#when same
|
35
|
+
[100, 100, 1],
|
36
|
+
[0,0, 1],
|
37
|
+
#when lessening
|
38
|
+
[100, 90, -1.11],
|
39
|
+
[100, 50, -2],
|
40
|
+
[100, 10, -10],
|
41
|
+
#when one number is zero - not sure what we should return here.
|
42
|
+
[0.00, 1, 999999],
|
43
|
+
[1, 0.00, -999999],
|
44
|
+
]
|
45
|
+
data.each do |group|
|
46
|
+
va, vb, expected = group
|
47
|
+
actual = @differ.compute_difference_in_values(va, vb)
|
48
|
+
assert_equal(expected, actual, "for #{va}->#{vb}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_compare
|
54
|
+
threshold = 1.2
|
55
|
+
actual=@differ.compare(@report_a, @report_b, threshold)
|
56
|
+
assert_not_nil actual
|
57
|
+
expected = {
|
58
|
+
:summary_diff=>
|
59
|
+
{
|
60
|
+
:diff_count=>{:change => -1.11, :from => 100, :to => 90},
|
61
|
+
:diff_avg_time=>{:change => 1.5, :from => 10, :to => 15},
|
62
|
+
:diff_min_time=>{:change => 1, :from => 0.1, :to => 0.1},
|
63
|
+
:diff_max_time=>{:change => 2.0, :from => 20.0, :to => 40.0},
|
64
|
+
:diff_std_dev=>{:change => 3.0, :from => 2.0, :to => 6.0}},
|
65
|
+
:request_diffs=>
|
66
|
+
{"MyCon#MyAc.get.xml"=>
|
67
|
+
{
|
68
|
+
:diff_count=>{:change => 1.1, :from => 100, :to => 110},
|
69
|
+
:diff_avg_time=>{:change => 1.2, :from => 100, :to => 120},
|
70
|
+
:diff_std_dev=>{:change => 1.3, :from => 100, :to => 130},
|
71
|
+
:diff_min_time=>{:change => 1.4, :from => 100, :to => 140},
|
72
|
+
:diff_max_time=>{:change => 1.5, :from => 100, :to => 150} }},
|
73
|
+
:unmatched_actions => [],
|
74
|
+
:threshold => threshold
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
assert_equal(expected, actual)
|
79
|
+
|
80
|
+
ra1 = Request.create('MyCon','MyAc2',600,1,1,1,1)
|
81
|
+
rb1 = Request.create('MyCon','MyAc2',610,1,1,1,1)
|
82
|
+
ra2 = Request.create('MyCon','MyAc3',50,1,1,1,1)
|
83
|
+
rb2 = Request.create('MyCon','MyAc3',50,1,1,1,1)
|
84
|
+
@report_a.requests << ra1 << ra2
|
85
|
+
@report_b.requests << rb1 << rb2
|
86
|
+
assert_equal 3, @report_a.requests.size
|
87
|
+
|
88
|
+
actual=@differ.compare(@report_a, @report_b, threshold)
|
89
|
+
end
|
90
|
+
def test_prepare_report()
|
91
|
+
diff_data = @differ.compare(@report_a, @report_b)
|
92
|
+
report_text = @differ.prepare_report(diff_data)
|
93
|
+
#TODO: check report text as as we expect
|
94
|
+
##puts report_text
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_matched_requests_values_ab
|
98
|
+
matches = @differ.find_matched_actions(@report_a, @report_b)
|
99
|
+
assert_equal 1, matches.size
|
100
|
+
assert_equal [100, 110], matches.first.values_ab(:count)
|
101
|
+
assert_equal [100, 120], matches.first.values_ab(:avg_time)
|
102
|
+
assert_equal [100, 130], matches.first.values_ab(:std_dev)
|
103
|
+
assert_equal [100, 140], matches.first.values_ab(:min_time)
|
104
|
+
assert_equal [100, 150], matches.first.values_ab(:max_time)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_find_matched_actions
|
108
|
+
matches = @differ.find_matched_actions(@report_a, @report_b)
|
109
|
+
assert_equal 1, matches.size
|
110
|
+
the_match=matches.first
|
111
|
+
assert_equal [@report_a.requests.first, @report_b.requests.first], [the_match.request1, the_match.request2]
|
112
|
+
|
113
|
+
#with one of the reports having NO requests
|
114
|
+
@report_a.requests.clear
|
115
|
+
assert_equal 0, @differ.find_matched_actions(@report_a, @report_b).size
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_find_unmatched_actions
|
119
|
+
#initially, should return empty list - all match
|
120
|
+
assert_equal [], @differ.find_unmatched_actions(@report_a, @report_b)
|
121
|
+
#add a request to only one report - should find it
|
122
|
+
odd_req = Request.create('MyCon','UniqueAction',110,120,130,140,150)
|
123
|
+
@report_a.requests << odd_req
|
124
|
+
unmatcheds = @differ.find_unmatched_actions(@report_a, @report_b)
|
125
|
+
assert_equal 1, unmatcheds.size
|
126
|
+
assert_equal 'UniqueAction', unmatcheds.first.request.action
|
127
|
+
assert_equal @report_a, unmatcheds.first.report
|
128
|
+
|
129
|
+
#add another request (only to rep b)
|
130
|
+
odd_req2 = Request.create('UniqueCon','MyAc',110,120,130,140,150)
|
131
|
+
@report_b.requests << odd_req2
|
132
|
+
unmatcheds = @differ.find_unmatched_actions(@report_a, @report_b)
|
133
|
+
assert_equal 2, unmatcheds.size
|
134
|
+
assert_equal 'UniqueAction', unmatcheds.first.request.action
|
135
|
+
assert_equal @report_a, unmatcheds.first.report
|
136
|
+
assert_equal 'UniqueCon', unmatcheds.last.request.controller
|
137
|
+
assert_equal @report_b, unmatcheds.last.report
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_compare_summaries
|
141
|
+
actual=@differ.compare_summaries(@report_a, @report_b)
|
142
|
+
assert_equal(
|
143
|
+
{
|
144
|
+
:diff_count=>{:change => -1.11, :from => 100, :to => 90},
|
145
|
+
:diff_avg_time=>{:change => 1.5, :from => 10, :to => 15},
|
146
|
+
:diff_std_dev=>{:change => 3.0, :from => 2.0, :to => 6.0},
|
147
|
+
:diff_min_time=>{:change => 1, :from => 0.1, :to => 0.1},
|
148
|
+
:diff_max_time=>{:change => 2.0, :from => 20.0, :to => 40.0},
|
149
|
+
}, actual)
|
150
|
+
end
|
151
|
+
|
152
|
+
#populate @report_a, @report_b
|
153
|
+
def create_reports
|
154
|
+
ra = Report.new
|
155
|
+
ra.summary.count=100
|
156
|
+
ra.summary.avg_time=10.0
|
157
|
+
ra.summary.std_dev=2.0
|
158
|
+
ra.summary.min_time=0.1
|
159
|
+
ra.summary.max_time=20.0
|
160
|
+
|
161
|
+
ca1 = Request.create('MyCon','MyAc',100,100,100,100,100, {:verb=>'get',:format =>'xml'})
|
162
|
+
cb1 = Request.create('MyCon','MyAc',110,120,130,140,150, {:verb=>'get',:format =>'xml'})
|
163
|
+
ra.requests << ca1
|
164
|
+
|
165
|
+
rb = Report.new
|
166
|
+
rb.summary.count=90
|
167
|
+
rb.summary.avg_time=15.0
|
168
|
+
rb.summary.std_dev=6
|
169
|
+
rb.summary.min_time=0.1
|
170
|
+
rb.summary.max_time=40.0
|
171
|
+
rb.requests << cb1
|
172
|
+
@report_a = ra
|
173
|
+
@report_b = rb
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
end
|
178
|
+
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'report/report_parser'
|
6
|
+
|
7
|
+
class TestReportParser < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def file_data(filename)
|
10
|
+
'test/example_data/' + filename
|
11
|
+
end
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@parser = ReportParser.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialization
|
18
|
+
parser = ReportParser.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_can_parse_report
|
22
|
+
content = File.read(file_data('example.txt'))
|
23
|
+
|
24
|
+
result = @parser.parse("my report name", content)
|
25
|
+
assert_not_nil(result)
|
26
|
+
assert_equal("my report name", result.name)
|
27
|
+
assert_equal(8, result.requests.size)
|
28
|
+
expected_controllers= %w(
|
29
|
+
FooController
|
30
|
+
FooController
|
31
|
+
FooController
|
32
|
+
FooController
|
33
|
+
BarController
|
34
|
+
HealthController
|
35
|
+
QuxController
|
36
|
+
UsersController)
|
37
|
+
assert_equal(expected_controllers, result.requests.map{|rq| rq.controller})
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_can_extract_from_all_requests
|
41
|
+
content = File.read(file_data('example.txt'))
|
42
|
+
result = @parser.parse("whatever", content)
|
43
|
+
assert_equal(11830,result.summary.count)
|
44
|
+
assert_equal(0.185,result.summary.avg_time)
|
45
|
+
assert_equal(0.212,result.summary.std_dev)
|
46
|
+
assert_equal(0.001,result.summary.min_time)
|
47
|
+
assert_equal(3.553,result.summary.max_time)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_can_parse_a_request
|
51
|
+
line = "ApiFooController#update.PUT.xml: 3557 0.144 0.137 0.059 3.212"
|
52
|
+
request = @parser.parse_request(line)
|
53
|
+
assert_equal("ApiFooController",request.controller)
|
54
|
+
assert_equal("update",request.action)
|
55
|
+
assert_equal("PUT",request.verb)
|
56
|
+
assert_equal("xml",request.format)
|
57
|
+
assert_equal(3557,request.count)
|
58
|
+
assert_equal(0.144,request.avg_time)
|
59
|
+
assert_equal(0.137,request.std_dev)
|
60
|
+
assert_equal(0.059,request.min_time)
|
61
|
+
assert_equal(3.212,request.max_time)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_should_normalize_request_format_to_lowercase
|
65
|
+
line = "ApiFooController#update.PUT.XmL: 3557 0.144 0.137 0.059 3.212"
|
66
|
+
request = @parser.parse_request(line)
|
67
|
+
assert_equal("xml",request.format)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_normalize_request_verb_to_uppercase
|
71
|
+
line = "ApiFooController#update.puT.xml: 3557 0.144 0.137 0.059 3.212"
|
72
|
+
request = @parser.parse_request(line)
|
73
|
+
assert_equal("PUT",request.verb)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_should_parse_request_having_no_format
|
77
|
+
line = "ApiFooController#update.GET: 3557 0.144 0.137 0.059 3.212"
|
78
|
+
request = @parser.parse_request(line)
|
79
|
+
assert_equal("GET",request.verb)
|
80
|
+
assert_nil(request.format)
|
81
|
+
assert_equal(0.144,request.avg_time)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_can_parse_a_request_having_module_named_controller_name
|
85
|
+
line = "Api::V1::FooController#show.GET: 11707 0.107 0.263 0.015 19.075"
|
86
|
+
request = @parser.parse_request(line)
|
87
|
+
assert_equal("Api::V1::FooController",request.controller)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_should_parse_a_few_lines
|
91
|
+
should_parse "QuxController#index.GET.rss: 5 0.241 0.078 0.121 0.367"
|
92
|
+
end
|
93
|
+
|
94
|
+
def should_parse(line)
|
95
|
+
@parser.parse_request(line)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
class TestRequest < Test::Unit::TestCase
|
101
|
+
def test_remembers_its_values
|
102
|
+
r = Request.new
|
103
|
+
r.controller = "somecontroller"
|
104
|
+
r.action = "someaction"
|
105
|
+
r.verb = "GET"
|
106
|
+
r.format = "xml"
|
107
|
+
r.count = 100
|
108
|
+
r.avg_time = 1.123
|
109
|
+
r.std_dev = 0.22
|
110
|
+
r.min_time = 3.33
|
111
|
+
r.max_time = 10.10
|
112
|
+
assert_equal("somecontroller",r.controller)
|
113
|
+
assert_equal("someaction",r.action)
|
114
|
+
assert_equal("GET",r.verb)
|
115
|
+
assert_equal("xml",r.format)
|
116
|
+
assert_equal(3.33,r.min_time)
|
117
|
+
assert_equal(10.10,r.max_time)
|
118
|
+
assert_equal(1.123,r.avg_time)
|
119
|
+
assert_equal(0.22,r.std_dev)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_create
|
123
|
+
req = Request.create('Con','Ac',1,2,3,4,5, {:verb=>'get',:format =>'xml'})
|
124
|
+
assert_equal('Con', req.controller)
|
125
|
+
assert_equal('Ac', req.action)
|
126
|
+
assert_equal(1, req.count)
|
127
|
+
assert_equal(2, req.avg_time)
|
128
|
+
assert_equal(3, req.std_dev)
|
129
|
+
assert_equal(4, req.min_time)
|
130
|
+
assert_equal(5, req.max_time)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_should_not_fixup_already_fixed_up_name
|
134
|
+
r = Request.new
|
135
|
+
r.controller = "Api::V1::GraultController"
|
136
|
+
r.fixup_controller_name!
|
137
|
+
assert_equal("Api::V1::GraultController",r.controller)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nbogie-production_log_analyzer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 119
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 1
|
7
8
|
- 5
|
8
9
|
- 1
|
9
|
-
-
|
10
|
-
version: 1.5.1.
|
10
|
+
- 2
|
11
|
+
version: 1.5.1.2
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Eric Hodel
|
@@ -15,16 +16,17 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date:
|
19
|
-
default_executable:
|
19
|
+
date: 2011-07-07 00:00:00 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: rails_analyzer_tools
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
28
30
|
segments:
|
29
31
|
- 1
|
30
32
|
- 4
|
@@ -33,33 +35,21 @@ dependencies:
|
|
33
35
|
type: :runtime
|
34
36
|
version_requirements: *id001
|
35
37
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
38
|
+
name: hoe
|
37
39
|
prerelease: false
|
38
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
39
42
|
requirements:
|
40
43
|
- - ">="
|
41
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 35
|
42
46
|
segments:
|
43
47
|
- 2
|
44
|
-
-
|
48
|
+
- 9
|
45
49
|
- 4
|
46
|
-
version: 2.
|
50
|
+
version: 2.9.4
|
47
51
|
type: :development
|
48
52
|
version_requirements: *id002
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: hoe
|
51
|
-
prerelease: false
|
52
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
-
requirements:
|
54
|
-
- - ">="
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
segments:
|
57
|
-
- 2
|
58
|
-
- 6
|
59
|
-
- 0
|
60
|
-
version: 2.6.0
|
61
|
-
type: :development
|
62
|
-
version_requirements: *id003
|
63
53
|
description: |-
|
64
54
|
production_log_analyzer lets you find out which actions on a Rails
|
65
55
|
site are slowing you down.
|
@@ -99,7 +89,9 @@ files:
|
|
99
89
|
- test/test_action_grep.rb
|
100
90
|
- test/test_analyzer.rb
|
101
91
|
- test/test_parser.rb
|
102
|
-
|
92
|
+
- test/test_report_differ.rb
|
93
|
+
- test/test_report_parser.rb
|
94
|
+
- .gemtest
|
103
95
|
homepage: http://seattlerb.rubyforge.org/production_log_analyzer
|
104
96
|
licenses: []
|
105
97
|
|
@@ -110,27 +102,33 @@ rdoc_options:
|
|
110
102
|
require_paths:
|
111
103
|
- lib
|
112
104
|
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
113
106
|
requirements:
|
114
107
|
- - ">="
|
115
108
|
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
116
110
|
segments:
|
117
111
|
- 0
|
118
112
|
version: "0"
|
119
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
120
115
|
requirements:
|
121
116
|
- - ">="
|
122
117
|
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
123
119
|
segments:
|
124
120
|
- 0
|
125
121
|
version: "0"
|
126
122
|
requirements: []
|
127
123
|
|
128
124
|
rubyforge_project: nbogie-production_log_analyzer
|
129
|
-
rubygems_version: 1.
|
125
|
+
rubygems_version: 1.8.5
|
130
126
|
signing_key:
|
131
127
|
specification_version: 3
|
132
128
|
summary: production_log_analyzer lets you find out which actions on a Rails site are slowing you down
|
133
129
|
test_files:
|
134
130
|
- test/test_parser.rb
|
135
131
|
- test/test_analyzer.rb
|
132
|
+
- test/test_report_differ.rb
|
136
133
|
- test/test_action_grep.rb
|
134
|
+
- test/test_report_parser.rb
|