fluent-diagtool 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +13 -0
- data/AUTHORS +1 -1
- data/Gemfile.lock +5 -5
- data/README.md +14 -11
- data/exe/diagtool +10 -2
- data/lib/fluent/diagtool/collectutils.rb +83 -26
- data/lib/fluent/diagtool/diagutils.rb +84 -12
- data/lib/fluent/diagtool/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 180c7e58ee03d59778640b05042fca84197936b7bdd2b2fff236ef86f0639ef4
|
4
|
+
data.tar.gz: b1ffccfb3a92af08dfa17fe4796e7a229a25d0abe1bf0f1362ac4618bf5c99f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b482bfc75cda3285976980d2f8a04abfe848dd9bb6ff4992c0760f871f237811fbae361dfb15075482a781ec284974d7471937423e3400f0b576bc3dff03ccf0
|
7
|
+
data.tar.gz: 5810ec1b6f37b5ccf49f53bd8271beb885dde8c7b9e8be33aed38b5d137e8952085aaddbb8b7717e58535bd36decd19e1babde94a2ba78d07ba41d1ffd0cf9c5
|
data/.gitignore
ADDED
data/AUTHORS
CHANGED
@@ -1 +1 @@
|
|
1
|
-
TOMONORI KUBOTA <
|
1
|
+
TOMONORI KUBOTA <tkubota _at_ ctc-america.com>
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fluent-diagtool (0.1.
|
5
|
-
fileutils (~> 1.0
|
6
|
-
json (~> 2.1
|
4
|
+
fluent-diagtool (0.1.4)
|
5
|
+
fileutils (~> 1.0)
|
6
|
+
json (~> 2.1)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
11
|
diff-lcs (1.3)
|
12
|
-
fileutils (1.
|
13
|
-
json (2.
|
12
|
+
fileutils (1.4.1)
|
13
|
+
json (2.3.0)
|
14
14
|
rake (12.3.3)
|
15
15
|
rspec (3.9.0)
|
16
16
|
rspec-core (~> 3.9.0)
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Fluentd Diagnostic Tool
|
2
2
|
|
3
|
-
The diagtool enable users to automate the date collection which is required for trouble shooting. The data collected by diagtool include the configuration and log files of the td-agent and diagnostic information of operating system such as network and memory status and stats. In some cases, configuration and log files contains the security sensitive information, such as IP addresses and Hostname. The diagtool also provides the functions to generate mask on IP addresses, Hostname(in FQDN style) and user defined keywords described in the collected data
|
4
|
-
The scope of data collection
|
3
|
+
The diagtool enable users to automate the date collection which is required for trouble shooting. The data collected by diagtool include the configuration and log files of the td-agent and diagnostic information of operating system such as network and memory status and stats. In some cases, configuration and log files contains the security sensitive information, such as IP addresses and Hostname. The diagtool also provides the functions to generate mask on IP addresses, Hostname(in FQDN style) and user defined keywords described in the collected data.
|
4
|
+
The scope of data collection:
|
5
5
|
- TD Agent information
|
6
6
|
- configuration files (*)
|
7
7
|
- log files (*)
|
@@ -11,18 +11,21 @@ The scope of data collection:
|
|
11
11
|
- OS log file
|
12
12
|
- OS parameters
|
13
13
|
- OS and kernel version
|
14
|
-
- time/date information
|
15
|
-
- maximum number of file descriptor(ulimit)
|
14
|
+
- time/date information(ntp -q/chronyc sources)
|
15
|
+
- maximum number of file descriptor(ulimit -n)
|
16
16
|
- kernel network parameters(sysctl)
|
17
|
-
-
|
18
|
-
-
|
17
|
+
- snapshot of current process(ps)
|
18
|
+
- network conectivity status/stats(netstat -plan/netstat -s)
|
19
|
+
- memory information(/proc/meminfo)
|
19
20
|
<br>
|
20
|
-
(*) The diagtool automatically gather the path of td-agent configuration files and log files and use them during data collection.
|
21
|
+
(*) The diagtool automatically gather the path of td-agent configuration files and log files from td-agent daemon and use them during data collection.
|
21
22
|
|
22
23
|
## Prerequisite
|
24
|
+
The diagtool provides support for td-agent based installation running on Linux OS. The td-agent is a stable distribution package of Fluentd.
|
25
|
+
The differences between Fluentd and td-agent are described in followed url:
|
26
|
+
https://www.fluentd.org/faqs
|
23
27
|
|
24
|
-
|
25
|
-
## Installation
|
28
|
+
## Diagtool Installation
|
26
29
|
|
27
30
|
```
|
28
31
|
# gem install fluent-diagtool
|
@@ -114,8 +117,8 @@ NOTE: When user specified the keywork, only the exact match words will be masked
|
|
114
117
|
2020-05-12 18:21:22 -0400: [Diagtool] [INFO] [Collect] Generate tar file /tmp/work1/diagout-20200512182119.tar.gz
|
115
118
|
```
|
116
119
|
## Mask Function
|
117
|
-
When run diagtool with mask option, the log of mask is also created in 'mask_{timestamp}.json' file. Users are able to confirm how the mask was generated on each files.
|
118
|
-
|
120
|
+
When run diagtool with mask option, the log of mask is also created in 'mask_{timestamp}.json' file. Users are able to confirm how the mask was generated on each files.
|
121
|
+
The diagtool provides hash-seed option with '-s'. When hash-seed is specified, the mask will be generated with original word and hash-seed so that users could use unique mask value.
|
119
122
|
#### Mask sample - IP address: IPv4_{md5hash}
|
120
123
|
```
|
121
124
|
"Line112-8": {
|
data/exe/diagtool
CHANGED
@@ -26,13 +26,21 @@ include Diagtool
|
|
26
26
|
params = {}
|
27
27
|
OptionParser.new do |opt|
|
28
28
|
opt.banner = "Usage: #{$0} -o OUTPUT_DIR -m {yes | no} -w {word1,[word2...]} -f {listfile} -s {hash seed}"
|
29
|
+
opt.on('--precheck', 'Run Precheck (Optional)')
|
29
30
|
opt.on('-o','--output DIR', String, 'Output directory (Mandatory)')
|
30
31
|
opt.on('-m','--mask yes|no', String, 'Enable mask function (Optional : Default=no)')
|
31
32
|
opt.on('-w','--word-list word1,word2', Array, 'Provide a list of user-defined words which will to be masked (Optional : Default=None)')
|
32
|
-
opt.on('-f','--word-file
|
33
|
+
opt.on('-f','--word-file list_file', String, 'provide a file which describes a List of user-defined words (Optional : Default=None)')
|
33
34
|
opt.on('-s','--hash-seed seed', String, 'provide a word which will be used when generate the mask (Optional : Default=None)')
|
35
|
+
opt.on('-c','--conf config_file', String, 'provide a full path of td-agent configuration file (Optional : Default=None)')
|
36
|
+
opt.on('-l','--log log_file', String, 'provide a full path of td-agent log file (Optional : Default=None)')
|
34
37
|
end.parse!(into: params)
|
38
|
+
|
35
39
|
diag = DiagUtils.new(params)
|
36
|
-
|
40
|
+
if params[:precheck]
|
41
|
+
diag.run_precheck()
|
42
|
+
else
|
43
|
+
diag.run_diagtool()
|
44
|
+
end
|
37
45
|
|
38
46
|
|
@@ -24,17 +24,35 @@ module Diagtool
|
|
24
24
|
@logger = Logger.new(STDOUT, level: log_level, formatter: proc {|severity, datetime, progname, msg|
|
25
25
|
"#{datetime}: [Diagutils] [#{severity}] #{msg}\n"
|
26
26
|
})
|
27
|
+
@precheck = conf[:precheck]
|
27
28
|
@time_format = conf[:time]
|
28
29
|
@basedir = conf[:basedir]
|
29
30
|
@workdir = conf[:workdir]
|
30
31
|
@outdir = conf[:outdir]
|
31
|
-
|
32
|
+
|
32
33
|
@tdenv = get_tdenv()
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
if not conf[:tdconf].empty?
|
35
|
+
@tdconf = conf[:tdconf].split('/')[-1]
|
36
|
+
@tdconf_path = conf[:tdconf].gsub(@tdconf,'')
|
37
|
+
elsif
|
38
|
+
if not @tdenv['FLUENT_CONF'].empty?
|
39
|
+
@tdconf = @tdenv['FLUENT_CONF'].split('/')[-1]
|
40
|
+
@tdconf_path = @tdenv['FLUENT_CONF'].gsub(@tdconf,'')
|
41
|
+
else
|
42
|
+
raise "The path of td-agent configuration file need to be specified." if conf[:precheck] == false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
if not conf[:tdlog].empty?
|
46
|
+
@tdlog = conf[:tdlog].split('/')[-1]
|
47
|
+
@tdlog_path = conf[:tdlog].gsub(@tdlog,'')
|
48
|
+
elsif
|
49
|
+
if not @tdenv['TD_AGENT_LOG_FILE'].empty?
|
50
|
+
@tdlog = @tdenv['TD_AGENT_LOG_FILE'].split('/')[-1]
|
51
|
+
@tdlog_path = @tdenv['TD_AGENT_LOG_FILE'].gsub(@tdlog,'')
|
52
|
+
else
|
53
|
+
raise "The path of td-agent log file need to be specified." if conf[:precheck] == false
|
54
|
+
end
|
55
|
+
end
|
38
56
|
@osenv = get_osenv()
|
39
57
|
@oslog_path = '/var/log/'
|
40
58
|
@oslog = 'messages'
|
@@ -57,8 +75,10 @@ module Diagtool
|
|
57
75
|
s = l.split(":")
|
58
76
|
os_dict[s[0].chomp.strip] = s[1].chomp.strip
|
59
77
|
}
|
60
|
-
|
61
|
-
|
78
|
+
if @precheck == false # SKip if precheck is true
|
79
|
+
File.open(@outdir+'/os_env.output', 'w') do |f|
|
80
|
+
f.puts(stdout)
|
81
|
+
end
|
62
82
|
end
|
63
83
|
return os_dict
|
64
84
|
end
|
@@ -66,13 +86,43 @@ module Diagtool
|
|
66
86
|
def get_tdenv()
|
67
87
|
stdout, stderr, status = Open3.capture3('systemctl cat td-agent')
|
68
88
|
env_dict = {}
|
69
|
-
|
70
|
-
|
71
|
-
|
89
|
+
if status.success?
|
90
|
+
if @precheck == false # SKip if precheck is true
|
91
|
+
File.open(@outdir+'/td-agent_env.output', 'w') do |f|
|
92
|
+
f.puts(stdout)
|
93
|
+
end
|
94
|
+
end
|
72
95
|
stdout.split().each do | l |
|
73
|
-
|
74
|
-
|
75
|
-
|
96
|
+
if l.include?('Environment')
|
97
|
+
env_dict[l.split('=')[1]] = l.split('=')[2]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
exe = 'fluentd'
|
102
|
+
stdout, stderr, status = Open3.capture3("ps aux | grep #{exe} | grep -v grep")
|
103
|
+
line = stdout.split(/\n/)
|
104
|
+
log_path = ''
|
105
|
+
conf_path = ''
|
106
|
+
line.each { |l|
|
107
|
+
cmd = l.split.drop(10)
|
108
|
+
i = 0
|
109
|
+
log_pos = 0
|
110
|
+
conf_pos = 0
|
111
|
+
if cmd[-1] != '--under-supervisor'
|
112
|
+
cmd.each { |c|
|
113
|
+
if c.include?("--log") || c.include?("-l")
|
114
|
+
log_pos = i + 1
|
115
|
+
log_path = cmd[log_pos]
|
116
|
+
elsif c.include?("--conf") || c.include?("-c")
|
117
|
+
conf_pos = i + 1
|
118
|
+
conf_path = cmd[conf_pos]
|
119
|
+
end
|
120
|
+
i+=1
|
121
|
+
}
|
122
|
+
end
|
123
|
+
}
|
124
|
+
env_dict['FLUENT_CONF'] = conf_path
|
125
|
+
env_dict['TD_AGENT_LOG_FILE'] = log_path
|
76
126
|
end
|
77
127
|
return env_dict
|
78
128
|
end
|
@@ -90,27 +140,34 @@ module Diagtool
|
|
90
140
|
end
|
91
141
|
|
92
142
|
def collect_tdconf()
|
93
|
-
|
94
|
-
FileUtils.
|
95
|
-
|
143
|
+
target_dir = @workdir+@tdconf_path
|
144
|
+
FileUtils.mkdir_p(target_dir)
|
145
|
+
FileUtils.cp(@tdconf_path+@tdconf, target_dir)
|
146
|
+
return target_dir+@tdconf
|
96
147
|
end
|
97
148
|
|
98
149
|
def collect_tdlog()
|
99
|
-
|
100
|
-
|
101
|
-
|
150
|
+
target_dir = @workdir+@tdlog_path
|
151
|
+
p target_dir
|
152
|
+
FileUtils.mkdir_p(target_dir)
|
153
|
+
Dir.glob(@tdlog_path+@tdlog+'*').each{ |f|
|
154
|
+
FileUtils.cp(f, target_dir)
|
155
|
+
}
|
156
|
+
return Dir.glob(target_dir+@tdlog+'*')
|
102
157
|
end
|
103
158
|
|
104
159
|
def collect_sysctl()
|
105
|
-
|
106
|
-
FileUtils.
|
107
|
-
|
160
|
+
target_dir = @workdir+@sysctl_path
|
161
|
+
FileUtils.mkdir_p(target_dir)
|
162
|
+
FileUtils.cp(@sysctl_path+@sysctl, target_dir)
|
163
|
+
return target_dir+@sysctl
|
108
164
|
end
|
109
165
|
|
110
166
|
def collect_oslog()
|
111
|
-
|
112
|
-
FileUtils.
|
113
|
-
|
167
|
+
target_dir = @workdir+@oslog_path
|
168
|
+
FileUtils.mkdir_p(target_dir)
|
169
|
+
FileUtils.cp(@oslog_path+@oslog, target_dir)
|
170
|
+
return target_dir+@oslog
|
114
171
|
end
|
115
172
|
|
116
173
|
def collect_ulimit()
|
@@ -27,14 +27,62 @@ module Diagtool
|
|
27
27
|
time = Time.new
|
28
28
|
@time_format = time.strftime("%Y%m%d%0k%M%0S")
|
29
29
|
@conf = parse_diagconf(params)
|
30
|
+
#@conf[:time] = @time_format
|
31
|
+
#@conf[:workdir] = @conf[:basedir] + '/' + @time_format
|
32
|
+
#@conf[:outdir] = @conf[:workdir] + '/output'
|
33
|
+
|
34
|
+
#FileUtils.mkdir_p(@conf[:workdir])
|
35
|
+
#FileUtils.mkdir_p(@conf[:outdir])
|
36
|
+
|
37
|
+
#diaglog = @conf[:workdir] + '/diagtool.output'
|
38
|
+
#@masklog = './mask_' + @time_format + '.json'
|
39
|
+
#@logger = Logger.new(STDOUT, formatter: proc {|severity, datetime, progname, msg|
|
40
|
+
# "#{datetime}: [Diagtool] [#{severity}] #{msg}\n"
|
41
|
+
#})
|
42
|
+
#@logger_file = Logger.new(diaglog, formatter: proc {|severity, datetime, progname, msg|
|
43
|
+
# "#{datetime}: [Diagtool] [#{severity}] #{msg}\n"
|
44
|
+
#})
|
45
|
+
#diaglogger_info("Parsing command options...")
|
46
|
+
#diaglogger_info(" Option : Output directory = #{@conf[:basedir]}")
|
47
|
+
#diaglogger_info(" Option : Mask = #{@conf[:mask]}")
|
48
|
+
#diaglogger_info(" Option : Word list = #{@conf[:words]}")
|
49
|
+
#diaglogger_info(" Option : Hash Seed = #{@conf[:seed]}")
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_precheck()
|
53
|
+
prechecklog = Logger.new(STDOUT, formatter: proc {|severity, datetime, progname, msg|
|
54
|
+
"#{datetime}: [Diagtool] [#{severity}] #{msg}\n"
|
55
|
+
})
|
56
|
+
loglevel = 'WARN'
|
57
|
+
c = CollectUtils.new(@conf, loglevel)
|
58
|
+
c_env = c.export_env()
|
59
|
+
prechecklog.info("[Precheck] Check OS parameters...")
|
60
|
+
prechecklog.info("[Precheck] operating system = #{c_env[:os]}")
|
61
|
+
prechecklog.info("[Precheck] kernel version = #{c_env[:kernel]}")
|
62
|
+
prechecklog.info("[Precheck] Check td-agent parameters...")
|
63
|
+
prechecklog.info("[Precheck] td-agent conf path = #{c_env[:tdconf_path]}")
|
64
|
+
prechecklog.info("[Precheck] td-agent conf file = #{c_env[:tdconf]}")
|
65
|
+
prechecklog.info("[Precheck] td-agent log path = #{c_env[:tdlog_path]}")
|
66
|
+
prechecklog.info("[Precheck] td-agent log = #{c_env[:tdlog]}")
|
67
|
+
if c_env[:tdconf_path] == nil || c_env[:tdconf] == nil
|
68
|
+
prechecklog.warn("[Precheck] can not find td-agent conf path: please run diagtool command with -c /path/to/<td-agent conf file>")
|
69
|
+
end
|
70
|
+
if c_env[:tdlog_path] == nil || c_env[:tdlog] == nil
|
71
|
+
prechecklog.warn("[Precheck] can not find td-agent log path: please run diagtool command with -l /path/to/<td-agent log file>")
|
72
|
+
end
|
73
|
+
if c_env[:tdconf_path] != nil && c_env[:tdconf] != nil && c_env[:tdlog_path] != nil && c_env[:tdlog] != nil
|
74
|
+
prechecklog.info("[Precheck] Precheck completed. You can run diagtool command without -c and -l options")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def run_diagtool()
|
30
79
|
@conf[:time] = @time_format
|
31
80
|
@conf[:workdir] = @conf[:basedir] + '/' + @time_format
|
32
81
|
@conf[:outdir] = @conf[:workdir] + '/output'
|
33
|
-
|
34
82
|
FileUtils.mkdir_p(@conf[:workdir])
|
35
83
|
FileUtils.mkdir_p(@conf[:outdir])
|
36
|
-
|
37
84
|
diaglog = @conf[:workdir] + '/diagtool.output'
|
85
|
+
|
38
86
|
@masklog = './mask_' + @time_format + '.json'
|
39
87
|
@logger = Logger.new(STDOUT, formatter: proc {|severity, datetime, progname, msg|
|
40
88
|
"#{datetime}: [Diagtool] [#{severity}] #{msg}\n"
|
@@ -47,9 +95,7 @@ module Diagtool
|
|
47
95
|
diaglogger_info(" Option : Mask = #{@conf[:mask]}")
|
48
96
|
diaglogger_info(" Option : Word list = #{@conf[:words]}")
|
49
97
|
diaglogger_info(" Option : Hash Seed = #{@conf[:seed]}")
|
50
|
-
|
51
|
-
|
52
|
-
def diagtool()
|
98
|
+
|
53
99
|
loglevel = 'WARN'
|
54
100
|
diaglogger_info("Initializing parameters...")
|
55
101
|
c = CollectUtils.new(@conf, loglevel)
|
@@ -167,16 +213,23 @@ module Diagtool
|
|
167
213
|
|
168
214
|
def parse_diagconf(params)
|
169
215
|
options = {
|
170
|
-
:basedir => '', :mask => '', :words => [], :wfile => '', :seed => ''
|
216
|
+
:precheck => '', :basedir => '', :mask => '', :words => [], :wfile => '', :seed => '', :tdconf =>'', :tdlog => ''
|
171
217
|
}
|
172
|
-
if params[:
|
173
|
-
|
174
|
-
|
218
|
+
if params[:precheck]
|
219
|
+
options[:precheck] = params[:precheck]
|
220
|
+
else
|
221
|
+
options[:precheck] = false
|
222
|
+
end
|
223
|
+
if options[:precheck] == false
|
224
|
+
if params[:output] != nil
|
225
|
+
if Dir.exist?(params[:output])
|
226
|
+
options[:basedir] = params[:output]
|
227
|
+
else
|
228
|
+
raise "output directory '#{basedir}' does not exist"
|
229
|
+
end
|
175
230
|
else
|
176
|
-
raise "output directory '
|
231
|
+
raise "output directory '-o' must be specified"
|
177
232
|
end
|
178
|
-
else
|
179
|
-
raise "output directory '-o' must be specified"
|
180
233
|
end
|
181
234
|
if params[:mask] == nil
|
182
235
|
options[:mask] = 'no'
|
@@ -200,6 +253,25 @@ module Diagtool
|
|
200
253
|
end
|
201
254
|
options[:words] = options[:words].uniq
|
202
255
|
options[:seed] = params[:"hash-seed"] if params[:"hash-seed"] != nil
|
256
|
+
|
257
|
+
if params[:conf] != nil
|
258
|
+
f = params[:conf]
|
259
|
+
if File.exist?(f)
|
260
|
+
options[:tdconf] = params[:conf]
|
261
|
+
else
|
262
|
+
raise "#{params[:conf]} : No such file or directory"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
if params[:log] != nil
|
267
|
+
f = params[:log]
|
268
|
+
if File.exist?(f)
|
269
|
+
options[:tdlog] = params[:log]
|
270
|
+
else
|
271
|
+
raise "#{params[:log]} : No such file or directory"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
203
275
|
return options
|
204
276
|
end
|
205
277
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-diagtool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kubotat
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fileutils
|
@@ -48,6 +48,7 @@ executables:
|
|
48
48
|
extensions: []
|
49
49
|
extra_rdoc_files: []
|
50
50
|
files:
|
51
|
+
- ".gitignore"
|
51
52
|
- AUTHORS
|
52
53
|
- Gemfile
|
53
54
|
- Gemfile.lock
|