Narnach-rails_analyzer 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +58 -0
- data/Rakefile +28 -0
- data/bin/rails_analyzer +5 -0
- data/lib/array_ext.rb +51 -0
- data/lib/entries.rb +19 -0
- data/lib/float_ext.rb +18 -0
- data/lib/hit_stats.rb +64 -0
- data/lib/rails_analyzer.rb +23 -0
- data/lib/time_stats.rb +79 -0
- data/lib/url_hits.rb +36 -0
- data/rails_analyzer.gemspec +33 -0
- data/spec/entries_spec.rb +46 -0
- data/spec/rails_analyzer_spec.rb +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/url_hits_spec.rb +16 -0
- metadata +75 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Wes Oldenbeuving
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
== RailsAnalyzer
|
2
|
+
RailsAnalyzer generates reports about requests processed by a Ruby on Rails server.
|
3
|
+
|
4
|
+
It analyzes the log files created by a Rails server. It can accept any number of files as its command line parameters. It defaults to use 'log/production.log' as its input when no filenames are provided.
|
5
|
+
|
6
|
+
Two different reporting engines process the log files:
|
7
|
+
* TimeStats, which is concerned with *when* the request was made. It produces reports with the amount of hits recorded in the log file per time interval, and the relative amount of requests within a time interval. The relative interval simply lowers all hit counts until one hits zero. This makes it easy to filter out periodic requests.
|
8
|
+
* HitStats, which is concerned with how *fast* the requests were handled. It produces reports with detailed time statistics for each request. It has two types of reports: with params and without params. Each type of report produces a number of files, each which is sorted by one of the following statistics for responses: fastest, slowest, sum, average, median, standard deviation and hit count.
|
9
|
+
Both engines produce .txt files as their only output.
|
10
|
+
* TimeStats produces log_times_*.txt and log_times_*_relative.txt output.
|
11
|
+
* HitStats produces the other log_*.txt and log_*_with_params.txt files.
|
12
|
+
|
13
|
+
== Recent changes
|
14
|
+
|
15
|
+
=== Version 0.2.2
|
16
|
+
Added reports for slowest and fastest requests.
|
17
|
+
Documentation updates.
|
18
|
+
|
19
|
+
=== Version 0.2.1
|
20
|
+
Bugfixes:
|
21
|
+
* HitStats reports were not generated. They are working again.
|
22
|
+
* Array#median always returns a float to prevent integer math (lack of) rounding problems.
|
23
|
+
Dependencies:
|
24
|
+
* No longer rely on ActiveSupport. It was used for Array#sum and Array#group_by, which are now implemented in ArrayExt.
|
25
|
+
Specs:
|
26
|
+
* Parts of UrlHits and Entries got specs to help debugging the HitStats bug.
|
27
|
+
* Added specs for all ArrayExt methods.
|
28
|
+
|
29
|
+
=== Version 0.2.0
|
30
|
+
Split single-file script into one file per existing class.
|
31
|
+
Introduced new classes to handle responsibilities that were not yet handled.
|
32
|
+
Changed classes involved in generating URL hits-based reports to be more flexible.
|
33
|
+
Generally refactored a lot of non-DRY code to be at least a bit nicer.
|
34
|
+
|
35
|
+
=== Version 0.1.0
|
36
|
+
Imported single-file script
|
37
|
+
|
38
|
+
== Installation
|
39
|
+
=== From gem
|
40
|
+
The gem is located on github.
|
41
|
+
gem install Narnach-rails_analyzer -s http://gems.github.com
|
42
|
+
=== From git
|
43
|
+
From the project root, use rake to install:
|
44
|
+
git clone git://github.com/Narnach/rails_analyzer.git
|
45
|
+
cd rails_analyzer
|
46
|
+
rake install
|
47
|
+
This will build the gem and install it for you.
|
48
|
+
|
49
|
+
== Syntax
|
50
|
+
rails_analyzer [log_file1] [log_file2] [..] [log_fileN]
|
51
|
+
When no log files are provided, log/production.log is used.
|
52
|
+
|
53
|
+
== About
|
54
|
+
|
55
|
+
Author:: Wes 'Narnach' Oldenbeuving (narnach@gmail.com)
|
56
|
+
Website:: http://www.github.com/Narnach/rails_analyzer
|
57
|
+
Copyright:: Copyright (c) 2008 Wes Oldenbeuving
|
58
|
+
License:: MIT license. See MIT-LICENSE (in the gem directory) for license details.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
################################################################################
|
7
|
+
### Gem
|
8
|
+
################################################################################
|
9
|
+
|
10
|
+
begin
|
11
|
+
# Parse gemspec using the github safety level.
|
12
|
+
file = Dir['*.gemspec'].first
|
13
|
+
data = File.read(file)
|
14
|
+
spec = nil
|
15
|
+
Thread.new { spec = eval("$SAFE = 3\n%s" % data)}.join
|
16
|
+
|
17
|
+
# Create the gem tasks
|
18
|
+
Rake::GemPackageTask.new(spec) do |package|
|
19
|
+
package.gem_spec = spec
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
printf "WARNING: Error caught (%s): %s\n%s", e.class.name, e.message, e.backtrace[0...5].map {|l| ' %s' % l}.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Package and install the gem for the current version'
|
26
|
+
task :install => :gem do
|
27
|
+
system "sudo gem install -l pkg/%s-%s.gem" % [spec.name, spec.version]
|
28
|
+
end
|
data/bin/rails_analyzer
ADDED
data/lib/array_ext.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module ArrayExt
|
2
|
+
module GroupBy
|
3
|
+
# Returns a Hash:
|
4
|
+
# - The keys are grouping values
|
5
|
+
# - The values are an Array with values grouped to that key.
|
6
|
+
def group_by(&block)
|
7
|
+
grouped_results = Hash.new { |hash, key| hash[key] = Array.new }
|
8
|
+
each do |element|
|
9
|
+
group_key = block.call(element)
|
10
|
+
grouped_results[group_key] << element
|
11
|
+
end
|
12
|
+
grouped_results
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Stats
|
17
|
+
def avg
|
18
|
+
sum / size.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the median as a Float.
|
22
|
+
def median
|
23
|
+
return 0 if size == 0
|
24
|
+
if size%2==0
|
25
|
+
# Average two middle values
|
26
|
+
# [1,2,3,4,5,6].median #=> 3.5
|
27
|
+
(self[size / 2] + self[size / 2 - 1]) / 2.0
|
28
|
+
else
|
29
|
+
# Use middle value
|
30
|
+
# [1,2,3,4,5].median #=> 3
|
31
|
+
self[size / 2].to_f
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def stddev
|
36
|
+
avg_cached = avg # prevent having to recompute it each time
|
37
|
+
squared_deviations = map {|n| (n - avg_cached) ** 2 }
|
38
|
+
variance = squared_deviations.avg
|
39
|
+
Math::sqrt(variance)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sum
|
43
|
+
inject(0.0) {|s,n| s+n }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Array
|
49
|
+
include ArrayExt::GroupBy
|
50
|
+
include ArrayExt::Stats
|
51
|
+
end
|
data/lib/entries.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'url_hits'
|
2
|
+
|
3
|
+
class Entries
|
4
|
+
attr_accessor :entries
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@entries = Hash.new { |hash, url| hash[url] = UrlHits.new(url) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_hit(url, time)
|
11
|
+
entries[url].add_hit(time)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s(sort=:size)
|
15
|
+
sorted = entries.values.sort {|a,b| b.send(sort) <=> a.send(sort) }
|
16
|
+
head = ('%6s ' + '%6s '*5 + '%9s %s') % %w[Hits Low Median Avg Stddev High Sum Url]
|
17
|
+
head << "\n" << sorted.join("\n")
|
18
|
+
end
|
19
|
+
end
|
data/lib/float_ext.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Add decent rounding to X decimals.
|
2
|
+
module FloatExt
|
3
|
+
def round_to(x=4)
|
4
|
+
(self * 10**x).round.to_f / 10**x
|
5
|
+
end
|
6
|
+
|
7
|
+
def ceil_to(x=4)
|
8
|
+
(self * 10**x).ceil.to_f / 10**x
|
9
|
+
end
|
10
|
+
|
11
|
+
def floor_to(x=4)
|
12
|
+
(self * 10**x).floor.to_f / 10**x
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Float
|
17
|
+
include FloatExt
|
18
|
+
end
|
data/lib/hit_stats.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'entries'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class HitStats
|
5
|
+
attr_accessor :logs, :hits_with_query, :hits_without_query
|
6
|
+
|
7
|
+
def initialize(logs)
|
8
|
+
@logs = logs
|
9
|
+
@hits_with_query = Entries.new
|
10
|
+
@hits_without_query = Entries.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.generate(logs)
|
14
|
+
hs = self.new(logs)
|
15
|
+
hs.parse_logs
|
16
|
+
hs.save_reports
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_logs
|
20
|
+
logs.each do |log|
|
21
|
+
parse_log(log)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def save_reports
|
26
|
+
[:sum, :avg, :size, :median, :stddev, :min, :max].each do |sort_order|
|
27
|
+
File.open("log_%s.txt" % name_for_sort_order(sort_order),"wb") {|file| file.puts hits_without_query.to_s(sort_order) }
|
28
|
+
File.open('log_%s_with_params.txt' % name_for_sort_order(sort_order), 'wb') {|file| file.puts hits_with_query.to_s(sort_order)}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def name_for_sort_order(order)
|
35
|
+
{
|
36
|
+
:size => 'hits',
|
37
|
+
:min => 'low',
|
38
|
+
:max => 'high',
|
39
|
+
}[order] || order
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_log(log)
|
43
|
+
results = `grep "Completed" #{log}`
|
44
|
+
results.each do |line|
|
45
|
+
parse_line(line)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_line(line)
|
50
|
+
unless line =~ /\[(.*?)\]/
|
51
|
+
puts "Failed to parse: #{line}"
|
52
|
+
return
|
53
|
+
end
|
54
|
+
return unless uri=URI.parse($1) rescue nil
|
55
|
+
unless line =~ /Completed\ in\ ([0-9]+\.[0-9]+)/
|
56
|
+
puts "Could not extract time from line: #{line}"
|
57
|
+
return
|
58
|
+
end
|
59
|
+
time = $1.to_f
|
60
|
+
hits_with_query.add_hit(uri.to_s,time)
|
61
|
+
uri.query=nil
|
62
|
+
hits_without_query.add_hit(uri.to_s,time)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'time_stats'
|
2
|
+
require 'hit_stats'
|
3
|
+
|
4
|
+
class RailsAnalyzer
|
5
|
+
attr_accessor :logs
|
6
|
+
|
7
|
+
def initialize(logs=[])
|
8
|
+
@logs = logs
|
9
|
+
@logs = %w[log/production.log] if logs.size==0
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_reports
|
13
|
+
puts "RailsAnalyzer"
|
14
|
+
puts "Analyzes the following Rails log files:"
|
15
|
+
puts logs.map{|l| ' %s' % l}.join("\n")
|
16
|
+
|
17
|
+
puts 'Generating time-based reports'
|
18
|
+
TimeStats.generate(logs)
|
19
|
+
|
20
|
+
puts 'Generating hit-based reports'
|
21
|
+
HitStats.generate(logs)
|
22
|
+
end
|
23
|
+
end
|
data/lib/time_stats.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'array_ext'
|
2
|
+
|
3
|
+
class TimeStats
|
4
|
+
attr_accessor :logs, :times
|
5
|
+
|
6
|
+
def initialize(logs)
|
7
|
+
@times = []
|
8
|
+
@logs = logs
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.generate(logs)
|
12
|
+
ts = new(logs)
|
13
|
+
ts.parse_files
|
14
|
+
ts.save_reports
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_files
|
18
|
+
logs.each do |log|
|
19
|
+
results = `grep "Processing" #{log}`
|
20
|
+
timestamps = results.map { |line| (line =~ /Processing.*\(for .* at (\d+-\d+-\d+ \d+:\d+:\d+)\)/) ? $1 : nil}.compact
|
21
|
+
times.concat(timestamps)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def save_reports
|
26
|
+
%w[day hour day_hour].each do |timeframe|
|
27
|
+
filename = 'log_times_%s.txt' % timeframe
|
28
|
+
save_hits_report(filename, timeframe)
|
29
|
+
end
|
30
|
+
%w[hour ten_min].each do |timeframe|
|
31
|
+
hits = self.send('per_%s' % timeframe).map {|frame, hits| hits.size}
|
32
|
+
offset = hits.min || 0
|
33
|
+
filename = 'log_times_%s_relative.txt' % timeframe
|
34
|
+
save_hits_report(filename, timeframe, offset)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def save_hits_report(filename, timeframe, offset = 0)
|
41
|
+
collection = self.send('per_%s' % timeframe)
|
42
|
+
File.open(filename,'wb') do |f|
|
43
|
+
collection.each do |frame, hits|
|
44
|
+
f.puts '%s: %s' % [frame, hits.size - offset]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def per_day_hour
|
50
|
+
group_times_by {|d, h, m, s| '%s %sh' % [d, h]}
|
51
|
+
end
|
52
|
+
|
53
|
+
def per_day
|
54
|
+
group_times_by {|d, h, m, s| d}
|
55
|
+
end
|
56
|
+
|
57
|
+
def per_hour
|
58
|
+
group_times_by {|d, h, m, s| h}
|
59
|
+
end
|
60
|
+
|
61
|
+
def per_ten_min
|
62
|
+
group_times_by {|d, h, m, s| '%sh%s0' % [h, m[0,1]]}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Group times by date/time-related data.
|
66
|
+
# Sorts by the yield return value
|
67
|
+
# Returns an Array of two-element Arrays:
|
68
|
+
# - The first element is the sort key
|
69
|
+
# - The second element is the hit times for that key
|
70
|
+
# The return value is sorted by key.
|
71
|
+
def group_times_by(&block) # :yields: date, hour, min, sec
|
72
|
+
grouped_times = times.group_by do |t|
|
73
|
+
date, time = t.split(" ")
|
74
|
+
hour, min, sec = time.split(":")
|
75
|
+
block.call(date, hour, min, sec)
|
76
|
+
end
|
77
|
+
grouped_times.to_a.sort {|a,b| a.first <=> b.first}
|
78
|
+
end
|
79
|
+
end
|
data/lib/url_hits.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'float_ext'
|
2
|
+
require 'array_ext'
|
3
|
+
|
4
|
+
class UrlHits
|
5
|
+
attr_reader :url, :hits
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
9
|
+
@hits = Array.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_hit(time)
|
13
|
+
hits << time
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
'%6i %s %s' % [size, time_stats, @url]
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
(other.class == self.class) && (other.url == self.url) && (other.hits == self.hits)
|
22
|
+
end
|
23
|
+
|
24
|
+
[:size, :min, :max, :sum, :stddev, :median, :avg].each do |op|
|
25
|
+
define_method(op) do
|
26
|
+
hits.send(op)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def time_stats
|
33
|
+
return nil unless size > 0
|
34
|
+
'%3.03f %3.03f %3.03f %3.03f %3.03f %6.03f' % [min, median, avg, stddev, max, sum]
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
# Project
|
3
|
+
s.name = 'rails_analyzer'
|
4
|
+
s.summary = "RailsAnalyzer generates reports about requests processed by a Ruby on Rails server."
|
5
|
+
s.description = "RailsAnalyzer generates reports about requests processed by a Ruby on Rails server."
|
6
|
+
s.version = '0.2.2'
|
7
|
+
s.date = '2008-09-15'
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Wes Oldenbeuving"]
|
10
|
+
s.email = "narnach@gmail.com"
|
11
|
+
s.homepage = "http://www.github.com/Narnach/rails_analyzer"
|
12
|
+
|
13
|
+
# Files
|
14
|
+
root_files = %w[MIT-LICENSE README.rdoc Rakefile rails_analyzer.gemspec]
|
15
|
+
bin_files = %w[rails_analyzer]
|
16
|
+
lib_files = %w[rails_analyzer array_ext float_ext time_stats hit_stats entries url_hits]
|
17
|
+
test_files = %w[]
|
18
|
+
spec_files = %w[rails_analyzer entries url_hits]
|
19
|
+
other_files = %w[spec/spec.opts spec/spec_helper.rb]
|
20
|
+
s.bindir = "bin"
|
21
|
+
s.require_path = "lib"
|
22
|
+
s.executables = bin_files
|
23
|
+
s.test_files = test_files.map {|f| 'test/%s_test.rb' % f} + spec_files.map {|f| 'spec/%s_spec.rb' % f}
|
24
|
+
s.files = root_files + s.test_files + other_files + bin_files.map {|f| 'bin/%s' % f} + lib_files.map {|f| 'lib/%s.rb' % f}
|
25
|
+
|
26
|
+
# rdoc
|
27
|
+
s.has_rdoc = true
|
28
|
+
s.extra_rdoc_files = %w[ README.rdoc MIT-LICENSE]
|
29
|
+
s.rdoc_options << '--inline-source' << '--line-numbers' << '--main' << 'README.rdoc'
|
30
|
+
|
31
|
+
# Requirements
|
32
|
+
s.required_ruby_version = ">= 1.8.0"
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'entries'
|
3
|
+
|
4
|
+
describe Entries do
|
5
|
+
describe '#add_hit' do
|
6
|
+
it 'should be stored grouped per URL' do
|
7
|
+
u = 'http://www.example.org'
|
8
|
+
u2 = 'http://www2.example.org'
|
9
|
+
uh1 = UrlHits.new(u)
|
10
|
+
uh1.add_hit(0.1)
|
11
|
+
uh2 = UrlHits.new(u)
|
12
|
+
uh2.add_hit(0.1)
|
13
|
+
uh2.add_hit(0.2)
|
14
|
+
uh3 = UrlHits.new(u)
|
15
|
+
uh3.add_hit(0.1)
|
16
|
+
uh3.add_hit(0.2)
|
17
|
+
uh3.add_hit(0.3)
|
18
|
+
uh4 = UrlHits.new(u2)
|
19
|
+
uh4.add_hit(0.1)
|
20
|
+
|
21
|
+
e = Entries.new
|
22
|
+
e.entries.should == {}
|
23
|
+
e.add_hit(u, 0.1)
|
24
|
+
e.entries.should == {u => uh1}
|
25
|
+
e.add_hit(u, 0.2)
|
26
|
+
e.entries.should == {u => uh2}
|
27
|
+
e.add_hit(u, 0.3)
|
28
|
+
e.entries.should == {u => uh3}
|
29
|
+
e.add_hit(u2, 0.1)
|
30
|
+
e.entries.should == {u => uh3, u2 => uh4}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#to_s' do
|
35
|
+
it "should return a summary of the url hit times" do
|
36
|
+
e = Entries.new
|
37
|
+
e.add_hit('http://www.example.org', 0.1)
|
38
|
+
e.add_hit('http://www.example.org', 0.2)
|
39
|
+
e.add_hit('http://www.example.org', 0.3)
|
40
|
+
expected_output = '' + \
|
41
|
+
' Hits Low Median Avg Stddev High Sum Url' + "\n" + \
|
42
|
+
' 3 0.100 0.200 0.200 0.082 0.300 0.600 http://www.example.org'
|
43
|
+
e.to_s.should == expected_output
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'url_hits'
|
3
|
+
|
4
|
+
describe UrlHits do
|
5
|
+
describe '#to_s' do
|
6
|
+
it "should return a summary of the url hit times" do
|
7
|
+
uh = UrlHits.new('http://www.example.org')
|
8
|
+
uh.add_hit(0.1)
|
9
|
+
uh.to_s.should == ' 1 0.100 0.100 0.100 0.000 0.100 0.100 http://www.example.org'
|
10
|
+
uh.add_hit(0.2)
|
11
|
+
uh.to_s.should == ' 2 0.100 0.150 0.150 0.050 0.200 0.300 http://www.example.org'
|
12
|
+
uh.add_hit(0.3)
|
13
|
+
uh.to_s.should == ' 3 0.100 0.200 0.200 0.082 0.300 0.600 http://www.example.org'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Narnach-rails_analyzer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wes Oldenbeuving
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-09-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: RailsAnalyzer generates reports about requests processed by a Ruby on Rails server.
|
17
|
+
email: narnach@gmail.com
|
18
|
+
executables:
|
19
|
+
- rails_analyzer
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- MIT-LICENSE
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- rails_analyzer.gemspec
|
30
|
+
- spec/rails_analyzer_spec.rb
|
31
|
+
- spec/entries_spec.rb
|
32
|
+
- spec/url_hits_spec.rb
|
33
|
+
- spec/spec.opts
|
34
|
+
- spec/spec_helper.rb
|
35
|
+
- bin/rails_analyzer
|
36
|
+
- lib/rails_analyzer.rb
|
37
|
+
- lib/array_ext.rb
|
38
|
+
- lib/float_ext.rb
|
39
|
+
- lib/time_stats.rb
|
40
|
+
- lib/hit_stats.rb
|
41
|
+
- lib/entries.rb
|
42
|
+
- lib/url_hits.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://www.github.com/Narnach/rails_analyzer
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options:
|
47
|
+
- --inline-source
|
48
|
+
- --line-numbers
|
49
|
+
- --main
|
50
|
+
- README.rdoc
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.8.0
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.2.0
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: RailsAnalyzer generates reports about requests processed by a Ruby on Rails server.
|
72
|
+
test_files:
|
73
|
+
- spec/rails_analyzer_spec.rb
|
74
|
+
- spec/entries_spec.rb
|
75
|
+
- spec/url_hits_spec.rb
|