wvanbergen-request-log-analyzer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +119 -0
- data/Rakefile +43 -0
- data/TODO +20 -0
- data/bin/request-log-analyzer +95 -0
- data/bin/request-log-database +79 -0
- data/lib/bashcolorizer.rb +60 -0
- data/lib/command_line/arguments.rb +129 -0
- data/lib/command_line/exceptions.rb +37 -0
- data/lib/command_line/flag.rb +51 -0
- data/lib/rails_analyzer/log_parser.rb +83 -0
- data/lib/rails_analyzer/record_inserter.rb +161 -0
- data/lib/rails_analyzer/summarizer.rb +121 -0
- data/lib/ruby-progressbar/progressbar.en.rd +103 -0
- data/lib/ruby-progressbar/progressbar.ja.rd +100 -0
- data/lib/ruby-progressbar/progressbar.rb +236 -0
- data/output/blockers.rb +11 -0
- data/output/errors.rb +9 -0
- data/output/hourly_spread.rb +28 -0
- data/output/mean_db_time.rb +7 -0
- data/output/mean_rendering_time.rb +7 -0
- data/output/mean_time.rb +7 -0
- data/output/most_requested.rb +6 -0
- data/output/timespan.rb +9 -0
- data/output/total_db_time.rb +6 -0
- data/output/total_time.rb +6 -0
- data/output/usage.rb +14 -0
- data/test/log_fragments/fragment_1.log +59 -0
- data/test/log_fragments/fragment_2.log +5 -0
- data/test/log_parser_test.rb +85 -0
- data/test/record_inserter_test.rb +42 -0
- data/test/tasks.rake +8 -0
- metadata +95 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module RailsAnalyzer
|
4
|
+
# Parse a rails log file
|
5
|
+
class LogParser
|
6
|
+
|
7
|
+
LOG_LINES = {
|
8
|
+
# Processing EmployeeController#index (for 123.123.123.123 at 2008-07-13 06:00:00) [GET]
|
9
|
+
:started => {
|
10
|
+
:teaser => /Processing/,
|
11
|
+
:regexp => /Processing (\w+)#(\w+) \(for (\d+\.\d+\.\d+\.\d+) at (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\) \[([A-Z]+)\]/,
|
12
|
+
:params => { :controller => 1, :action => 2, :ip => 3, :timestamp => 4, :method => 5}
|
13
|
+
},
|
14
|
+
# RuntimeError (Cannot destroy employee): /app/models/employee.rb:198:in `before_destroy'
|
15
|
+
:failed => {
|
16
|
+
:teaser => /Error/,
|
17
|
+
:regexp => /(\w+)(Error|Invalid) \((.*)\)\:(.*)/,
|
18
|
+
:params => { :error => 1, :exception_string => 3, :stack_trace => 4 }
|
19
|
+
},
|
20
|
+
# Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]
|
21
|
+
:completed => {
|
22
|
+
:teaser => /Completed/,
|
23
|
+
:regexp => /Completed in (\d+\.\d{5}) \(\d+ reqs\/sec\) (\| Rendering: (\d+\.\d{5}) \(\d+\%\) )?(\| DB: (\d+\.\d{5}) \(\d+\%\) )?\| (\d\d\d).+\[(http.+)\]/,
|
24
|
+
:params => { :url => 7, :status => [6, :to_i], :duration => [1, :to_f], :rendering => [3, :to_f], :db => [5, :to_f] }
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
# LogParser initializer
|
29
|
+
# <tt>file</tt> The fileobject this LogParser wil operate on.
|
30
|
+
def initialize(file, options = {})
|
31
|
+
@file_name = file
|
32
|
+
@options = options
|
33
|
+
@file_size = File.size(@file_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def progress(&block)
|
37
|
+
@progress_handler = block
|
38
|
+
end
|
39
|
+
|
40
|
+
# Output a warning
|
41
|
+
# <tt>message</tt> The warning message (object)
|
42
|
+
def warn(message)
|
43
|
+
puts " -> " + message.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# Finds a log line and then parses the information in the line.
|
47
|
+
# Yields a hash containing the information found.
|
48
|
+
# <tt>*line_types</tt> The log line types to look for (defaults to LOG_LINES.keys).
|
49
|
+
# Yeilds a Hash when it encounters a chunk of information.
|
50
|
+
def each(*line_types, &block)
|
51
|
+
# parse everything by default
|
52
|
+
line_types = LOG_LINES.keys if line_types.empty?
|
53
|
+
|
54
|
+
File.open(@file_name) do |file|
|
55
|
+
|
56
|
+
file.each_line do |line|
|
57
|
+
|
58
|
+
@progress_handler.call(file.pos, @file_size) if @progress_handler
|
59
|
+
|
60
|
+
line_types.each do |line_type|
|
61
|
+
if LOG_LINES[line_type][:teaser] =~ line
|
62
|
+
if LOG_LINES[line_type][:regexp] =~ line
|
63
|
+
request = { :type => line_type, :line => file.lineno }
|
64
|
+
LOG_LINES[line_type][:params].each do |key, value|
|
65
|
+
request[key] = case value
|
66
|
+
when Numeric; $~[value]
|
67
|
+
when Array; $~[value.first].send(value.last)
|
68
|
+
else; nil
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
yield(request) if block_given?
|
73
|
+
else
|
74
|
+
warn("Unparsable #{line_type} line: " + line[0..79]) unless line_type == :failed
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@progress_handler.call(:finished, @file_size) if @progress_handler
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sqlite3'
|
3
|
+
|
4
|
+
module RailsAnalyzer
|
5
|
+
|
6
|
+
# Set of functions that can be used to easily log requests into a SQLite3 Database.
|
7
|
+
class RecordInserter
|
8
|
+
|
9
|
+
attr_reader :database
|
10
|
+
attr_reader :current_request
|
11
|
+
attr_reader :warning_count
|
12
|
+
|
13
|
+
# Initializer
|
14
|
+
# <tt>db_file</tt> The file which will be used for the SQLite3 Database storage.
|
15
|
+
def initialize(db_file)
|
16
|
+
@database = SQLite3::Database.new(db_file)
|
17
|
+
@insert_statements = nil
|
18
|
+
@warning_count = 0
|
19
|
+
create_tables_if_needed!
|
20
|
+
end
|
21
|
+
|
22
|
+
# Calculate the database durations of the requests currenty in the database.
|
23
|
+
# Used if a logfile does contain any database durations.
|
24
|
+
def calculate_db_durations!
|
25
|
+
@database.execute('UPDATE "completed_queries" SET "database" = "duration" - "rendering" WHERE "database" IS NULL OR "database" = 0.0')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Insert a batch of loglines into the database.
|
29
|
+
# Function prepares insert statements, yeilds and then closes and commits.
|
30
|
+
def insert_batch(&block)
|
31
|
+
@database.transaction
|
32
|
+
prepare_statements!
|
33
|
+
block.call(self)
|
34
|
+
close_prepared_statements!
|
35
|
+
@database.commit
|
36
|
+
rescue Exception => e
|
37
|
+
puts e.message
|
38
|
+
@database.rollback
|
39
|
+
end
|
40
|
+
|
41
|
+
def insert_warning(line, warning)
|
42
|
+
@database.execute("INSERT INTO parse_warnings (line, warning) VALUES (:line, :warning)", :line => line, :warning => warning)
|
43
|
+
@warning_count += 1
|
44
|
+
end
|
45
|
+
|
46
|
+
# Insert a request into the database.
|
47
|
+
# <tt>request</tt> The request to insert.
|
48
|
+
# <tt>close_statements</tt> Close prepared statements (default false)
|
49
|
+
def insert(request, close_statements = false)
|
50
|
+
unless @insert_statements
|
51
|
+
prepare_statements!
|
52
|
+
close_statements = true
|
53
|
+
end
|
54
|
+
|
55
|
+
if request[:type] && @insert_statements.has_key?(request[:type])
|
56
|
+
if request[:type] == :started
|
57
|
+
insert_warning(request[:line], "Unclosed request encountered on line #{request[:line]} (request started on line #{@current_request})") unless @current_request.nil?
|
58
|
+
@current_request = request[:line]
|
59
|
+
elsif [:failed, :completed].include?(request[:type])
|
60
|
+
@current_request = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
@insert_statements[request.delete(:type)].execute(request)
|
65
|
+
rescue SQLite3::Exception => e
|
66
|
+
insert_warning(request[:line], "Could not save log line to database: " + e.message.to_s)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
insert_warning(request[:line], "Ignored unknown statement type")
|
70
|
+
end
|
71
|
+
|
72
|
+
close_prepared_statements! if close_statements
|
73
|
+
end
|
74
|
+
|
75
|
+
# Insert a batch of files into the database.
|
76
|
+
# <tt>db_file</tt> The filename of the database file to use.
|
77
|
+
# Returns the created database.
|
78
|
+
def self.insert_batch_into(db_file, options = {}, &block)
|
79
|
+
db = RecordInserter.new(db_file)
|
80
|
+
db.insert_batch(&block)
|
81
|
+
return db
|
82
|
+
end
|
83
|
+
|
84
|
+
def count(type)
|
85
|
+
@database.get_first_value("SELECT COUNT(*) FROM \"#{type}_requests\"").to_i
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
|
90
|
+
# Prepare insert statements.
|
91
|
+
def prepare_statements!
|
92
|
+
@insert_statements = {
|
93
|
+
:started => @database.prepare("
|
94
|
+
INSERT INTO started_requests ( line, timestamp, ip, method, controller, action)
|
95
|
+
VALUES (:line, :timestamp, :ip, :method, :controller, :action)"),
|
96
|
+
|
97
|
+
:failed => @database.prepare("
|
98
|
+
INSERT INTO failed_requests ( line, exception_string, stack_trace, error)
|
99
|
+
VALUES (:line, :exception_string, :stack_trace, :error)"),
|
100
|
+
|
101
|
+
:completed => @database.prepare("
|
102
|
+
INSERT INTO completed_requests ( line, url, status, duration, rendering_time, database_time)
|
103
|
+
VALUES (:line, :url, :status, :duration, :rendering, :db)")
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Close all prepared statments
|
108
|
+
def close_prepared_statements!
|
109
|
+
@insert_statements.each { |key, stmt| stmt.close }
|
110
|
+
end
|
111
|
+
|
112
|
+
# Create the needed database tables if they don't exist.
|
113
|
+
def create_tables_if_needed!
|
114
|
+
|
115
|
+
@database.execute("
|
116
|
+
CREATE TABLE IF NOT EXISTS started_requests (
|
117
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
118
|
+
line INTEGER NOT NULL,
|
119
|
+
timestamp DATETIME NOT NULL,
|
120
|
+
controller VARCHAR(255) NOT NULL,
|
121
|
+
action VARCHAR(255) NOT NULL,
|
122
|
+
method VARCHAR(6) NOT NULL,
|
123
|
+
ip VARCHAR(6) NOT NULL
|
124
|
+
)
|
125
|
+
");
|
126
|
+
|
127
|
+
@database.execute("
|
128
|
+
CREATE TABLE IF NOT EXISTS failed_requests (
|
129
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
130
|
+
line INTEGER NOT NULL,
|
131
|
+
started_request_id INTEGER,
|
132
|
+
error VARCHAR(255),
|
133
|
+
exception_string VARCHAR(255),
|
134
|
+
stack_trace TEXT
|
135
|
+
)
|
136
|
+
");
|
137
|
+
|
138
|
+
@database.execute("
|
139
|
+
CREATE TABLE IF NOT EXISTS completed_requests (
|
140
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
141
|
+
line INTEGER NOT NULL,
|
142
|
+
started_request_id INTEGER,
|
143
|
+
url VARCHAR(255) NOT NULL,
|
144
|
+
hashed_url VARCHAR(255),
|
145
|
+
status INTEGER NOT NULL,
|
146
|
+
duration FLOAT,
|
147
|
+
rendering_time FLOAT,
|
148
|
+
database_time FLOAT
|
149
|
+
)
|
150
|
+
");
|
151
|
+
|
152
|
+
@database.execute("CREATE TABLE IF NOT EXISTS parse_warnings (
|
153
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
154
|
+
line INTEGER NOT NULL,
|
155
|
+
warning VARCHAR(255) NOT NULL
|
156
|
+
)
|
157
|
+
");
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module RailsAnalyzer
|
2
|
+
|
3
|
+
# Functions to summarize an array of requets.
|
4
|
+
# Can calculate request counts, duratations, mean times etc. of all the requests given.
|
5
|
+
class Summarizer
|
6
|
+
|
7
|
+
attr_reader :actions
|
8
|
+
attr_reader :errors
|
9
|
+
attr_reader :request_count
|
10
|
+
attr_reader :request_time_graph
|
11
|
+
attr_reader :first_request_at
|
12
|
+
attr_reader :last_request_at
|
13
|
+
|
14
|
+
attr_accessor :blocker_duration
|
15
|
+
DEFAULT_BLOCKER_DURATION = 1.0
|
16
|
+
|
17
|
+
# Initializer. Sets global variables
|
18
|
+
# Options
|
19
|
+
# * <tt>:calculate_database</tt> Calculate the database times if they are not explicitly logged.
|
20
|
+
def initialize(options = {})
|
21
|
+
@actions = {}
|
22
|
+
@blockers = {}
|
23
|
+
@errors = {}
|
24
|
+
@request_count = 0
|
25
|
+
@blocker_duration = DEFAULT_BLOCKER_DURATION
|
26
|
+
@calculate_database = options[:calculate_database]
|
27
|
+
@request_time_graph = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Check if any of the request parsed had a timestamp.
|
31
|
+
def has_timestamps?
|
32
|
+
@first_request_at
|
33
|
+
end
|
34
|
+
|
35
|
+
# Parse a request string into a hash containing all keys found in the string.
|
36
|
+
# Yields the hash found to the block operator.
|
37
|
+
# <tt>request</tt> The request string to parse.
|
38
|
+
# <tt>&block</tt> Block operator
|
39
|
+
def group(request, &block)
|
40
|
+
request[:duration] ||= 0
|
41
|
+
|
42
|
+
case request[:type]
|
43
|
+
when :started
|
44
|
+
@first_request_at ||= request[:timestamp] # assume time-based order of file
|
45
|
+
@last_request_at = request[:timestamp] # assume time-based order of file
|
46
|
+
@request_time_graph[request[:timestamp][11..12].to_i] +=1
|
47
|
+
|
48
|
+
when :completed
|
49
|
+
@request_count += 1
|
50
|
+
hash = block_given? ? yield(request) : request.hash
|
51
|
+
|
52
|
+
@actions[hash] ||= {:count => 0, :total_time => 0.0, :total_db_time => 0.0, :total_rendering_time => 0.0,
|
53
|
+
:min_time => request[:duration], :max_time => request[:duration] }
|
54
|
+
|
55
|
+
@actions[hash][:count] += 1
|
56
|
+
@actions[hash][:total_time] += request[:duration]
|
57
|
+
@actions[hash][:total_db_time] += request[:db] if request[:db]
|
58
|
+
@actions[hash][:total_db_time] += request[:duration] - request[:rendering] if @calculate_database
|
59
|
+
|
60
|
+
@actions[hash][:total_rendering_time] += request[:rendering] if request[:rendering]
|
61
|
+
|
62
|
+
@actions[hash][:min_time] = [@actions[hash][:min_time], request[:duration]].min
|
63
|
+
@actions[hash][:max_time] = [@actions[hash][:min_time], request[:duration]].max
|
64
|
+
@actions[hash][:mean_time] = @actions[hash][:total_time] / @actions[hash][:count].to_f
|
65
|
+
|
66
|
+
@actions[hash][:mean_db_time] = @actions[hash][:total_db_time] / @actions[hash][:count].to_f
|
67
|
+
@actions[hash][:mean_rendering_time] = @actions[hash][:total_rendering_time] / @actions[hash][:count].to_f
|
68
|
+
|
69
|
+
if request[:duration] > @blocker_duration
|
70
|
+
@blockers[hash] ||= { :count => 0, :total_time => 0.0 }
|
71
|
+
@blockers[hash][:count] += 1
|
72
|
+
@blockers[hash][:total_time] += request[:duration]
|
73
|
+
end
|
74
|
+
|
75
|
+
when :failed
|
76
|
+
hash = request[:error]
|
77
|
+
@errors[hash] ||= {:count => 0, :exception_strings => {}}
|
78
|
+
@errors[hash][:count] +=1
|
79
|
+
|
80
|
+
@errors[hash][:exception_strings][request[:exception_string]] ||= 0
|
81
|
+
@errors[hash][:exception_strings][request[:exception_string]] += 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return a list of requests sorted on a specific action field
|
86
|
+
# <tt>field</tt> The action field to sort by.
|
87
|
+
# <tt>min_count</tt> Values which fall below this amount are not returned (default nil).
|
88
|
+
def sort_actions_by(field, min_count = nil)
|
89
|
+
actions = min_count.nil? ? @actions.to_a : @actions.delete_if { |k, v| v[:count] < min_count}.to_a
|
90
|
+
actions.sort { |a, b| (a[1][field.to_sym] <=> b[1][field.to_sym]) }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns a list of request blockers sorted by a specific field
|
94
|
+
# <tt>field</tt> The action field to sort by.
|
95
|
+
# <tt>min_count</tt> Values which fall below this amount are not returned (default @blocker_duration).
|
96
|
+
def sort_blockers_by(field, min_count = @blocker_duration)
|
97
|
+
blockers = min_count.nil? ? @blockers.to_a : @blockers.delete_if { |k, v| v[:count] < min_count}.to_a
|
98
|
+
blockers.sort { |a, b| a[1][field.to_sym] <=> b[1][field.to_sym] }
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns a list of request blockers sorted by a specific field
|
102
|
+
# <tt>field</tt> The action field to sort by.
|
103
|
+
# <tt>min_count</tt> Values which fall below this amount are not returned (default @blocker_duration).
|
104
|
+
def sort_errors_by(field, min_count = nil)
|
105
|
+
errors = min_count.nil? ? @errors.to_a : @errors.delete_if { |k, v| v[:count] < min_count}.to_a
|
106
|
+
errors.sort { |a, b| a[1][field.to_sym] <=> b[1][field.to_sym] }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Calculate the duration of a request
|
110
|
+
# Returns a DateTime object if possible, 0 otherwise.
|
111
|
+
def duration
|
112
|
+
(@last_request_at && @first_request_at) ? (DateTime.parse(@last_request_at) - DateTime.parse(@first_request_at)).round : 0
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if the request time graph usable data.
|
116
|
+
def request_time_graph?
|
117
|
+
@request_time_graph.uniq != [0] && duration > 0
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
=begin
|
2
|
+
index:Ej
|
3
|
+
|
4
|
+
= Ruby/ProgressBar: A Text Progress Bar Library for Ruby
|
5
|
+
|
6
|
+
Last Modified: 2005-05-22 00:28:04
|
7
|
+
|
8
|
+
--
|
9
|
+
|
10
|
+
Ruby/ProgressBar is a text progress bar library for Ruby.
|
11
|
+
It can indicate progress with percentage, a progress bar,
|
12
|
+
and estimated remaining time.
|
13
|
+
|
14
|
+
The latest version of Ruby/ProgressBar is available at
|
15
|
+
((<URL:http://namazu.org/~satoru/ruby-progressbar/>))
|
16
|
+
.
|
17
|
+
|
18
|
+
== Examples
|
19
|
+
|
20
|
+
% irb --simple-prompt -r progressbar
|
21
|
+
>> pbar = ProgressBar.new("test", 100)
|
22
|
+
=> (ProgressBar: 0/100)
|
23
|
+
>> 100.times {sleep(0.1); pbar.inc}; pbar.finish
|
24
|
+
test: 100% |oooooooooooooooooooooooooooooooooooooooo| Time: 00:00:10
|
25
|
+
=> nil
|
26
|
+
|
27
|
+
>> pbar = ProgressBar.new("test", 100)
|
28
|
+
=> (ProgressBar: 0/100)
|
29
|
+
>> (1..100).each{|x| sleep(0.1); pbar.set(x)}; pbar.finish
|
30
|
+
test: 67% |oooooooooooooooooooooooooo | ETA: 00:00:03
|
31
|
+
|
32
|
+
== API
|
33
|
+
|
34
|
+
--- ProgressBar#new (title, total, out = STDERR)
|
35
|
+
Display the initial progress bar and return a
|
36
|
+
ProgressBar object. ((|title|)) specifies the title,
|
37
|
+
and ((|total|)) specifies the total cost of processing.
|
38
|
+
Optional parameter ((|out|)) specifies the output IO.
|
39
|
+
|
40
|
+
The display of the progress bar is updated when one or
|
41
|
+
more percent is proceeded or one or more seconds are
|
42
|
+
elapsed from the previous display.
|
43
|
+
|
44
|
+
--- ProgressBar#inc (step = 1)
|
45
|
+
Increase the internal counter by ((|step|)) and update
|
46
|
+
the display of the progress bar. Display the estimated
|
47
|
+
remaining time on the right side of the bar. The counter
|
48
|
+
does not go beyond the ((|total|)).
|
49
|
+
|
50
|
+
--- ProgressBar#set (count)
|
51
|
+
Set the internal counter to ((|count|)) and update the
|
52
|
+
display of the progress bar. Display the estimated
|
53
|
+
remaining time on the right side of the bar. Raise if
|
54
|
+
((|count|)) is a negative number or a number more than
|
55
|
+
the ((|total|)).
|
56
|
+
|
57
|
+
--- ProgressBar#finish
|
58
|
+
Stop the progress bar and update the display of progress
|
59
|
+
bar. Display the elapsed time on the right side of the bar.
|
60
|
+
The progress bar always stops at 100 % by the method.
|
61
|
+
|
62
|
+
--- ProgressBar#halt
|
63
|
+
Stop the progress bar and update the display of progress
|
64
|
+
bar. Display the elapsed time on the right side of the bar.
|
65
|
+
The progress bar stops at the current percentage by the method.
|
66
|
+
|
67
|
+
--- ProgressBar#format=
|
68
|
+
Set the format for displaying a progress bar.
|
69
|
+
Default: "%-14s %3d%% %s %s".
|
70
|
+
|
71
|
+
--- ProgressBar#format_arguments=
|
72
|
+
Set the methods for displaying a progress bar.
|
73
|
+
Default: [:title, :percentage, :bar, :stat].
|
74
|
+
|
75
|
+
--- ProgressBar#file_transfer_mode
|
76
|
+
Use :stat_for_file_transfer instead of :stat to display
|
77
|
+
transfered bytes and transfer rate.
|
78
|
+
|
79
|
+
|
80
|
+
ReverseProgressBar class is also available. The
|
81
|
+
functionality is identical to ProgressBar but the direction
|
82
|
+
of the progress bar is just opposite.
|
83
|
+
|
84
|
+
== Limitations
|
85
|
+
|
86
|
+
Since the progress is calculated by the proportion to the
|
87
|
+
total cost of processing, Ruby/ProgressBar cannot be used if
|
88
|
+
the total cost of processing is unknown in advance.
|
89
|
+
Moreover, the estimation of remaining time cannot be
|
90
|
+
accurately performed if the progress does not flow uniformly.
|
91
|
+
|
92
|
+
== Download
|
93
|
+
|
94
|
+
Ruby/ProgressBar is a free software with ABSOLUTELY NO WARRANTY
|
95
|
+
under the terms of Ruby's license.
|
96
|
+
|
97
|
+
* ((<URL:http://namazu.org/~satoru/ruby-progressbar/ruby-progressbar-0.9.tar.gz>))
|
98
|
+
* ((<URL:http://cvs.namazu.org/ruby-progressbar/>))
|
99
|
+
|
100
|
+
--
|
101
|
+
|
102
|
+
- ((<Satoru Takabayashi|URL:http://namazu.org/~satoru/>)) -
|
103
|
+
=end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
=begin
|
2
|
+
index:eJ
|
3
|
+
|
4
|
+
= Ruby/ProgressBar: �ץ����쥹�С���ƥ����Ȥ�ɽ������ Ruby�ѤΥ饤�֥��
|
5
|
+
|
6
|
+
�ǽ�������: 2005-05-22 00:28:53
|
7
|
+
|
8
|
+
|
9
|
+
--
|
10
|
+
|
11
|
+
Ruby/ProgressBar �ϥץ����쥹�С���ƥ����Ȥ�ɽ������ Ruby��
|
12
|
+
�Υ饤�֥��Ǥ��������ο�Ľ������ѡ�����ȡ��ץ����쥹�С���
|
13
|
+
����ӿ���Ĥ���֤Ȥ���ɽ�����ޤ���
|
14
|
+
|
15
|
+
�ǿ��Ǥ�
|
16
|
+
((<URL:http://namazu.org/~satoru/ruby-progressbar/>))
|
17
|
+
���������ǽ�Ǥ�
|
18
|
+
|
19
|
+
== ������
|
20
|
+
|
21
|
+
% irb --simple-prompt -r progressbar
|
22
|
+
>> pbar = ProgressBar.new("test", 100)
|
23
|
+
=> (ProgressBar: 0/100)
|
24
|
+
>> 100.times {sleep(0.1); pbar.inc}; pbar.finish
|
25
|
+
test: 100% |oooooooooooooooooooooooooooooooooooooooo| Time: 00:00:10
|
26
|
+
=> nil
|
27
|
+
|
28
|
+
>> pbar = ProgressBar.new("test", 100)
|
29
|
+
=> (ProgressBar: 0/100)
|
30
|
+
>> (1..100).each{|x| sleep(0.1); pbar.set(x)}; pbar.finish
|
31
|
+
test: 67% |oooooooooooooooooooooooooo | ETA: 00:00:03
|
32
|
+
|
33
|
+
== API
|
34
|
+
|
35
|
+
--- ProgressBar#new (title, total, out = STDERR)
|
36
|
+
�ץ����쥹�С��ν�����֤�ɽ������������ ProgressBar����
|
37
|
+
�������Ȥ��֤���((|title|)) �Ǹ��Ф���((|total|)) �ǽ�
|
38
|
+
�������פ�((|out|)) �ǽ������ IO �����ꤹ�롣
|
39
|
+
|
40
|
+
�ץ����쥹�С���ɽ���ϡ������ɽ�������Ľ�� 1%�ʾ夢��
|
41
|
+
���Ȥ������뤤�� 1�ðʾ�вᤷ�����˹�������ޤ���
|
42
|
+
|
43
|
+
--- ProgressBar#inc (step = 1)
|
44
|
+
�����Υ����� ((|step|)) �������ʤ�ơ��ץ����쥹�С�
|
45
|
+
��ɽ�������롣�С��α�¦�ˤϿ���Ĥ���֤�ɽ�����롣
|
46
|
+
������ ((|total|)) ��ۤ��ƿʤळ�ȤϤʤ���
|
47
|
+
|
48
|
+
--- ProgressBar#set (count)
|
49
|
+
�������ͤ� ((|count|)) �����ꤷ���ץ����쥹�С���
|
50
|
+
ɽ�������롣�С��α�¦�ˤϿ���Ĥ���֤�ɽ�����롣
|
51
|
+
((|count|)) �˥ޥ��ʥ����ͤ��뤤�� ((|total|)) ����礭
|
52
|
+
���ͤ��Ϥ����㳰��ȯ�����롣
|
53
|
+
|
54
|
+
--- ProgressBar#finish
|
55
|
+
�ץ����쥹�С�����ߤ����ץ����쥹�С���ɽ�������롣
|
56
|
+
�ץ����쥹�С��α�¦�ˤϷв���֤�ɽ�����롣
|
57
|
+
���ΤȤ����ץ����쥹�С��� 100% �ǽ�λ���롣
|
58
|
+
|
59
|
+
--- ProgressBar#halt
|
60
|
+
�ץ����쥹�С�����ߤ����ץ����쥹�С���ɽ�������롣
|
61
|
+
�ץ����쥹�С��α�¦�ˤϷв���֤�ɽ�����롣
|
62
|
+
���ΤȤ����ץ����쥹�С��Ϥ��λ����Υѡ�����ơ����ǽ�λ���롣
|
63
|
+
|
64
|
+
--- ProgressBar#format=
|
65
|
+
�ץ����쥹�С�ɽ���Υե����ޥåȤ����ꤹ�롣
|
66
|
+
̤�ѹ����� "%-14s %3d%% %s %s"
|
67
|
+
|
68
|
+
--- ProgressBar#format_arguments=
|
69
|
+
�ץ����쥹�С�ɽ���˻Ȥ��ؿ������ꤹ�롣
|
70
|
+
̤�ѹ����� [:title, :percentage, :bar, :stat]
|
71
|
+
�ե�����ž�����ˤ� :stat ���Ѥ��� :stat_for_file_transfer
|
72
|
+
��Ȥ���ž���Х��ȿ���ž��®�٤�ɽ���Ǥ��롣
|
73
|
+
|
74
|
+
--- ProgressBar#file_transfer_mode
|
75
|
+
�ץ����쥹�С�ɽ���� :stat ���Ѥ��� :stat_for_file_transfer
|
76
|
+
��Ȥ���ž���Х��ȿ���ž��®�٤�ɽ�����롣
|
77
|
+
|
78
|
+
|
79
|
+
ReverseProgressBar �Ȥ������饹������ޤ�����ǽ��
|
80
|
+
ProgressBar �Ȥޤä���Ʊ���Ǥ������ץ����쥹�С��οʹ�������
|
81
|
+
�դˤʤäƤ��ޤ���
|
82
|
+
|
83
|
+
== ���»���
|
84
|
+
|
85
|
+
��Ľ��������������פ��Ф�����Ȥ��Ʒ����뤿�ᡢ��������
|
86
|
+
�פ������ˤ狼��ʤ������ǤϻȤ��ޤ��ޤ�����Ľ��ή�줬��
|
87
|
+
��Ǥʤ��Ȥ��ˤϻĤ���֤ο�����������Ԥ��ޤ���
|
88
|
+
|
89
|
+
== �����������
|
90
|
+
|
91
|
+
Ruby �Υ饤���˽��ä��ե���եȥ������Ȥ��Ƹ������ޤ���
|
92
|
+
������̵�ݾڤǤ���
|
93
|
+
|
94
|
+
* ((<URL:http://namazu.org/~satoru/ruby-progressbar/ruby-progressbar-0.9.tar.gz>))
|
95
|
+
* ((<URL:http://cvs.namazu.org/ruby-progressbar/>))
|
96
|
+
|
97
|
+
--
|
98
|
+
|
99
|
+
- ((<Satoru Takabayashi|URL:http://namazu.org/~satoru/>)) -
|
100
|
+
=end
|