fluent-auditify 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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.env +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/LICENSE.txt +202 -0
  5. data/README.md +37 -0
  6. data/Rakefile +13 -0
  7. data/exe/fluent-auditify +8 -0
  8. data/lib/fluent/auditify/command/auditify.rb +96 -0
  9. data/lib/fluent/auditify/helper/test.rb +72 -0
  10. data/lib/fluent/auditify/log.rb +77 -0
  11. data/lib/fluent/auditify/parser/v1config.rb +172 -0
  12. data/lib/fluent/auditify/parsletutil.rb +159 -0
  13. data/lib/fluent/auditify/plugin/base.rb +17 -0
  14. data/lib/fluent/auditify/plugin/conf.rb +135 -0
  15. data/lib/fluent/auditify/plugin/conf_buffer_file.rb +18 -0
  16. data/lib/fluent/auditify/plugin/conf_buffer_file_single.rb +18 -0
  17. data/lib/fluent/auditify/plugin/conf_buffer_memory.rb +18 -0
  18. data/lib/fluent/auditify/plugin/conf_filter_grep.rb +18 -0
  19. data/lib/fluent/auditify/plugin/conf_filter_parser.rb +18 -0
  20. data/lib/fluent/auditify/plugin/conf_filter_record_transformer.rb +18 -0
  21. data/lib/fluent/auditify/plugin/conf_filter_stdout.rb +18 -0
  22. data/lib/fluent/auditify/plugin/conf_in_exec.rb +18 -0
  23. data/lib/fluent/auditify/plugin/conf_in_forward.rb +18 -0
  24. data/lib/fluent/auditify/plugin/conf_in_http.rb +18 -0
  25. data/lib/fluent/auditify/plugin/conf_in_monitor_agent.rb +18 -0
  26. data/lib/fluent/auditify/plugin/conf_in_sample.rb +18 -0
  27. data/lib/fluent/auditify/plugin/conf_in_syslog.rb +18 -0
  28. data/lib/fluent/auditify/plugin/conf_in_tail.rb +18 -0
  29. data/lib/fluent/auditify/plugin/conf_in_tcp.rb +18 -0
  30. data/lib/fluent/auditify/plugin/conf_in_udp.rb +18 -0
  31. data/lib/fluent/auditify/plugin/conf_in_unix.rb +18 -0
  32. data/lib/fluent/auditify/plugin/conf_mask_secrets.rb +83 -0
  33. data/lib/fluent/auditify/plugin/conf_out_buffer.rb +18 -0
  34. data/lib/fluent/auditify/plugin/conf_out_copy.rb +18 -0
  35. data/lib/fluent/auditify/plugin/conf_out_exec.rb +18 -0
  36. data/lib/fluent/auditify/plugin/conf_out_exec_filter.rb +18 -0
  37. data/lib/fluent/auditify/plugin/conf_out_file.rb +18 -0
  38. data/lib/fluent/auditify/plugin/conf_out_forward.rb +18 -0
  39. data/lib/fluent/auditify/plugin/conf_out_http.rb +18 -0
  40. data/lib/fluent/auditify/plugin/conf_out_null.rb +18 -0
  41. data/lib/fluent/auditify/plugin/conf_out_relabel.rb +18 -0
  42. data/lib/fluent/auditify/plugin/conf_out_rewrite_tag_filter.rb +18 -0
  43. data/lib/fluent/auditify/plugin/conf_out_roundrobin.rb +18 -0
  44. data/lib/fluent/auditify/plugin/conf_out_secondary_file.rb +18 -0
  45. data/lib/fluent/auditify/plugin/conf_out_stdout.rb +18 -0
  46. data/lib/fluent/auditify/plugin/conf_plugin_params.rb +93 -0
  47. data/lib/fluent/auditify/plugin/conf_plugin_type.rb +113 -0
  48. data/lib/fluent/auditify/plugin/conf_v1dupid.rb +46 -0
  49. data/lib/fluent/auditify/plugin.rb +65 -0
  50. data/lib/fluent/auditify/plugin_manager.rb +178 -0
  51. data/lib/fluent/auditify/registry.rb +35 -0
  52. data/lib/fluent/auditify/reporter/console.rb +70 -0
  53. data/lib/fluent/auditify/reporter/json.rb +14 -0
  54. data/lib/fluent/auditify/reporter.rb +2 -0
  55. data/lib/fluent/auditify/syntax_checker.rb +30 -0
  56. data/lib/fluent/auditify/version.rb +7 -0
  57. data/lib/fluent/auditify.rb +9 -0
  58. data/sig/fluent/auditify.rbs +6 -0
  59. metadata +172 -0
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInMonitorAgent < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_monitor_agent', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInSample < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_sample', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInSyslog < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_syslog', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInTail < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_tail', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInTcp < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_tcp', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInUdp < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_udp', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfInUnix < Conf
6
+ Fluent::Auditify::Plugin.register_conf('in_unix', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/config/v1_parser'
3
+ require 'fluent/auditify/plugin/conf'
4
+ require 'fluent/auditify/parser/v1config'
5
+ require 'fluent/auditify/parsletutil'
6
+
7
+ module Fluent::Auditify::Plugin
8
+ class MaskSecrets < Conf
9
+ Fluent::Auditify::Plugin.register_conf('mask_secrets', self)
10
+
11
+ MASK_TABLE = {
12
+ # generic
13
+ 'private_key_passphrase' =>'YOUR_PRIVATE_KEY_PASSPHRASE',
14
+ 'ca_private_key_passphrase' => 'YOUR_CA_PRIVATE_KEY_PASSPHRASE',
15
+ 'password' => 'YOUR_PASSWORD',
16
+ 'shared_key' => 'YOUR_SHARED_KEY',
17
+ # s3
18
+ 'aws_key_id' => 'YOUR_AWS_KEY_ID',
19
+ 'aws_sec_key' => 'YOUR_AWS_SEC_KEY',
20
+ 's3_bucket' => 'YOUR_S3_BUCKET',
21
+ }
22
+
23
+ def supported_platform?
24
+ :any
25
+ end
26
+
27
+ def mask_body(body)
28
+ modified_body = []
29
+ body.each do |child|
30
+ key = child[:name].to_s
31
+ if MASK_TABLE.keys.include?(key)
32
+ child[:value].instance_variable_set(:@str, MASK_TABLE[key])
33
+ modified_body << {name: child[:name],
34
+ value: child[:value]}
35
+ else
36
+ if child[:section]
37
+ # process section
38
+ modified_body << mask_section(child)
39
+ else
40
+ modified_body << child
41
+ end
42
+ end
43
+ end
44
+ modified_body
45
+ end
46
+
47
+ def mask_section(section)
48
+ {section: section[:section],
49
+ body: mask_body(section[:body]),
50
+ name: section[:name]}
51
+ end
52
+
53
+ def parse(conf, options={})
54
+ begin
55
+ content = file_get_contents(conf)
56
+ root = Fluent::Config::V1Parser.parse(content, conf)
57
+ modified = []
58
+ begin
59
+ parser = Fluent::Auditify::Parser::V1ConfigParser.new
60
+ object = parser.parse(File.read(conf))
61
+
62
+ object.each_with_index do |directive, index|
63
+ if directive[:source] or directive[:match] # input or output plugin
64
+ directive[:body] = mask_body(directive[:body])
65
+ modified << directive
66
+ else
67
+ modified << directive
68
+ end
69
+ end
70
+ polish(modified)
71
+ if options[:mask_only]
72
+ util = Fluent::Auditify::ParsletUtil.new
73
+ util.export(modified)
74
+ end
75
+ rescue => e
76
+ puts e.parse_failure_cause.ascii_tree
77
+ end
78
+ rescue => e
79
+ log.error("parse error: #{e.message}")
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutBuffer < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_buffer', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutCopy < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_copy', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutExec < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_exec', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutExecFilter < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_exec_filter', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutFile < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_file', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutForward < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_forward', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutHttp < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_http', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutNull < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_null', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutRelabel < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_relabel', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutRewriteTagFilter < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_rewrite_tag_filter', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutRoundrobin < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_roundrobin', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutSecondaryFile < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_secondary_file', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+
4
+ module Fluent::Auditify::Plugin
5
+ class ConfOutStdout < Conf
6
+ Fluent::Auditify::Plugin.register_conf('out_stdout', self)
7
+
8
+ def supported_platform?
9
+ :any
10
+ end
11
+
12
+ def initialize
13
+ end
14
+
15
+ def parse(conf, options={})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,93 @@
1
+ require 'fluent/config/error'
2
+ require 'fluent/auditify/plugin/conf'
3
+ require 'fluent/auditify/parser/v1config'
4
+ require 'fluent/config/v1_parser'
5
+ require 'yaml'
6
+ begin
7
+ require 'fluent/version'
8
+ if Gem::Version.new(Fluent::VERSION) > Gem::Version.new('1.15.0')
9
+ require 'fluent/config/yaml_parser'
10
+ end
11
+ rescue LoadError
12
+ end
13
+ require 'term/ansicolor'
14
+
15
+ module Fluent::Auditify::Plugin
16
+ class ConfPluginParams < Conf
17
+ Fluent::Auditify::Plugin.register_conf('params', self)
18
+
19
+ def supported_platform?
20
+ :any
21
+ end
22
+
23
+ def supported_file_extension?
24
+ [:conf, :yaml, :yml]
25
+ end
26
+
27
+ def initialize
28
+ super
29
+ end
30
+
31
+ def parse(conf_path, options={})
32
+ @options.merge!(options) unless options.empty?
33
+ if conf_path.end_with?('.yaml', '.yml')
34
+ else conf_path.end_with?('.conf')
35
+ process_conf(conf_path, options)
36
+ end
37
+ end
38
+
39
+ def process_conf(conf_path, options={})
40
+ content = file_get_contents(conf_path)
41
+ @parser = Fluent::Auditify::Parser::V1ConfigParser.new
42
+ object = @parser.parse(content)
43
+
44
+ root = Fluent::Config::V1Parser.parse(content, conf_path)
45
+ nth_source = 0
46
+ root.elements.collect do |element|
47
+ case element.name
48
+ when 'source'
49
+ # parse
50
+ type = 'input'
51
+ plugin_name = element['@type']
52
+ plugin_spec = plugin_defs(type, plugin_name)
53
+ element.keys.each do |param|
54
+ unless plugin_spec.key?(param)
55
+ if @options[:config_version] == :v1
56
+ next if param == '@type'
57
+ source = @parser.find_nth_element('source', nth: nth_source + 1, elements: object)
58
+ source[:body].each do |pair|
59
+ if pair[:name] == 'type' and pair[:value] == plugin_name
60
+ num = pair[:value].line_and_column.first
61
+ lines = file_get_contents(conf_path, lines: true)
62
+ guilty(:warn, "<#{param}> is deprecated, use @type instead",
63
+ {path: conf_path, line: num,
64
+ content: lines[num],
65
+ suggest: lines[num - 1][:content].sub(/type/, '@type'),
66
+ category: :params, plugin: :params})
67
+ elsif pair[:name] == param and not pair.key?(:value)
68
+ # only key (use default value)
69
+ guilty(:error, "unknown <#{param}> parameter", {path: conf_path, category: :params, plugin: :params})
70
+ end
71
+ end
72
+ next
73
+ elsif options[:config_version] == :v0
74
+ next if param == 'type'
75
+ guilty(:error, "unknown <#{param}> parameter", {path: conf_path, category: :params, plugin: :params})
76
+ next
77
+ end
78
+ end
79
+ end
80
+ # directive such as <parse>
81
+ if Gem::Version.new(Fluent::VERSION) >= Gem::Version.new('1.7.0')
82
+ # Until Fluentd < 1.7.x, spec does not contain supported section
83
+ element.elements.each do |section|
84
+ unless plugin_spec.key?(section.name)
85
+ guilty(:error, "unknown <#{section.name}> directive", {path: conf_path, category: :params, plugin: :params})
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,113 @@
1
+ require 'fluent/config/error'
2
+ begin
3
+ require 'fluent/config/yaml_parser'
4
+ rescue LoadError
5
+ end
6
+ require 'fluent/config/v1_parser'
7
+ require 'fluent/auditify/plugin/conf'
8
+ require 'fluent/auditify/parser/v1config'
9
+ require 'open3'
10
+
11
+ module Fluent::Auditify::Plugin
12
+ class ConfPluginType < Conf
13
+ Fluent::Auditify::Plugin.register_conf('type', self)
14
+
15
+ def supported_platform?
16
+ :any
17
+ end
18
+
19
+ def supported_file_extension?
20
+ [:conf, :yaml, :yml]
21
+ end
22
+
23
+ def initialize
24
+ super
25
+ end
26
+
27
+ def plugin_info
28
+ {
29
+ name: 'plugin_type',
30
+ summary: 'Detect whether wrong plugin name was specified or not',
31
+ description: 'Detect whether wrong plugin name was specified or not in each directives. Typically it can detect the case that @type forward in filter directive.'
32
+ }
33
+ end
34
+
35
+ def parse(conf_path, options={})
36
+ if yaml?(conf_path)
37
+ raise NotImplementedError
38
+ else conf?(conf_path)
39
+ process_conf(conf_path, options)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def process_conf(conf_path, options={})
46
+ content = file_get_contents(conf_path)
47
+ @parser = Fluent::Auditify::Parser::V1ConfigParser.new
48
+ object = @parser.parse(content)
49
+ root = Fluent::Config::V1Parser.parse(content, conf_path)
50
+ root.elements.each_with_index do |element, index|
51
+ case element.name
52
+ when 'source'
53
+ # parse
54
+ type = 'input'
55
+ when 'filter'
56
+ type = 'filter'
57
+ plugin_name = element['@type']
58
+ plugin_spec = plugin_defs(type, plugin_name)
59
+ if plugin_spec.empty?
60
+ input_spec = plugin_defs('input', plugin_name)
61
+ output_spec = plugin_defs('output', plugin_name)
62
+ if input_spec.empty? and output_spec.empty?
63
+ guilty(:error, "unknown <#{plugin_name}> filter plugin", {path: conf_path, category: :syntax, plugin: :type})
64
+ else
65
+ unless input_spec.empty?
66
+ guess_type = 'input'
67
+ end
68
+ unless output_spec.empty?
69
+ guess_type = 'output'
70
+ end
71
+ filter = @parser.find_nth_element('filter', nth: index + 1, elements: object)
72
+ filter[:body].each do |pair|
73
+ if pair[:name] == '@type' and pair[:value] == plugin_name
74
+ num = pair[:value].line_and_column.first
75
+ lines = file_get_contents(conf_path, lines: true)
76
+ guilty(:error, "unknown <#{plugin_name}> filter plugin. Did you mean '@type #{plugin_name}' as #{guess_type} plugin?",
77
+ {path: conf_path, line: num, content: lines[num - 1], category: :syntax, plugin: :type})
78
+ end
79
+ end
80
+ end
81
+ end
82
+ when 'match'
83
+ type = 'output'
84
+ plugin_name = element['@type']
85
+ plugin_spec = plugin_defs(type, plugin_name)
86
+ if plugin_spec.empty?
87
+ input_spec = plugin_defs('input', plugin_name)
88
+ filter_spec = plugin_defs('filter', plugin_name)
89
+ if input_spec.empty? and filter_spec.empty?
90
+ guilty(:error, "unknown <#{plugin_name}> output plugin", {path: conf_path, category: :syntax, plugin: :type})
91
+ else
92
+ unless input_spec.empty?
93
+ guess_type = 'input'
94
+ end
95
+ unless filter_spec.empty?
96
+ guess_type = 'filter'
97
+ end
98
+ output = @parser.find_nth_element('output', nth: index + 1, elements: object)
99
+ output[:body].each do |pair|
100
+ if pair[:name] == '@type' and pair[:value] == plugin_name
101
+ num = pair[:value].line_and_column.first
102
+ lines = file_get_contents(conf_path, lines: true)
103
+ guilty(:error, "unknown <#{plugin_name}> output plugin. Did you mean '@type #{plugin_name}' as #{guess_type} plugin?",
104
+ {path: conf_path, line: num, content: lines[num - 1], category: :syntax, plugin: :type})
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end