tailstrom 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/bin/tailstrom +39 -10
- data/example/map1.rb +1 -1
- data/lib/tailstrom/command/stat.rb +63 -30
- data/lib/tailstrom/counter.rb +10 -4
- data/lib/tailstrom/table.rb +13 -2
- data/lib/tailstrom/tail_reader.rb +17 -4
- data/lib/tailstrom/version.rb +1 -1
- data/tailstrom.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2084969ae138b43205364ee1c78bbe4af7e3288
|
4
|
+
data.tar.gz: b9bf1f575d1c915c2ae185d38d40acabb27341d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b960f9634555b00cedf6cb08d2e4449b1f13dc5e40b956b2734bd59547d0207c427e63111ee47ef7b90d239c252703e789748e699f6b93e363431dd1939096b
|
7
|
+
data.tar.gz: bc421512afa39984806754b237e6096df8fb7c4ae31a6f78504ef3f82a055b2bceb055956d5af312fbbd23ca7afa503323fd0e2c907705f5327bcd3ac2b55a01
|
data/bin/tailstrom
CHANGED
@@ -1,24 +1,53 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
$: << File.expand_path('../../lib', __FILE__)
|
2
3
|
require 'optparse'
|
3
4
|
|
5
|
+
def file_or_string(value)
|
6
|
+
File.exist?(value) ? File.read(value) : value
|
7
|
+
end
|
8
|
+
|
4
9
|
options = {
|
5
10
|
:delimiter => "\t",
|
6
11
|
:interval => 1,
|
7
|
-
:mode => :stat
|
12
|
+
:mode => :stat,
|
13
|
+
:order => :desc
|
8
14
|
}
|
9
15
|
OptionParser.new(ARGV) {|opt|
|
10
|
-
opt.banner =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
opt.on('-
|
15
|
-
opt.on('-
|
16
|
-
opt.on('
|
16
|
+
opt.banner = <<-END
|
17
|
+
tail -f access.log | #{$0} [OPTIONS]
|
18
|
+
#{$0} [OPTIONS] [file]
|
19
|
+
END
|
20
|
+
opt.on('-f num', Integer, 'value field') {|v| options[:field] = v }
|
21
|
+
opt.on('-k num', Integer, 'key field') {|v| options[:key] = v }
|
22
|
+
opt.on('-d delimiter', String, 'delimiter') {|v| options[:delimiter] = v }
|
23
|
+
opt.on('-i interval', Integer, 'interval for stat mode') {|v| options[:interval] = v }
|
24
|
+
opt.on('-e file_or_string', '--in-filter file_or_string', String, 'input filtering') do |v|
|
25
|
+
options[:in_filter] = file_or_string v
|
26
|
+
end
|
27
|
+
opt.on('--map file_or_string', String, 'input mapping') do |v|
|
28
|
+
options[:map] = file_or_string v
|
29
|
+
end
|
30
|
+
opt.on('--out-filter file_or_string', String, 'output filtering') do |v|
|
31
|
+
options[:out_filter] = file_or_string v
|
32
|
+
end
|
33
|
+
opt.on('--sort file_or_string', String, 'output sorting') do |v|
|
34
|
+
options[:sort] = file_or_string v
|
35
|
+
end
|
36
|
+
opt.on('--order desc|asc', String, 'sorting order (default=desc)') do |v|
|
37
|
+
options[:order] = v.to_s.downcase == 'asc' ? :asc : :desc
|
38
|
+
end
|
17
39
|
opt.on('--stat', 'statistics mode (default)') { options[:mode] = :stat }
|
18
40
|
opt.on('--print', 'print line mode') { options[:mode] = :print }
|
19
|
-
|
41
|
+
opt.on('--version', 'show version') do
|
42
|
+
require 'tailstrom/version'
|
43
|
+
puts Tailstrom::VERSION
|
44
|
+
exit 0
|
45
|
+
end
|
46
|
+
}.order!
|
47
|
+
if infile = ARGV.shift
|
48
|
+
options[:static_infile] = open(infile, 'r')
|
49
|
+
end
|
20
50
|
|
21
|
-
$: << File.expand_path('../../lib', __FILE__)
|
22
51
|
require "tailstrom/command/#{options[:mode]}"
|
23
52
|
cls = Module.const_get "Tailstrom::Command::#{options[:mode].capitalize}"
|
24
53
|
cmd = cls.new options
|
data/example/map1.rb
CHANGED
@@ -5,58 +5,91 @@ require 'tailstrom/tail_reader'
|
|
5
5
|
module Tailstrom
|
6
6
|
module Command
|
7
7
|
class Stat
|
8
|
-
SCHEMA = [
|
9
|
-
{ :name => 'time', :width => 8 },
|
10
|
-
{ :name => 'count', :width => 7 },
|
11
|
-
{ :name => 'min', :width => 10 },
|
12
|
-
{ :name => 'max', :width => 10 },
|
13
|
-
{ :name => 'avg', :width => 10 },
|
14
|
-
{ :name => 'key', :width => 10, :align => :left }
|
15
|
-
]
|
16
|
-
|
17
8
|
def initialize(options)
|
18
|
-
@infile = $stdin
|
9
|
+
@infile = options[:static_infile] || $stdin
|
19
10
|
@counters = CounterCollection.new
|
20
|
-
@
|
21
|
-
@
|
11
|
+
@options = { :async => !options[:static_infile] }.merge options
|
12
|
+
@table = Table.new schema
|
13
|
+
end
|
14
|
+
|
15
|
+
def schema
|
16
|
+
[
|
17
|
+
({ :name => 'time', :width => 8 } if @options[:async]),
|
18
|
+
{ :name => 'count', :width => 7 },
|
19
|
+
{ :name => 'min', :width => 10 },
|
20
|
+
{ :name => 'max', :width => 10 },
|
21
|
+
{ :name => 'avg', :width => 10 },
|
22
|
+
{ :name => 'key', :width => 10, :align => :left }
|
23
|
+
].compact
|
22
24
|
end
|
23
25
|
|
24
26
|
def run
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@counters[line[:key]] << line[:value]
|
29
|
-
end
|
30
|
-
puts 'EOF'
|
27
|
+
reader = TailReader.new @infile, @options
|
28
|
+
reader.each_line do |line|
|
29
|
+
@counters[line[:key]] << line[:value]
|
31
30
|
end
|
32
31
|
|
33
32
|
height = `put lines`.to_i - 4 rescue 10
|
34
|
-
|
35
|
-
|
33
|
+
i = 0
|
34
|
+
begin
|
36
35
|
sleep @options[:interval]
|
37
36
|
|
38
|
-
if
|
37
|
+
if i % height == 0
|
39
38
|
@table.print_header
|
40
39
|
end
|
41
40
|
|
42
|
-
|
43
|
-
c.sum
|
44
|
-
}.reverse_each do |key, c|
|
45
|
-
key = (key == :nil ? nil : key)
|
46
|
-
time = Time.now.strftime("%H:%M:%S")
|
47
|
-
@table.print_row time, c.count, c.min, c.max, c.avg, key
|
48
|
-
end
|
41
|
+
print_counters
|
49
42
|
|
50
43
|
if @counters.size > 1
|
51
44
|
@table.puts
|
52
45
|
end
|
53
46
|
|
54
47
|
@counters.clear
|
55
|
-
|
56
|
-
end
|
48
|
+
i = i + 1
|
49
|
+
end while !reader.eof?
|
57
50
|
rescue Interrupt
|
58
51
|
exit 0
|
59
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def print_counters
|
56
|
+
sorted_counters.each do |key, c|
|
57
|
+
key = (key == :nil ? nil : key)
|
58
|
+
next unless out_filter(key, c)
|
59
|
+
if @options[:async]
|
60
|
+
time = Time.now.strftime("%H:%M:%S")
|
61
|
+
@table.print_row time, c.count, c.min, c.max, c.avg, key
|
62
|
+
else
|
63
|
+
@table.print_row c.count, c.min, c.max, c.avg, key
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def sorted_counters
|
69
|
+
counters = @counters.to_a
|
70
|
+
if sort = @options[:sort]
|
71
|
+
counters.sort_by! do |key, c|
|
72
|
+
sum, avg, min, max, count =
|
73
|
+
c.sum, c.avg, c.min, c.max, c.count
|
74
|
+
binding.eval sort
|
75
|
+
end
|
76
|
+
else
|
77
|
+
counters.sort_by! do |key, c|
|
78
|
+
c.sum
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@options[:order] == :asc ? counters : counters.reverse
|
82
|
+
end
|
83
|
+
|
84
|
+
def out_filter(key, counter)
|
85
|
+
if filter = @options[:out_filter]
|
86
|
+
sum, avg, min, max, count =
|
87
|
+
counter.sum, counter.avg, counter.min, counter.max, counter.count
|
88
|
+
binding.eval filter
|
89
|
+
else
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
60
93
|
end
|
61
94
|
end
|
62
95
|
end
|
data/lib/tailstrom/counter.rb
CHANGED
@@ -5,11 +5,17 @@ module Tailstrom
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def <<(value)
|
8
|
+
purge_cache
|
8
9
|
@values << value
|
9
10
|
end
|
10
11
|
|
11
12
|
def clear
|
12
13
|
@values = []
|
14
|
+
purge_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
def purge_cache
|
18
|
+
@cache = {}
|
13
19
|
end
|
14
20
|
|
15
21
|
def avg
|
@@ -18,15 +24,15 @@ module Tailstrom
|
|
18
24
|
end
|
19
25
|
|
20
26
|
def sum
|
21
|
-
@values.inject(0, :+)
|
27
|
+
@cache[:sum] ||= @values.inject(0, :+)
|
22
28
|
end
|
23
29
|
|
24
30
|
def min
|
25
|
-
@values.min
|
31
|
+
@cache[:min] ||= @values.min
|
26
32
|
end
|
27
33
|
|
28
34
|
def max
|
29
|
-
@values.max
|
35
|
+
@cache[:max] ||= @values.max
|
30
36
|
end
|
31
37
|
|
32
38
|
def med
|
@@ -34,7 +40,7 @@ module Tailstrom
|
|
34
40
|
end
|
35
41
|
|
36
42
|
def count
|
37
|
-
@values.count
|
43
|
+
@cache[:count] ||= @values.count
|
38
44
|
end
|
39
45
|
end
|
40
46
|
end
|
data/lib/tailstrom/table.rb
CHANGED
@@ -8,10 +8,10 @@ module Tailstrom
|
|
8
8
|
def print_row(*cols)
|
9
9
|
cols.each_with_index do |col, i|
|
10
10
|
col_schema = @schema[i]
|
11
|
-
|
11
|
+
str = format_string col
|
12
12
|
print ' ' if i > 0
|
13
13
|
align = col_schema[:align].to_s == 'left' ? '-' : nil
|
14
|
-
printf "%#{align}#{col_schema[:width]}s",
|
14
|
+
printf "%#{align}#{col_schema[:width]}s", str
|
15
15
|
end
|
16
16
|
self.puts
|
17
17
|
end
|
@@ -35,6 +35,17 @@ module Tailstrom
|
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
|
+
def format_string(value)
|
39
|
+
case value
|
40
|
+
when Numeric
|
41
|
+
num_with_delim value
|
42
|
+
when nil
|
43
|
+
'-'
|
44
|
+
else
|
45
|
+
value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
38
49
|
def num_with_delim(num)
|
39
50
|
head, tail = num.to_s.split('.')
|
40
51
|
head.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
|
@@ -5,28 +5,41 @@ module Tailstrom
|
|
5
5
|
@options = options
|
6
6
|
end
|
7
7
|
|
8
|
-
def each_line
|
8
|
+
def each_line(&block)
|
9
|
+
if @options[:async]
|
10
|
+
Thread.new { _each_line &block }
|
11
|
+
else
|
12
|
+
_each_line &block
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def _each_line
|
9
17
|
@infile.each_line do |line|
|
10
18
|
line.chomp!
|
11
19
|
result = parse_line(line)
|
12
20
|
yield result if result
|
13
21
|
end
|
14
22
|
end
|
23
|
+
private :_each_line
|
24
|
+
|
25
|
+
def eof?
|
26
|
+
@infile.eof?
|
27
|
+
end
|
15
28
|
|
16
29
|
def parse_line(line)
|
17
30
|
col = line.split @options[:delimiter]
|
18
31
|
value = @options[:field] ? col[@options[:field]] : line
|
19
32
|
value = format_value value
|
20
33
|
key = @options[:key] ? col[@options[:key]] : :nil
|
21
|
-
|
34
|
+
in_filter = @options[:in_filter]
|
22
35
|
|
23
36
|
if @options[:map]
|
24
37
|
binding.eval(@options[:map])
|
25
38
|
value = format_value value
|
26
39
|
end
|
27
40
|
|
28
|
-
if
|
29
|
-
return nil unless binding.eval(
|
41
|
+
if in_filter
|
42
|
+
return nil unless binding.eval(in_filter)
|
30
43
|
end
|
31
44
|
|
32
45
|
{ :line => line, :columns => col, :key => key, :value => value }
|
data/lib/tailstrom/version.rb
CHANGED
data/tailstrom.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Tailstrom::VERSION
|
9
9
|
spec.authors = ["Issei Naruta"]
|
10
10
|
spec.email = ["naruta@cookpad.com"]
|
11
|
-
spec.description = %q{tailstrom is an utility for "tail -f"}
|
11
|
+
spec.description = %q{tailstrom is an utility for "tail -f"}
|
12
12
|
spec.summary = %q{A utility for "tail -f"}
|
13
13
|
spec.homepage = ""
|
14
14
|
spec.license = "MIT"
|