tailstrom 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6fec2ff65f0328d66e043a18c115cd3015b9caf
4
- data.tar.gz: 647ff07f72e2450bc69405fb2705a3996c040e78
3
+ metadata.gz: e2084969ae138b43205364ee1c78bbe4af7e3288
4
+ data.tar.gz: b9bf1f575d1c915c2ae185d38d40acabb27341d6
5
5
  SHA512:
6
- metadata.gz: c557df7bb847da8d28c3f0f95193719bd65a0c1222e4f18fc2d0ea724c378ce6b8de4d1ece305ec969090b9cfe8dd704d79466d8e0ccb4b25ad544467a5dd135
7
- data.tar.gz: 8f0edf474fee9be1783f114287826bd5ecc6c641825bdc372b9a292c9ce3e68e81f3dfc630e43d397418986b89ef50512f2f47db39df2da2572835afc34c034d
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 = "tail -f access.log | #{$0} <OPTIONS>"
11
- opt.on('-f [num]', Integer, 'value field') {|v| options[:field] = v }
12
- opt.on('-k [num]', Integer, 'key field') {|v| options[:key] = v }
13
- opt.on('-d [delimiter]', String) {|v| options[:delimiter] = v }
14
- opt.on('-i [interval]', Integer, 'interval for stat mode') {|v| options[:interval] = v }
15
- opt.on('-e [filter]', String) {|v| options[:filter] = v }
16
- opt.on('--map [file]', String, 'mapping file') {|v| options[:map] = File.read(v) }
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
- }.parse!
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
@@ -7,4 +7,4 @@ key = case col[3]
7
7
  when %r(^/products/)
8
8
  'products'
9
9
  end
10
- #filter = 'value > 0'
10
+ #in_filter = 'value > 0'
@@ -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
- @table = Table.new SCHEMA
21
- @options = options
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
- Thread.start do
26
- reader = TailReader.new @infile, @options
27
- reader.each_line do |line|
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
- @i = 0
35
- loop do
33
+ i = 0
34
+ begin
36
35
  sleep @options[:interval]
37
36
 
38
- if @i % height == 0
37
+ if i % height == 0
39
38
  @table.print_header
40
39
  end
41
40
 
42
- @counters.to_a.sort_by {|key, c|
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
- @i = @i + 1
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
@@ -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
@@ -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
- num_str = col ? num_with_delim(col) : '-'
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", num_str
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
- filter = @options[:filter]
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 filter
29
- return nil unless binding.eval(filter)
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 }
@@ -1,3 +1,3 @@
1
1
  module Tailstrom
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
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"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tailstrom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Issei Naruta