fluent-plugin-top 0.1.0
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 +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +39 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/fluent-plugin-top.gemspec +25 -0
- data/lib/fluent/plugin/in_top.rb +108 -0
- data/lib/fluent/plugin/in_top_parser.rb +80 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 68d92f3f4a576246b36676c92c36d930a29512a2
|
4
|
+
data.tar.gz: f171f9eb83e0999918432beb4a25c83b166347cd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74c90f3744cce92369344c10a1db9090a7484bd75e7c837f08df2617fb3cd0ebcf33148d9e94d904d97a6662037930ae49f33982489cac9d90c45a308a791fcf
|
7
|
+
data.tar.gz: 9b4019cfde8285e36f195e4d8ed92da80e6603e1214982d5631787790a7b0ffbf58c853d3160e46c6ad376bb6813e28abaeb5598eec6a7b22c5c4b41ef1241e5
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2016 Tetsu Izawa (@moccos)
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
fluent-plugin-top
|
2
|
+
===
|
3
|
+
|
4
|
+
Fluentd input plugin for top command.
|
5
|
+
|
6
|
+
If you focus on system metrics rather than each process,
|
7
|
+
you should use [dstat plugin](https://github.com/shun0102/fluent-plugin-dstat).
|
8
|
+
|
9
|
+
## Configuration
|
10
|
+
<source>
|
11
|
+
@type top
|
12
|
+
tag local.top # *required*
|
13
|
+
interval 30 # default: 10.0
|
14
|
+
command_line true # default: true
|
15
|
+
extra_switch -w 200 # default: ""
|
16
|
+
cpu_percent 50 # default: nil
|
17
|
+
</source>
|
18
|
+
|
19
|
+
* **tag**: Output tag. [required]
|
20
|
+
* **interval**: Refresh interval in sec.
|
21
|
+
* **command_line**: Get command line (/usr/bin/ruby foo.rb -v) instead of simple name (ruby).
|
22
|
+
* **extra_switch**: Extra command line switch for top command.
|
23
|
+
* **cpu_percent**: Threshold - CPU usage (percent).
|
24
|
+
* **mem_percent**: Threshold - Memory usage (percent).
|
25
|
+
* **mem**: Threshold - Memory usage in megabytes.
|
26
|
+
|
27
|
+
At least one threshold parameter should be specified.
|
28
|
+
Otherwise, this plugin does not output anything.
|
29
|
+
If you specify multiple threshold parameters, they are "OR"ed.
|
30
|
+
|
31
|
+
<!--== Examples-->
|
32
|
+
|
33
|
+
<!--TODO: write here-->
|
34
|
+
|
35
|
+
## Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2016 Tetsu Izawa (@moccos)
|
38
|
+
|
39
|
+
Apache License, Version 2.0
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "fluent-plugin-top"
|
7
|
+
spec.version = "0.1.0"
|
8
|
+
spec.authors = ["Tetsu Izawa (@moccos)"]
|
9
|
+
spec.email = ["tt.izawa@gmail.com"]
|
10
|
+
spec.homepage = "https://github.com/moccos/fluent-plugin-top"
|
11
|
+
|
12
|
+
spec.summary = %q{Fluentd top command input plugin}
|
13
|
+
spec.description = %q{Fluentd top command input plugin}
|
14
|
+
spec.licenses = ["Apache License, Version 2.0"]
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_runtime_dependency "fluentd", ">= 0.12.0"
|
24
|
+
spec.add_runtime_dependency "fluent-mixin-rewrite-tag-name"
|
25
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'fluent/input'
|
3
|
+
require 'fluent/mixin/rewrite_tag_name'
|
4
|
+
require_relative 'in_top_parser'
|
5
|
+
|
6
|
+
module Fluent
|
7
|
+
class TopInput < Fluent::Input
|
8
|
+
INTERVAL_MIN = 0.5 # avoid too short interval
|
9
|
+
|
10
|
+
Fluent::Plugin.register_input('top', self)
|
11
|
+
desc "Top command. Don't forget to specify batch switch (-b)."
|
12
|
+
config_param :top, :string, :default => "top -b"
|
13
|
+
desc 'Output tag.'
|
14
|
+
config_param :tag, :string
|
15
|
+
|
16
|
+
### Command line options
|
17
|
+
desc 'Refresh interval. (top -d)'
|
18
|
+
config_param :interval, :float, :default => 10.0
|
19
|
+
desc 'Get command line. (top -c)'
|
20
|
+
config_param :command_line, :bool, :default => true
|
21
|
+
desc 'Extra command line args for top command.'
|
22
|
+
config_param :extra_switch, :string, :default => ""
|
23
|
+
|
24
|
+
### Conditions
|
25
|
+
desc "Threshold - CPU usage (percent)."
|
26
|
+
config_param :cpu_percent, :float, :default => nil
|
27
|
+
desc "Threshold - Memory usage (percent)."
|
28
|
+
config_param :mem_percent, :float, :default => nil
|
29
|
+
desc "Threshold - Memory usage in megabytes."
|
30
|
+
config_param :mem, :integer, :default => nil
|
31
|
+
|
32
|
+
### Future works
|
33
|
+
#config_param :cpu_rank, :integer, :default => nil
|
34
|
+
#config_param :pid, :array, :default => []
|
35
|
+
#config_param :pid_file, :array, :default => []
|
36
|
+
#config_param :pid_file_watch_interval, :int, :default => 30
|
37
|
+
|
38
|
+
desc 'Command line and args. This overrides other settings.'
|
39
|
+
config_param :test_cmd, :string, :default => nil
|
40
|
+
|
41
|
+
# for fluent-mixin-rewrite-tag-name
|
42
|
+
include Fluent::Mixin::RewriteTagName
|
43
|
+
desc 'Command to get hostname. Typically it is "hostname" or "hostname -s".'
|
44
|
+
config_param :hostname_command, :string, :default => "hostname"
|
45
|
+
|
46
|
+
def configure(conf)
|
47
|
+
super
|
48
|
+
interval = @interval > INTERVAL_MIN ? @interval : INTERVAL_MIN
|
49
|
+
@top_command =
|
50
|
+
if @test_cmd then
|
51
|
+
@test_cmd
|
52
|
+
else
|
53
|
+
"#{@top} -d #{interval} #{@command_line ? "-c" : ""} #{@extra_switch}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def start
|
58
|
+
super
|
59
|
+
@top_thread = Thread.new do
|
60
|
+
run_top()
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def shutdown
|
65
|
+
super
|
66
|
+
$log.trace "Shutdown top command thread."
|
67
|
+
@top_thread.kill if @top_thread
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def run_top
|
72
|
+
$log.trace "Top command thread is running: " + @top_command
|
73
|
+
IO.popen(@top_command, "r") {|io|
|
74
|
+
parser = Fluent::TopInputParser.new()
|
75
|
+
io.each {|line|
|
76
|
+
result, ps = parser.parse(line)
|
77
|
+
if result && check_ps_info(ps) then
|
78
|
+
ps.args = ps.args.join(' ')
|
79
|
+
emit_message(@tag, ps.to_h)
|
80
|
+
end
|
81
|
+
}
|
82
|
+
}
|
83
|
+
$log.info "Exit top command thread. (reached EOF)"
|
84
|
+
end
|
85
|
+
|
86
|
+
def check_ps_info(ps)
|
87
|
+
# For now, all conditions are "OR"ed
|
88
|
+
case
|
89
|
+
when @cpu_percent && ps.cpu >= @cpu_percent
|
90
|
+
true
|
91
|
+
when @mem_percent && ps.mem >= @mem_percent
|
92
|
+
true
|
93
|
+
when @mem && ps.res >= @mem * 1024 # megabytes
|
94
|
+
true
|
95
|
+
else
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def emit_message(tag, message)
|
101
|
+
time = Engine.now
|
102
|
+
# for fluent-mixin-rewrite-tag-name
|
103
|
+
emit_tag = tag.dup
|
104
|
+
filter_record(emit_tag, time, message)
|
105
|
+
router.emit(emit_tag, time, message)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Fluent
|
2
|
+
class TopInputParser
|
3
|
+
### state
|
4
|
+
STATE_HEADER = 1
|
5
|
+
STATE_PROCESS = 2
|
6
|
+
|
7
|
+
@@PS_INFO = Struct.new(:pid, :user, :res, :cpu, :mem, :cmd, :args)
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
reset_state
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(line)
|
14
|
+
case @state
|
15
|
+
when STATE_HEADER then
|
16
|
+
return parse_header line
|
17
|
+
else
|
18
|
+
return parse_process line
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def reset_state()
|
24
|
+
@state = STATE_HEADER
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_header(line)
|
28
|
+
# PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
29
|
+
# 1 root 20 0 38004 5992 3916 S 0.0 0.6 0:03.43 systemd
|
30
|
+
|
31
|
+
ss = line.split("\s")
|
32
|
+
@state = STATE_PROCESS if ss[0] == "PID"
|
33
|
+
return false, nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_process(line)
|
37
|
+
ss = line.split("\s")
|
38
|
+
if !is_number?(ss[0]) then
|
39
|
+
reset_state
|
40
|
+
return parse_header(line)
|
41
|
+
end
|
42
|
+
begin
|
43
|
+
pid, user, _pr, _ni, _virt, res, _shr, _s, cpu, mem, _time, cmd = ss
|
44
|
+
args = ss.drop(12)
|
45
|
+
return true, @@PS_INFO.new(pid.to_i, user, res, cpu.to_f, mem.to_f, cmd, args)
|
46
|
+
rescue => e
|
47
|
+
$log.warn "parse error #{e.to_s}: " + line
|
48
|
+
reset_state
|
49
|
+
return false, nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_number?(s)
|
54
|
+
begin
|
55
|
+
Float(s)
|
56
|
+
true
|
57
|
+
rescue
|
58
|
+
false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_unit(s)
|
63
|
+
begin
|
64
|
+
case s[-1]
|
65
|
+
when "m"
|
66
|
+
s[0, s.length-1].to_f * 1024
|
67
|
+
when "g"
|
68
|
+
s[0, s.length-1].to_f * 1024 * 1024
|
69
|
+
#when "t" # I've never seen...
|
70
|
+
#s[0, s.length-1].to_f * 1024 * 1024 * 1024
|
71
|
+
else
|
72
|
+
s.to_i
|
73
|
+
end
|
74
|
+
rescue
|
75
|
+
$log.warn "Memory unit parse error: " + s
|
76
|
+
-1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-top
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tetsu Izawa (@moccos)
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fluentd
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.12.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.12.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fluent-mixin-rewrite-tag-name
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Fluentd top command input plugin
|
70
|
+
email:
|
71
|
+
- tt.izawa@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- VERSION
|
82
|
+
- fluent-plugin-top.gemspec
|
83
|
+
- lib/fluent/plugin/in_top.rb
|
84
|
+
- lib/fluent/plugin/in_top_parser.rb
|
85
|
+
homepage: https://github.com/moccos/fluent-plugin-top
|
86
|
+
licenses:
|
87
|
+
- Apache License, Version 2.0
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.6.6
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Fluentd top command input plugin
|
109
|
+
test_files: []
|