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.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +5 -0
  3. data/Gemfile.lock +1 -1
  4. data/app/controllers/api/settings_controller.rb +46 -16
  5. data/app/controllers/concerns/setting_concern.rb +1 -1
  6. data/app/controllers/fluentd/settings/filter_grep_controller.rb +9 -0
  7. data/app/controllers/fluentd/settings/filter_parser_controller.rb +9 -0
  8. data/app/controllers/fluentd/settings/filter_record_transformer_controller.rb +14 -0
  9. data/app/controllers/fluentd/settings/filter_stdout_controller.rb +9 -0
  10. data/app/javascript/packs/filter_grep_setting.js +39 -0
  11. data/app/javascript/packs/grep_container.js +53 -0
  12. data/app/javascript/packs/grep_pattern.js +43 -0
  13. data/app/javascript/packs/owned_plugin_form.js +9 -7
  14. data/app/javascript/packs/settings.js +34 -16
  15. data/app/models/concerns/fluentd/setting/configurable.rb +1 -0
  16. data/app/models/concerns/fluentd/setting/label.rb +11 -0
  17. data/app/models/concerns/fluentd/setting/plugin.rb +2 -0
  18. data/app/models/concerns/fluentd/setting/plugin_config.rb +34 -4
  19. data/app/models/concerns/fluentd/setting/section_config.rb +10 -2
  20. data/app/models/fluentd/agent/common.rb +97 -0
  21. data/app/models/fluentd/setting/config.rb +71 -0
  22. data/app/models/fluentd/setting/filter_grep.rb +38 -0
  23. data/app/models/fluentd/setting/filter_parser.rb +34 -0
  24. data/app/models/fluentd/setting/filter_record_transformer.rb +27 -0
  25. data/app/models/fluentd/setting/filter_stdout.rb +34 -0
  26. data/app/models/fluentd/setting/in_forward.rb +1 -0
  27. data/app/models/fluentd/setting/in_http.rb +1 -1
  28. data/app/models/fluentd/setting/in_monitor_agent.rb +1 -1
  29. data/app/models/fluentd/setting/in_syslog.rb +1 -1
  30. data/app/models/fluentd/setting/out_elasticsearch.rb +1 -0
  31. data/app/models/fluentd/setting/out_forward.rb +1 -1
  32. data/app/models/fluentd/setting/out_mongo.rb +1 -0
  33. data/app/models/fluentd/setting/out_s3.rb +1 -0
  34. data/app/models/fluentd/setting/out_stdout.rb +1 -1
  35. data/app/models/fluentd/setting/out_tdlog.rb +1 -1
  36. data/app/views/api/settings/_element.json.jbuilder +3 -1
  37. data/app/views/api/settings/index.json.jbuilder +10 -2
  38. data/app/views/api/settings/show.json.jbuilder +1 -1
  39. data/app/views/fluentd/settings/filter_grep/_form.html.haml +18 -0
  40. data/app/views/fluentd/settings/filter_record_transformer/_form.html.haml +20 -0
  41. data/app/views/fluentd/settings/in_tail/_form.html.haml +1 -0
  42. data/app/views/fluentd/settings/source_and_output.html.haml +46 -14
  43. data/app/views/shared/vue/_filter_grep_setting.html.haml +19 -0
  44. data/app/views/shared/vue/_grep_container.html.haml +32 -0
  45. data/app/views/shared/vue/_grep_pattern.html.haml +24 -0
  46. data/app/views/shared/vue/_setting.html.erb +2 -2
  47. data/config/locales/translation_en.yml +39 -10
  48. data/config/locales/translation_ja.yml +39 -10
  49. data/config/routes.rb +6 -0
  50. data/lib/fluentd-ui/version.rb +1 -1
  51. data/test/factories/fluentd.rb +4 -4
  52. data/test/factories/plugins.rb +2 -2
  53. data/test/factories/user.rb +2 -2
  54. data/test/fixtures/config/label.conf +15 -0
  55. data/test/fixtures/config/multi-label.conf +40 -0
  56. data/test/fixtures/config/simple.conf +12 -0
  57. data/test/models/fluentd/agent_common_test.rb +288 -0
  58. data/test/models/fluentd/setting/config_test.rb +98 -0
  59. data/test/support/configurable_daemon_settings.rb +1 -1
  60. data/test/system/fluentd/setting/filter_grep_test.rb +96 -0
  61. data/test/system/fluentd/setting/filter_parser_test.rb +13 -0
  62. data/test/system/fluentd/setting/filter_record_transformer_test.rb +30 -0
  63. data/test/system/fluentd/setting/filter_stdout_test.rb +13 -0
  64. data/test/system/source_and_output_test.rb +168 -19
  65. data/test/test_helper.rb +4 -0
  66. metadata +98 -55
  67. data/.rspec +0 -2
@@ -35,6 +35,7 @@ class Fluentd
35
35
  self.class._sections.each do |name, klass|
36
36
  klass.init
37
37
  if klass.multi
38
+ next if attributes.nil?
38
39
  next if attributes[name].nil?
39
40
  attributes[name].each do |attr|
40
41
  next unless attr
@@ -0,0 +1,11 @@
1
+ class Fluentd
2
+ module Setting
3
+ module Label
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ config_argument(:label, :string)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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
- config = to_config.to_s.lines[1..-2].join
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
- config_element(name, argument, attrs, elements)
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
- elements = section_params.map do |index, _section_params|
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.to_h.reject do |key, value|
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].new(section_params).to_config
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.compact
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