fluentd-ui 1.0.1 → 1.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.
Potentially problematic release.
This version of fluentd-ui might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ChangeLog.md +5 -0
- data/Gemfile.lock +1 -1
- data/app/controllers/api/settings_controller.rb +46 -16
- data/app/controllers/concerns/setting_concern.rb +1 -1
- data/app/controllers/fluentd/settings/filter_grep_controller.rb +9 -0
- data/app/controllers/fluentd/settings/filter_parser_controller.rb +9 -0
- data/app/controllers/fluentd/settings/filter_record_transformer_controller.rb +14 -0
- data/app/controllers/fluentd/settings/filter_stdout_controller.rb +9 -0
- data/app/javascript/packs/filter_grep_setting.js +39 -0
- data/app/javascript/packs/grep_container.js +53 -0
- data/app/javascript/packs/grep_pattern.js +43 -0
- data/app/javascript/packs/owned_plugin_form.js +9 -7
- data/app/javascript/packs/settings.js +34 -16
- data/app/models/concerns/fluentd/setting/configurable.rb +1 -0
- data/app/models/concerns/fluentd/setting/label.rb +11 -0
- data/app/models/concerns/fluentd/setting/plugin.rb +2 -0
- data/app/models/concerns/fluentd/setting/plugin_config.rb +34 -4
- data/app/models/concerns/fluentd/setting/section_config.rb +10 -2
- data/app/models/fluentd/agent/common.rb +97 -0
- data/app/models/fluentd/setting/config.rb +71 -0
- data/app/models/fluentd/setting/filter_grep.rb +38 -0
- data/app/models/fluentd/setting/filter_parser.rb +34 -0
- data/app/models/fluentd/setting/filter_record_transformer.rb +27 -0
- data/app/models/fluentd/setting/filter_stdout.rb +34 -0
- data/app/models/fluentd/setting/in_forward.rb +1 -0
- data/app/models/fluentd/setting/in_http.rb +1 -1
- data/app/models/fluentd/setting/in_monitor_agent.rb +1 -1
- data/app/models/fluentd/setting/in_syslog.rb +1 -1
- data/app/models/fluentd/setting/out_elasticsearch.rb +1 -0
- data/app/models/fluentd/setting/out_forward.rb +1 -1
- data/app/models/fluentd/setting/out_mongo.rb +1 -0
- data/app/models/fluentd/setting/out_s3.rb +1 -0
- data/app/models/fluentd/setting/out_stdout.rb +1 -1
- data/app/models/fluentd/setting/out_tdlog.rb +1 -1
- data/app/views/api/settings/_element.json.jbuilder +3 -1
- data/app/views/api/settings/index.json.jbuilder +10 -2
- data/app/views/api/settings/show.json.jbuilder +1 -1
- data/app/views/fluentd/settings/filter_grep/_form.html.haml +18 -0
- data/app/views/fluentd/settings/filter_record_transformer/_form.html.haml +20 -0
- data/app/views/fluentd/settings/in_tail/_form.html.haml +1 -0
- data/app/views/fluentd/settings/source_and_output.html.haml +46 -14
- data/app/views/shared/vue/_filter_grep_setting.html.haml +19 -0
- data/app/views/shared/vue/_grep_container.html.haml +32 -0
- data/app/views/shared/vue/_grep_pattern.html.haml +24 -0
- data/app/views/shared/vue/_setting.html.erb +2 -2
- data/config/locales/translation_en.yml +39 -10
- data/config/locales/translation_ja.yml +39 -10
- data/config/routes.rb +6 -0
- data/lib/fluentd-ui/version.rb +1 -1
- data/test/factories/fluentd.rb +4 -4
- data/test/factories/plugins.rb +2 -2
- data/test/factories/user.rb +2 -2
- data/test/fixtures/config/label.conf +15 -0
- data/test/fixtures/config/multi-label.conf +40 -0
- data/test/fixtures/config/simple.conf +12 -0
- data/test/models/fluentd/agent_common_test.rb +288 -0
- data/test/models/fluentd/setting/config_test.rb +98 -0
- data/test/support/configurable_daemon_settings.rb +1 -1
- data/test/system/fluentd/setting/filter_grep_test.rb +96 -0
- data/test/system/fluentd/setting/filter_parser_test.rb +13 -0
- data/test/system/fluentd/setting/filter_record_transformer_test.rb +30 -0
- data/test/system/fluentd/setting/filter_stdout_test.rb +13 -0
- data/test/system/source_and_output_test.rb +168 -19
- data/test/test_helper.rb +4 -0
- metadata +98 -55
- data/.rspec +0 -2
@@ -1,4 +1,5 @@
|
|
1
1
|
require "fluent/plugin"
|
2
|
+
require "fluent/plugin/buf_file"
|
2
3
|
require "fluent/test/log"
|
3
4
|
require "fluent/test/driver/input"
|
4
5
|
require "fluent/test/driver/output"
|
@@ -17,6 +18,7 @@ class Fluentd
|
|
17
18
|
include Fluentd::Setting::PluginConfig
|
18
19
|
include Fluentd::Setting::SectionParser
|
19
20
|
include Fluentd::Setting::PluginParameter
|
21
|
+
include Fluentd::Setting::Label
|
20
22
|
|
21
23
|
included do
|
22
24
|
cattr_accessor :plugin_type, :plugin_name, :config_definition
|
@@ -10,7 +10,12 @@ class Fluentd
|
|
10
10
|
def validate_configuration
|
11
11
|
original_log = $log
|
12
12
|
$log = DummyLogger.logger
|
13
|
-
|
13
|
+
full_config = to_config.to_s
|
14
|
+
config = if full_config.start_with?("<label ")
|
15
|
+
full_config.lines[2..-3].join
|
16
|
+
else
|
17
|
+
full_config.lines[1..-2].join
|
18
|
+
end
|
14
19
|
self.class.create_driver(config)
|
15
20
|
rescue Fluent::ConfigError => ex
|
16
21
|
errors.add(:base, :invalid, message: ex.message)
|
@@ -40,6 +45,10 @@ class Fluentd
|
|
40
45
|
end
|
41
46
|
_attributes = { "@type" => self.plugin_name }.merge(_attributes)
|
42
47
|
_attributes["@log_level"] = _attributes.delete("log_level")
|
48
|
+
label = _attributes.delete("label")
|
49
|
+
if plugin_type == "input"
|
50
|
+
_attributes["@label"] = label
|
51
|
+
end
|
43
52
|
argument = case plugin_type
|
44
53
|
when "output", "filter", "buffer"
|
45
54
|
_attributes.delete(self._argument_name.to_s) || ""
|
@@ -47,7 +56,18 @@ class Fluentd
|
|
47
56
|
""
|
48
57
|
end
|
49
58
|
attrs, elements = parse_attributes(_attributes)
|
50
|
-
|
59
|
+
case plugin_type
|
60
|
+
when "output", "filter"
|
61
|
+
# e is <match> or <filter>
|
62
|
+
e = config_element(name, argument, attrs, elements)
|
63
|
+
if label.blank?
|
64
|
+
e
|
65
|
+
else
|
66
|
+
config_element("label", label, {}, [e])
|
67
|
+
end
|
68
|
+
else
|
69
|
+
config_element(name, argument, attrs, elements)
|
70
|
+
end
|
51
71
|
end
|
52
72
|
|
53
73
|
def parse_attributes(attributes)
|
@@ -70,11 +90,21 @@ class Fluentd
|
|
70
90
|
}
|
71
91
|
end
|
72
92
|
end
|
73
|
-
|
93
|
+
_elements = section_params.map do |index, _section_params|
|
74
94
|
section_class.new(_section_params).to_config
|
75
95
|
end.compact
|
96
|
+
elements.concat(_elements)
|
97
|
+
end
|
98
|
+
params = params.to_h
|
99
|
+
if plugin_type == "filter" && plugin_name == "record_transformer"
|
100
|
+
record_params = {}
|
101
|
+
params.delete("record").lines.each do |line|
|
102
|
+
k, v = line.split(" ", 2)
|
103
|
+
record_params[k] = v
|
104
|
+
end
|
105
|
+
elements << config_element("record", "", record_params, [])
|
76
106
|
end
|
77
|
-
attrs = params.
|
107
|
+
attrs = params.reject do |key, value|
|
78
108
|
skip?(key.to_sym, value)
|
79
109
|
end
|
80
110
|
return attrs, elements
|
@@ -22,9 +22,17 @@ class Fluentd
|
|
22
22
|
end
|
23
23
|
elements = sections.map do |key, section_params|
|
24
24
|
if section_params.present?
|
25
|
-
self._sections[key.to_sym]
|
25
|
+
section_class = self._sections[key.to_sym]
|
26
|
+
if section_class.multi?
|
27
|
+
section_params.map do |index, _section_params|
|
28
|
+
section_class.new(_section_params).to_config
|
29
|
+
end
|
30
|
+
else
|
31
|
+
section_class.new(section_params).to_config
|
32
|
+
end
|
26
33
|
end
|
27
|
-
end
|
34
|
+
end
|
35
|
+
elements = elements.flatten.compact
|
28
36
|
attrs = params.to_h.reject do |key, value|
|
29
37
|
skip?(key.to_sym, value)
|
30
38
|
end
|
@@ -18,6 +18,8 @@
|
|
18
18
|
# - https://github.com/treasure-data/omnibus-td-agent/blob/master/templates/etc/systemd/td-agent.service.erb#L14
|
19
19
|
# fluentd: /etc/fluent/fluent.conf (created by fluentd -s)
|
20
20
|
|
21
|
+
require "strscan"
|
22
|
+
|
21
23
|
class Fluentd
|
22
24
|
class Agent
|
23
25
|
module Common
|
@@ -74,6 +76,25 @@ class Fluentd
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
def config_merge(content)
|
80
|
+
if content.start_with?("<label ")
|
81
|
+
label = content.slice(/<label\s+(.+?)>/, 1)
|
82
|
+
key = "label:#{label}"
|
83
|
+
parsed_config = parse_config(config)
|
84
|
+
if parsed_config.key?(key)
|
85
|
+
offset = parsed_config[key][0][:pos] + parsed_config[key][0][:size]
|
86
|
+
label, sections = parse_label_section(content, offset)
|
87
|
+
parsed_config[key][0][:sections]["filter"].concat(sections["filter"])
|
88
|
+
parsed_config[key][0][:sections]["match"].concat(sections["match"])
|
89
|
+
config_write(dump_parsed_config(parsed_config))
|
90
|
+
else
|
91
|
+
config_append(content)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
config_append(content)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
77
98
|
def configuration
|
78
99
|
if File.exists? config_file
|
79
100
|
::Fluentd::Agent::Configuration.new(config_file)
|
@@ -142,6 +163,82 @@ class Fluentd
|
|
142
163
|
FileUtils.rm(file) if File.exist? file
|
143
164
|
end
|
144
165
|
end
|
166
|
+
|
167
|
+
def parse_config(content)
|
168
|
+
scanner = StringScanner.new(content)
|
169
|
+
contents = Hash.new {|h, k| h[k] = [] }
|
170
|
+
until scanner.eos? do
|
171
|
+
started = scanner.pos
|
172
|
+
header = scanner.scan_until(/^<(source|filter|match|label)/)
|
173
|
+
section_type = scanner[1]
|
174
|
+
break unless header
|
175
|
+
case section_type
|
176
|
+
when "source", "filter", "match"
|
177
|
+
current_source = header + scanner.scan_until(%r{^</(?:source|filter|match)>})
|
178
|
+
contents[section_type] << { pos: started, content: current_source.strip }
|
179
|
+
when "label"
|
180
|
+
label_content = header + scanner.scan_until(%r{^</label>})
|
181
|
+
label, sections = parse_label_section(label_content, started)
|
182
|
+
contents["label:#{label}"] << { label: label, pos: started, sections: sections, size: label_content.size }
|
183
|
+
else
|
184
|
+
raise TypeError, "Unknown section: #{started}: #{section_type}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
contents
|
188
|
+
end
|
189
|
+
|
190
|
+
def parse_label_section(content, offset)
|
191
|
+
scanner = StringScanner.new(content)
|
192
|
+
scanner.scan_until(/^<label\s+?([^\s]+?)>/)
|
193
|
+
label = scanner[1]
|
194
|
+
sections = Hash.new {|h, k| h[k] = [] }
|
195
|
+
loop do
|
196
|
+
break if scanner.match?(%r{\s+?</label>})
|
197
|
+
pos = scanner.pos
|
198
|
+
header = scanner.scan_until(/^\s*<(filter|match)/)
|
199
|
+
type = scanner[1]
|
200
|
+
source = header + scanner.scan_until(%r{^\s*</(?:filter|match)>})
|
201
|
+
sections[type] << { label: label, pos: pos + offset, content: source.sub(/\n+/, "") }
|
202
|
+
end
|
203
|
+
return label, sections
|
204
|
+
end
|
205
|
+
|
206
|
+
def dump_parsed_config(parsed_config)
|
207
|
+
content = "".dup
|
208
|
+
sources = parsed_config["source"] || []
|
209
|
+
filters = parsed_config["filter"] || []
|
210
|
+
matches = parsed_config["match"] || []
|
211
|
+
labels = parsed_config.select do |key, sections|
|
212
|
+
key.start_with?("label:")
|
213
|
+
end
|
214
|
+
labels = labels.values.flatten
|
215
|
+
sorted_sections = (sources + filters + matches + labels).sort_by do |section|
|
216
|
+
section[:pos]
|
217
|
+
end
|
218
|
+
sorted_sections.each do |section|
|
219
|
+
if section.key?(:label)
|
220
|
+
label = section[:label]
|
221
|
+
sub_filters = section.dig(:sections, "filter") || []
|
222
|
+
sub_matches = section.dig(:sections, "match") || []
|
223
|
+
sorted_sub_filters = sub_filters.sort_by do |sub_section|
|
224
|
+
sub_section[:pos]
|
225
|
+
end
|
226
|
+
sorted_sub_matches = sub_matches.sort_by do |sub_section|
|
227
|
+
sub_section[:pos]
|
228
|
+
end
|
229
|
+
sub_sections = sorted_sub_filters + sorted_sub_matches
|
230
|
+
content << "<label #{label}>\n"
|
231
|
+
sub_sections.each do |sub_section|
|
232
|
+
content << sub_section[:content] << "\n\n"
|
233
|
+
end
|
234
|
+
content.chomp!
|
235
|
+
content << "</label>\n\n"
|
236
|
+
else
|
237
|
+
content << section[:content] << "\n\n"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
content.chomp
|
241
|
+
end
|
145
242
|
end
|
146
243
|
end
|
147
244
|
end
|
@@ -21,12 +21,83 @@ class Fluentd
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def filters
|
25
|
+
elements.find_all do |elm|
|
26
|
+
elm.name == "filter"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
24
30
|
def matches
|
25
31
|
elements.find_all do |elm|
|
26
32
|
elm.name == "match"
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
36
|
+
def labels
|
37
|
+
elements.find_all do |elm|
|
38
|
+
elm.name == "label"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def group_by_label
|
43
|
+
hash = Hash.new{|h, k| h[k] = {} }
|
44
|
+
sources.each do |source|
|
45
|
+
label = source["@label"] || source["label"]
|
46
|
+
if label
|
47
|
+
hash[label][:sources] = [source]
|
48
|
+
else
|
49
|
+
hash["ROOT"][:sources] = [source]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
hash["ROOT"][:filters] = filters unless filters.empty?
|
53
|
+
hash["ROOT"][:matches] = matches unless matches.empty?
|
54
|
+
|
55
|
+
labels.each do |label|
|
56
|
+
hash[label.arg][:filters] = label.elements.find_all do |e|
|
57
|
+
e.name == "filter"
|
58
|
+
end
|
59
|
+
hash[label.arg][:matches] = label.elements.find_all do |e|
|
60
|
+
e.name == "match"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
hash
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete_element(name, arg, element)
|
67
|
+
if name == "label"
|
68
|
+
label_section = fl_config.elements(name: name, arg: arg).first
|
69
|
+
original_size = label_section.elements.size
|
70
|
+
remaining_elements = label_section.elements.reject do |e|
|
71
|
+
element == e
|
72
|
+
end
|
73
|
+
if remaining_elements.empty?
|
74
|
+
remaining_elements = fl_config.elements.reject do |e|
|
75
|
+
label_section == e
|
76
|
+
end
|
77
|
+
fl_config.elements = remaining_elements
|
78
|
+
return element
|
79
|
+
else
|
80
|
+
label_section.elements = remaining_elements
|
81
|
+
if original_size == label_section.elements.size
|
82
|
+
return nil
|
83
|
+
else
|
84
|
+
return element
|
85
|
+
end
|
86
|
+
end
|
87
|
+
else
|
88
|
+
original_size = fl_config.elements.size
|
89
|
+
remaining_elements = fl_config.elements.reject do |e|
|
90
|
+
element == e
|
91
|
+
end
|
92
|
+
fl_config.elements = remaining_elements
|
93
|
+
if original_size == fl_config.elements.size
|
94
|
+
return nil
|
95
|
+
else
|
96
|
+
return element
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
30
101
|
def write_to_file
|
31
102
|
return unless Fluentd.instance
|
32
103
|
Fluentd.instance.agent.config_write formatted
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Fluentd
|
2
|
+
module Setting
|
3
|
+
class FilterGrep
|
4
|
+
include Fluentd::Setting::Plugin
|
5
|
+
|
6
|
+
register_plugin("filter", "grep")
|
7
|
+
|
8
|
+
def self.initial_params
|
9
|
+
{
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.permit_params
|
14
|
+
[
|
15
|
+
:label,
|
16
|
+
:pattern, :log_level, :@log_level,
|
17
|
+
{ and: {regexp: [:key, :pattern], exclude: [:key, :pattern]} },
|
18
|
+
{ or: {regexp: [:key, :pattern], exclude: [:key, :pattern]} }
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def common_options
|
23
|
+
[
|
24
|
+
:label,
|
25
|
+
:pattern,
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
def hidden_options
|
30
|
+
regexps = (1..20).map {|n| :"regexp#{n}"}
|
31
|
+
excludes = (1..20).map {|n| :"exclude#{n}"}
|
32
|
+
[
|
33
|
+
*regexps, *excludes, :regexp, :exclude, :and, :or
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Fluentd
|
2
|
+
module Setting
|
3
|
+
class FilterParser
|
4
|
+
include Fluentd::Setting::Plugin
|
5
|
+
|
6
|
+
register_plugin("filter", "parser")
|
7
|
+
|
8
|
+
def self.initial_params
|
9
|
+
{
|
10
|
+
parse_type: "none",
|
11
|
+
parse: {
|
12
|
+
"0" => {
|
13
|
+
"type" => "none"
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def common_options
|
20
|
+
[
|
21
|
+
:label,
|
22
|
+
:pattern,
|
23
|
+
:key_name,
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def hidden_options
|
28
|
+
[
|
29
|
+
:parse
|
30
|
+
]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Fluentd
|
2
|
+
module Setting
|
3
|
+
class FilterRecordTransformer
|
4
|
+
include Fluentd::Setting::Plugin
|
5
|
+
|
6
|
+
register_plugin("filter", "record_transformer")
|
7
|
+
|
8
|
+
attribute(:record, :string)
|
9
|
+
|
10
|
+
def self.initial_params
|
11
|
+
{
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def common_options
|
16
|
+
[
|
17
|
+
:label,
|
18
|
+
:pattern,
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def hidden_options
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Fluentd
|
2
|
+
module Setting
|
3
|
+
class FilterStdout
|
4
|
+
include Fluentd::Setting::Plugin
|
5
|
+
|
6
|
+
register_plugin("filter", "stdout")
|
7
|
+
|
8
|
+
def self.initial_params
|
9
|
+
{
|
10
|
+
format_type: "stdout",
|
11
|
+
format: {
|
12
|
+
"0" => {
|
13
|
+
"@type" => "stdout",
|
14
|
+
"output_type" => "json"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def common_options
|
21
|
+
[
|
22
|
+
:label,
|
23
|
+
:pattern,
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
def hidden_options
|
28
|
+
[
|
29
|
+
:inject
|
30
|
+
]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|