fluent-plugin-dstat 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,9 +7,8 @@ source "http://rubygems.org"
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
  group :development do
9
9
  gem "shoulda", ">= 0"
10
- gem "bundler", "~> 1.0.0"
10
+ gem "bundler", "~> 1.0"
11
11
  gem "jeweler", "~> 1.6.4"
12
- gem "rcov", ">= 0"
13
12
  end
14
13
 
15
14
  gem "fluentd", "~> 0.10.7"
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ Dstat plugin for Fluent
2
+
3
+ Description goes here.
4
+
5
+ ## What's Dstat?
6
+
7
+ Dstat is a versatile replacement for vmstat, iostat, netstat and ifstat.
8
+ If you need more detail, see here[http://dag.wieers.com/home-made/dstat]
9
+ This plugin use Dstat, so you need to install Dstat before using this plugin.
10
+
11
+ ## Configuration
12
+
13
+ ```
14
+ <source>
15
+ type dstat
16
+ tag dstat
17
+ option -c
18
+ delay 3
19
+ </source>
20
+ ```
21
+
22
+ * option:option for dstat command(default: -fcdnm)
23
+
24
+ ## Output Format
25
+
26
+ When you use option -a, you get structured output data like below.
27
+
28
+ {
29
+ "hostname":"tsukuba000",
30
+ dstat":{"total cpu usage":"usr":"0.0","sys":"0.0","idl":"100.0","wai":"0.0","hiq":"0.0","siq":"0.0"},
31
+ "dsk/total":{"read":"0.0","writ":"0.0"},"net/total":{"recv":"148.0","send":"164.0"},
32
+ "paging":{"in":"0.0","out":"0.0"},
33
+ "system":{"int":"16.333","csw":"29.0"}}
34
+ }
35
+
36
+ ## Supported options
37
+
38
+ ```
39
+ aio, cpu, cpu24, disk, epoch, fs, int, int24, io, ipc, load, lock, mem, net, page, page24, proc, raw, socket, swap, swapold, sys, tcp, udp, unix, vm, disk-util, freespace, top-bio, top-cpu,top-io, top-mem, top-oom, utmp, top-io -fc
40
+ ```
41
+
42
+ ## Copyright
43
+
44
+ Copyright (c) 2011 Shunsuke Mikami. See LICENSE.txt for
45
+ further details.
46
+
data/Rakefile CHANGED
@@ -30,14 +30,6 @@ Rake::TestTask.new(:test) do |test|
30
30
  test.verbose = true
31
31
  end
32
32
 
33
- require 'rcov/rcovtask'
34
- Rcov::RcovTask.new do |test|
35
- test.libs << 'test'
36
- test.pattern = 'test/**/test_*.rb'
37
- test.verbose = true
38
- test.rcov_opts << '--exclude "gems/*"'
39
- end
40
-
41
33
  task :default => :test
42
34
 
43
35
  require 'rdoc/task'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -5,22 +5,22 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "fluent-plugin-dstat"
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Shunsuke Mikami"]
12
- s.date = "2012-01-12"
12
+ s.date = "2012-07-29"
13
13
  s.email = "shun0102@gmail.com"
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE.txt",
16
- "README.rdoc"
16
+ "README.md"
17
17
  ]
18
18
  s.files = [
19
19
  ".document",
20
20
  "AUTHORS",
21
21
  "Gemfile",
22
22
  "LICENSE.txt",
23
- "README.rdoc",
23
+ "README.md",
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "fluent-plugin-dstat.gemspec",
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
30
30
  ]
31
31
  s.homepage = "http://github.com/shun0102/fluent-plugin-dstat"
32
32
  s.require_paths = ["lib"]
33
- s.rubygems_version = "1.8.10"
33
+ s.rubygems_version = "1.8.23"
34
34
  s.summary = "Dstat Input plugin for Fluent event collector"
35
35
 
36
36
  if s.respond_to? :specification_version then
@@ -40,24 +40,21 @@ Gem::Specification.new do |s|
40
40
  s.add_runtime_dependency(%q<fluentd>, ["~> 0.10.7"])
41
41
  s.add_runtime_dependency(%q<rdoc>, [">= 0"])
42
42
  s.add_development_dependency(%q<shoulda>, [">= 0"])
43
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
43
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
44
44
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
45
- s.add_development_dependency(%q<rcov>, [">= 0"])
46
45
  else
47
46
  s.add_dependency(%q<fluentd>, ["~> 0.10.7"])
48
47
  s.add_dependency(%q<rdoc>, [">= 0"])
49
48
  s.add_dependency(%q<shoulda>, [">= 0"])
50
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
49
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
51
50
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
52
- s.add_dependency(%q<rcov>, [">= 0"])
53
51
  end
54
52
  else
55
53
  s.add_dependency(%q<fluentd>, ["~> 0.10.7"])
56
54
  s.add_dependency(%q<rdoc>, [">= 0"])
57
55
  s.add_dependency(%q<shoulda>, [">= 0"])
58
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
56
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
59
57
  s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
60
- s.add_dependency(%q<rcov>, [">= 0"])
61
58
  end
62
59
  end
63
60
 
@@ -2,123 +2,129 @@ module Fluent
2
2
 
3
3
  class DstatInput < Input
4
4
 
5
- def split_second_key(str)
6
- result = []
7
- while (str)
8
- index = /[^ ] / =~ str
9
- if index
10
- result << str[0..index]
11
- else
12
- result << str unless str == " "
13
- return result
14
- end
15
- str = str[(index + 1)..-1]
16
- end
17
-
18
- return result
19
- end
20
-
21
5
  Plugin.register_input('dstat', self)
22
6
 
23
7
  def initialize
24
8
  super
9
+ require 'csv'
25
10
  @hostname = `hostname -s`.chomp!
26
11
  @line_number = 0
27
12
  @first_keys = []
28
13
  @second_keys = []
14
+ @data_array = []
15
+ @max_lines = 100
29
16
  end
30
17
 
31
18
  config_param :tag, :string
32
19
  config_param :option, :string, :default => "-fcdnm"
33
20
  config_param :delay, :integer, :default => 1
21
+ config_param :tmp_file, :string, :default => "/tmp/dstat.csv"
34
22
 
35
23
  def configure(conf)
36
24
  super
37
- @command = "dstat #{@option} #{@delay}"
25
+ @command = "dstat #{@option} --output #{@tmp_file} #{@delay}"
38
26
  end
39
27
 
40
28
  def start
29
+ if File.exist?(@tmp_file)
30
+ File.truncate(@tmp_file, 0)
31
+ else
32
+ `touch #{@tmp_file}`
33
+ end
41
34
  @io = IO.popen(@command, "r")
42
35
  @pid = @io.pid
36
+
37
+ @loop = Coolio::Loop.new
38
+ @dw = DstatCSVWatcher.new(@tmp_file, &method(:receive_lines))
39
+ @dw.attach(@loop)
43
40
  @thread = Thread.new(&method(:run))
44
41
  end
45
42
 
46
43
  def shutdown
47
44
  Process.kill(:TERM, @pid)
48
- if @thread.join(60) # TODO wait time
49
- return
50
- end
51
- Process.kill(:KILL, @pid)
45
+ @dw.detach
46
+ @loop.stop
52
47
  @thread.join
48
+ File.delete(@tmp_file)
53
49
  end
54
50
 
55
51
  def run
56
- @io.each_line(&method(:each_line))
57
- end
58
-
59
- private
60
- def each_line(line)
61
52
  begin
62
- line.chomp!
63
- line.gsub!(/\e\[7l/, "")
53
+ @loop.run
54
+ rescue
55
+ $log.error "unexpected error", :error=>$!.to_s
56
+ $log.error_backtrace
57
+ end
58
+ end
64
59
 
60
+ def receive_lines(lines)
61
+ lines.each do |line|
62
+ next if line == ""
65
63
  case @line_number
66
- when 0
67
- @first_keys = line.split(" ")
68
- when 1
69
- index = 0
70
- @first_keys.each do |i|
71
- @second_keys << line[index..(index + i.length - 1)]
72
- index += i.length + 1
64
+ when 0..1
65
+ when 2
66
+ line.delete!("\"")
67
+ @first_keys = CSV.parse_line(line)
68
+ pre_key = ""
69
+ @first_keys.each_with_index do |key, index|
70
+ if key.nil? || key == ""
71
+ @first_keys[index] = pre_key
72
+ end
73
+ pre_key = @first_keys[index]
73
74
  end
74
- else
75
- hash = Hash.new()
76
- values = []
77
- index = 0
78
- @first_keys.each do |i|
79
- values << line[index..(index + i.length - 1)]
80
- index += i.length + 1
75
+ when 3
76
+ line.delete!("\"")
77
+ @second_keys = line.split(',')
78
+ @first_keys.each_with_index do |key, index|
79
+ @data_array[index] = {}
80
+ @data_array[index][:first] = key
81
+ @data_array[index][:second] = @second_keys[index]
81
82
  end
82
-
83
- @first_keys.each_with_index do |i, index|
84
- value_hash = Hash.new()
85
- first = i.gsub(/^-+|-+$/, "")
86
- length = i.length
87
-
88
- if first == "most-expensive"
89
- s_key = @second_keys[index].gsub(/^\s+|\s+$/, "")
90
- value_hash[s_key] = values[index]
91
- else
92
- keys = split_second_key(@second_keys[index])
93
- second_index = 0
94
-
95
- keys.each do |i|
96
- next_index = second_index + i.length - 1
97
- value = values[index][second_index..next_index]
98
- second_index += i.length + 1
99
- value = value.gsub(/^\s+|\s+$/, "") if value
100
- value_hash[i.gsub(/^\s+|\s+$/, "")] = value
101
- end
102
- end
103
-
104
- if hash[first].nil?
105
- hash[first] = value_hash
106
- else
107
- hash[first] = hash[first].merge(value_hash)
108
- end
83
+ else
84
+ values = line.split(',')
85
+ data = Hash.new { |hash,key| hash[key] = Hash.new {} }
86
+ values.each_with_index do |v, index|
87
+ data[@first_keys[index]][@second_keys[index]] = v
109
88
  end
110
-
111
89
  record = {
112
90
  'hostname' => @hostname,
113
- 'dstat' => hash
91
+ 'dstat' => data
114
92
  }
115
93
  Engine.emit(@tag, Engine.now, record)
116
94
  end
95
+
96
+ if (@line_number % @max_lines) == (@max_lines - 1)
97
+ @dw.detach
98
+ File.truncate(@tmp_file, 0)
99
+ @dw = DstatCSVWatcher.new(@tmp_file, &method(:receive_lines))
100
+ @dw.attach(@loop)
101
+ end
102
+
117
103
  @line_number += 1
104
+ end
118
105
 
119
- rescue
120
- $log.error "exec failed to emit", :error=>$!, :line=>line
121
- $log.warn_backtrace $!.backtrace
106
+ end
107
+
108
+ class DstatCSVWatcher < Cool.io::StatWatcher
109
+ INTERVAL = 0.500
110
+ attr_accessor :previous, :cur
111
+
112
+ def initialize(path, &receive_lines)
113
+ super path, INTERVAL
114
+ @path = path
115
+ @io = File.open(path)
116
+ @pos = 0
117
+ @receive_lines = receive_lines
118
+ end
119
+
120
+ def on_change(prev, cur)
121
+ buffer = @io.read(cur.size - @pos)
122
+ @pos = cur.size
123
+ lines = []
124
+ while line = buffer.slice!(/.*?\n/m)
125
+ lines << line.chomp
126
+ end
127
+ @receive_lines.call(lines)
122
128
  end
123
129
  end
124
130
  end
@@ -9,9 +9,9 @@ class DstatInputTest < Test::Unit::TestCase
9
9
  "epoch", "fs", "int", "int24", "io", "ipc", "load", "lock",
10
10
  "mem", "net", "page", "page24", "proc", "raw", "socket",
11
11
  "swap", "swapold", "sys", "tcp", "udp", "unix", "vm",
12
- "disk-tps", "disk-util", "dstat-cpu", "dstat-ctxt", "dstat-mem", "freespace",
13
- "top-bio", "top-childwait", "top-cpu","top-io",
14
- "top-mem", "top-oom", "utmp", "top-io -fc"]
12
+ "disk-util", "freespace",
13
+ "top-bio", "top-cpu","top-io",
14
+ "top-mem", "top-oom", "top-io -fc"]
15
15
 
16
16
  CONFIG = %[
17
17
  tag dstat
@@ -31,7 +31,6 @@ class DstatInputTest < Test::Unit::TestCase
31
31
  def test_emit
32
32
 
33
33
  OPTIONS.each do |op|
34
- #emit_with_conf(CONFIG)
35
34
  conf = "tag dstat\n option --#{op}\n delay 1"
36
35
  emit_with_conf(conf)
37
36
  end
@@ -46,6 +45,7 @@ class DstatInputTest < Test::Unit::TestCase
46
45
  end
47
46
 
48
47
  length = `dstat #{d.instance.option} #{d.instance.delay} 1`.split("\n")[0].split("\s").length
48
+ puts `dstat #{d.instance.option} #{d.instance.delay} 3`
49
49
 
50
50
  emits = d.emits
51
51
  assert_equal true, emits.length > 0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-dstat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-12 00:00:00.000000000Z
12
+ date: 2012-07-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
16
- requirement: &22315940 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 0.10.7
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *22315940
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.10.7
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rdoc
27
- requirement: &22315460 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *22315460
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: shoulda
38
- requirement: &22314980 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,21 +53,31 @@ dependencies:
43
53
  version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *22314980
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: bundler
49
- requirement: &22314500 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ~>
53
68
  - !ruby/object:Gem::Version
54
- version: 1.0.0
69
+ version: '1.0'
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *22314500
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.0'
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: jeweler
60
- requirement: &22314020 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ~>
@@ -65,31 +85,25 @@ dependencies:
65
85
  version: 1.6.4
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *22314020
69
- - !ruby/object:Gem::Dependency
70
- name: rcov
71
- requirement: &22313540 !ruby/object:Gem::Requirement
88
+ version_requirements: !ruby/object:Gem::Requirement
72
89
  none: false
73
90
  requirements:
74
- - - ! '>='
91
+ - - ~>
75
92
  - !ruby/object:Gem::Version
76
- version: '0'
77
- type: :development
78
- prerelease: false
79
- version_requirements: *22313540
93
+ version: 1.6.4
80
94
  description:
81
95
  email: shun0102@gmail.com
82
96
  executables: []
83
97
  extensions: []
84
98
  extra_rdoc_files:
85
99
  - LICENSE.txt
86
- - README.rdoc
100
+ - README.md
87
101
  files:
88
102
  - .document
89
103
  - AUTHORS
90
104
  - Gemfile
91
105
  - LICENSE.txt
92
- - README.rdoc
106
+ - README.md
93
107
  - Rakefile
94
108
  - VERSION
95
109
  - fluent-plugin-dstat.gemspec
@@ -110,7 +124,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
124
  version: '0'
111
125
  segments:
112
126
  - 0
113
- hash: 3115706696286106192
127
+ hash: -4423186394386880393
114
128
  required_rubygems_version: !ruby/object:Gem::Requirement
115
129
  none: false
116
130
  requirements:
@@ -119,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
133
  version: '0'
120
134
  requirements: []
121
135
  rubyforge_project:
122
- rubygems_version: 1.8.10
136
+ rubygems_version: 1.8.23
123
137
  signing_key:
124
138
  specification_version: 3
125
139
  summary: Dstat Input plugin for Fluent event collector
data/README.rdoc DELETED
@@ -1,43 +0,0 @@
1
- = Dstat plugin for Fluent
2
-
3
- Description goes here.
4
-
5
- == What's Dstat?
6
-
7
- Dstat is a versatile replacement for vmstat, iostat, netstat and ifstat.
8
- If you need more detail, see here[http://dag.wieers.com/home-made/dstat]
9
- This plugin use Dstat, so you need to install Dstat before using this plugin.
10
-
11
- == Configuration
12
-
13
- <source>
14
- type dstat
15
- tag dstat
16
- option -c 3
17
- </source>
18
-
19
- * option:option for dstat command(default: -fcdnm 1)
20
-
21
- == Output Format
22
-
23
- When you use option -c, you get structured output data like below.
24
-
25
- {
26
- "hostname":"tsukuba000",
27
- "dstat":{"total-cpu-usage":{"usr":"0",
28
- "sys":"0",
29
- "idl":"100",
30
- "wai":"0",
31
- "hiq":"0",
32
- "siq":"0"}}
33
- }
34
-
35
- == Supported options
36
-
37
- aio, cpu, cpu24, disk, epoch, fs, int, int24, io, ipc, load, lock, mem, net, page, page24, proc, raw, socket, swap, swapold, sys, tcp, udp, unix, vm, disk-tps, disk-util, dstat-cpu, dstat-ctxt, dstat-mem, freespace, top-bio, top-childwait, top-cpu,top-io, top-mem, top-oom, utmp, top-io -fc
38
-
39
- == Copyright
40
-
41
- Copyright (c) 2011 Shunsuke Mikami. See LICENSE.txt for
42
- further details.
43
-