fluent-plugin-systemd 0.3.1 → 1.0.0.rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c2cebb67ce9b89e20f0354bdbb45f7f3c8f1c817
4
- data.tar.gz: b59f85ccd7e8550cdf7835c2fa3449406e9c0769
3
+ metadata.gz: 13f78fa020542fb3c022c6d0870ecf1ec2d307ae
4
+ data.tar.gz: 5cac751f2b33bc5783bf3a721999890e9f2c51ba
5
5
  SHA512:
6
- metadata.gz: 8a115c1eb388b1263f933d1f3283c84b6dbbfc4093756842095879c7f07312c0562ccbf87093fb4defd643e17cc5219569c795a48e82f3e79200990d8b22360f
7
- data.tar.gz: ba30dc865abe28b552379c7a680f6ffff3303990d98eea0747d4bda5810a585cbb866c9410a57302e6f4e9e5385d33894c0dacaca192fec4c207f5dc2e17917c
6
+ metadata.gz: 89677dd5dbf1c6648e37ec969590392cf54a929ae15d30a64824df1b3a93f1a7ea54f71c83839f484bcc914f5ffbaf8b2b32c05320e1dc45084ea30ec48afdae
7
+ data.tar.gz: dcd1c5f2eaac7c766344bbbae29d7fc8fb10cc951cc7dfbb07982ae5946dc8eef6ec26593b8ade6bac1c8fe981b78bb5f291982b9941a6ef02a85801919893c8
data/README.md CHANGED
@@ -44,7 +44,7 @@ or
44
44
  read_from_head true
45
45
  <storage>
46
46
  @type local
47
- persistent true
47
+ persistent false
48
48
  path kube-proxy.pos
49
49
  </storage>
50
50
  <entry>
@@ -196,7 +196,7 @@ For systems with systemd installed you can run the tests against your installed
196
196
 
197
197
  Issues and pull requests are very welcome.
198
198
 
199
- If you want to make a contribution but need some help or advice feel free to message me @errm on the [Fluentd Slack](http://slack.fluentd.org/), or send me an email ed@reevoo.com.
199
+ If you want to make a contribution but need some help or advice feel free to message me @errm on the [Fluentd Slack](http://slack.fluentd.org/), or send me an email edward-robinson@cookpad.com
200
200
 
201
201
  We have adopted the [Contributor Covenant](CODE_OF_CONDUCT.md) and thus expect anyone interacting with contributors, maintainers and users of this project to abide by it.
202
202
 
@@ -216,3 +216,5 @@ Many thanks to our fantastic contributors
216
216
  * [neko-neko](https://github.com/neko-neko)
217
217
  * [Sadayuki Furuhashi](https://github.com/frsyuki)
218
218
  * [Jesus Rafael Carrillo](https://github.com/jescarri)
219
+ * [John Thomas Wile II](https://github.com/jtwile2)
220
+ * [Kazuhiro Suzuki](https://github.com/ksauzz)
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
- require "fluent/plugin/filter"
3
- require "fluent/plugin/systemd/entry_mutator"
2
+
3
+ require 'fluent/plugin/filter'
4
+ require 'fluent/plugin/systemd/entry_mutator'
4
5
 
5
6
  module Fluent
6
7
  module Plugin
7
8
  # Fluentd systemd/journal filter plugin
8
9
  class SystemdEntryFilter < Filter
9
- Fluent::Plugin.register_filter("systemd_entry", self)
10
+ Fluent::Plugin.register_filter('systemd_entry', self)
10
11
 
11
12
  config_param :field_map, :hash, default: {}
12
13
  config_param :field_map_strict, :bool, default: false
@@ -16,9 +17,7 @@ module Fluent
16
17
  def configure(conf)
17
18
  super
18
19
  @mutator = SystemdEntryMutator.new(**@config_root_section.to_h)
19
- if @mutator.field_map_strict && @mutator.field_map.empty?
20
- log.warn("`field_map_strict` set to true with empty `field_map`, expect no fields")
21
- end
20
+ @mutator.warnings.each { |warning| log.warn(warning) }
22
21
  end
23
22
 
24
23
  def filter(_tag, _time, entry)
@@ -1,33 +1,31 @@
1
1
  # frozen_string_literal: true
2
- require "systemd/journal"
3
- require "fluent/plugin/input"
4
- require "fluent/plugin/systemd/pos_writer"
5
- require "fluent/plugin/systemd/entry_mutator"
2
+
3
+ require 'systemd/journal'
4
+ require 'fluent/plugin/input'
5
+ require 'fluent/plugin/systemd/entry_mutator'
6
6
 
7
7
  module Fluent
8
8
  module Plugin
9
- class SystemdInput < Input # rubocop:disable Metrics/ClassLength
10
- Fluent::Plugin.register_input("systemd", self)
9
+ # Fluentd plugin for reading from the systemd journal
10
+ class SystemdInput < Input
11
+ Fluent::Plugin.register_input('systemd', self)
11
12
 
12
13
  helpers :timer, :storage
13
14
 
14
- DEFAULT_STORAGE_TYPE = "local"
15
+ DEFAULT_STORAGE_TYPE = 'local'
15
16
 
16
- config_param :path, :string, default: "/var/log/journal"
17
+ config_param :path, :string, default: '/var/log/journal'
17
18
  config_param :filters, :array, default: []
18
- config_param :pos_file, :string, default: nil, deprecated: "Use <storage> section with `persistent: true' instead"
19
19
  config_param :read_from_head, :bool, default: false
20
- config_param :strip_underscores, :bool, default: false, deprecated: "Use <entry> section or `systemd_entry` " \
21
- "filter plugin instead"
22
20
  config_param :tag, :string
23
21
 
24
22
  config_section :storage do
25
- config_set_default :usage, "positions"
23
+ config_set_default :usage, 'positions'
26
24
  config_set_default :@type, DEFAULT_STORAGE_TYPE
27
25
  config_set_default :persistent, false
28
26
  end
29
27
 
30
- config_section :entry, param_name: "entry_opts", required: false, multi: false do
28
+ config_section :entry, param_name: 'entry_opts', required: false, multi: false do
31
29
  config_param :field_map, :hash, default: {}
32
30
  config_param :field_map_strict, :bool, default: false
33
31
  config_param :fields_strip_underscores, :bool, default: false
@@ -37,27 +35,16 @@ module Fluent
37
35
  def configure(conf)
38
36
  super
39
37
  @journal = nil
40
- @pos_storage = PosWriter.new(@pos_file, storage_create(usage: "positions"))
41
- # legacy strip_underscores backwards compatibility (legacy takes
42
- # precedence and is mutually exclusive with the entry block)
43
- mut_opts = @strip_underscores ? { fields_strip_underscores: true } : @entry_opts.to_h
44
- @mutator = SystemdEntryMutator.new(**mut_opts)
45
- if @mutator.field_map_strict && @mutator.field_map.empty?
46
- log.warn("`field_map_strict` set to true with empty `field_map`, expect no fields")
47
- end
38
+ @pos_storage = storage_create(usage: 'positions')
39
+ @mutator = SystemdEntryMutator.new(**@entry_opts.to_h)
40
+ @mutator.warnings.each { |warning| log.warn(warning) }
48
41
  end
49
42
 
50
43
  def start
51
44
  super
52
- @pos_storage.start
53
45
  timer_execute(:in_systemd_emit_worker, 1, &method(:run))
54
46
  end
55
47
 
56
- def shutdown
57
- @pos_storage.shutdown
58
- super
59
- end
60
-
61
48
  private
62
49
 
63
50
  def init_journal
@@ -80,8 +67,8 @@ module Fluent
80
67
  seek_to(cursor || read_from)
81
68
  rescue Systemd::JournalError
82
69
  log.warn(
83
- "Could not seek to cursor #{cursor} found in pos file: #{@pos_storage.path}, " \
84
- "falling back to reading from #{read_from}",
70
+ "Could not seek to cursor #{cursor} found in position file: #{@pos_storage.path}, " \
71
+ "falling back to reading from #{read_from}"
85
72
  )
86
73
  seek_to(read_from)
87
74
  end
@@ -120,7 +107,7 @@ module Fluent
120
107
  retries += 1
121
108
  sleep 1.5**retries + rand(0..3)
122
109
  retry
123
- rescue => e
110
+ rescue => e # rubocop:disable Style/RescueStandardError
124
111
  log.error("Exception emitting record: #{e}")
125
112
  end
126
113
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
- require "fluent/config/error"
2
+
3
+ require 'fluent/config/error'
3
4
 
4
5
  module Fluent
5
6
  module Plugin
@@ -19,12 +20,11 @@ module Fluent
19
20
  # "<new_field2>" => ["<source_field2>"]
20
21
  # }
21
22
  class SystemdEntryMutator
22
-
23
23
  Options = Struct.new(
24
24
  :field_map,
25
25
  :field_map_strict,
26
26
  :fields_lowercase,
27
- :fields_strip_underscores,
27
+ :fields_strip_underscores
28
28
  )
29
29
 
30
30
  def self.default_opts
@@ -56,6 +56,10 @@ module Fluent
56
56
  super
57
57
  end
58
58
 
59
+ def respond_to_missing?(sym, include_private = false)
60
+ @opts.members.include?(sym) || super
61
+ end
62
+
59
63
  # The main run method that performs all configured mutations, if any,
60
64
  # against a single journal entry. Returns the mutated entry hash.
61
65
  # entry - hash or `Systemd::Journal:Entry`
@@ -69,13 +73,11 @@ module Fluent
69
73
  # entry hash.
70
74
  # entry - hash or `Systemd::Journal:Entry`
71
75
  def map_fields(entry)
72
- mapped = {}
73
- @map.each do |cstm, sysds|
76
+ @map.each_with_object({}) do |(cstm, sysds), mapped|
74
77
  vals = sysds.collect { |fld| entry[fld] }.compact
75
78
  next if vals.empty? # systemd field does not exist in source entry
76
- mapped[cstm] = vals.length == 1 ? vals[0] : vals.join(" ")
79
+ mapped[cstm] = join_if_needed(vals)
77
80
  end
78
- mapped
79
81
  end
80
82
 
81
83
  # Run field formatting (mutations applied to all non-mapped fields)
@@ -84,20 +86,34 @@ module Fluent
84
86
  # mapped - Optional hash that represents a previously mapped entry to
85
87
  # which the formatted fields will be added
86
88
  def format_fields(entry, mapped = nil)
87
- mapped ||= {}
88
- entry.each do |fld, val|
89
+ entry.each_with_object(mapped || {}) do |(fld, val), formatted_entry|
89
90
  # don't mess with explicitly mapped fields
90
91
  next if @map_src_fields.include?(fld)
91
- fld = fld.gsub(/\A_+/, "") if @opts.fields_strip_underscores
92
- fld = fld.downcase if @opts.fields_lowercase
92
+ fld = format_field_name(fld)
93
93
  # account for mapping (appending) to an existing systemd field
94
- mapped[fld] = mapped.key?(fld) ? [val, mapped[fld]].join(" ") : val
94
+ formatted_entry[fld] = join_if_needed([val, mapped[fld]])
95
95
  end
96
- mapped
96
+ end
97
+
98
+ def warnings
99
+ return [] unless field_map_strict && field_map.empty?
100
+ '`field_map_strict` set to true with empty `field_map`, expect no fields'
97
101
  end
98
102
 
99
103
  private
100
104
 
105
+ def join_if_needed(values)
106
+ values.compact!
107
+ return values.first if values.length == 1
108
+ values.join(' ')
109
+ end
110
+
111
+ def format_field_name(name)
112
+ name = name.gsub(/\A_+/, '') if @opts.fields_strip_underscores
113
+ name = name.downcase if @opts.fields_lowercase
114
+ name
115
+ end
116
+
101
117
  # Returns a `SystemdEntryMutator::Options` struct derived from the
102
118
  # elements in the supplied hash merged with the option defaults
103
119
  def options_from_hash(opts)
@@ -109,39 +125,32 @@ module Fluent
109
125
  end
110
126
 
111
127
  def validate_options(opts)
112
- unless validate_strings_or_empty(opts[:field_map].keys)
113
- err = "`field_map` keys must be strings"
114
- end
115
- unless validate_strings_or_empty(opts[:field_map].values, true)
116
- err = "`field_map` values must be strings or array of strings"
117
- end
128
+ validate_all_strings opts[:field_map].keys, '`field_map` keys must be strings'
129
+ validate_all_strings opts[:field_map].values, '`field_map` values must be strings or an array of strings', true
118
130
  %i[field_map_strict fields_strip_underscores fields_lowercase].each do |opt|
119
- err = "`#{opt}` must be boolean" unless [true, false].include?(opts[opt])
131
+ validate_boolean opts[opt], opt
120
132
  end
121
- fail Fluent::ConfigError, err unless err.nil?
122
133
  end
123
134
 
124
- # Validates that values in array `arr` are strings. If `nested` is true
125
- # also allow and validate that `arr` values can be an array of strings
126
- def validate_strings_or_empty(arr, nested = false)
127
- return true if arr.empty?
128
- arr.each do |v|
129
- return true if v.is_a?(String)
130
- if v.is_a?(Array) && nested
131
- v.each { |nstd| return false unless nstd.is_a?(String) }
132
- end
135
+ def validate_all_strings(arr, message, allow_nesting = false)
136
+ valid = arr.all? do |value|
137
+ value.is_a?(String) || allow_nesting && value.is_a?(Array) && value.all? { |key| key.is_a?(String) }
133
138
  end
134
- false
139
+ raise Fluent::ConfigError, message unless valid
140
+ end
141
+
142
+ def validate_boolean(value, name)
143
+ raise Fluent::ConfigError, "`#{name}` must be boolean" unless [true, false].include?(value)
135
144
  end
136
145
 
137
- # Compute the inverse of a human friendly field map `fm` which is what
146
+ # Compute the inverse of a human friendly field map `field_map` which is what
138
147
  # the mutator uses for the actual mapping. The resulting structure for
139
148
  # the inverse field map hash is:
140
149
  # {"<new_field_name>" => ["<source_field_name>", ...], ...}
141
- def invert_field_map(fm)
150
+ def invert_field_map(field_map)
142
151
  invs = {}
143
- fm.values.flatten.uniq.each do |cstm|
144
- sysds = fm.select { |_, v| (v == cstm || v.include?(cstm)) }
152
+ field_map.values.flatten.uniq.each do |cstm|
153
+ sysds = field_map.select { |_, v| (v == cstm || v.include?(cstm)) }
145
154
  invs[cstm] = sysds.keys
146
155
  end
147
156
  invs
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-systemd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ed Robinson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-03 00:00:00.000000000 Z
11
+ date: 2018-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,19 +53,19 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.5'
55
55
  - !ruby/object:Gem::Dependency
56
- name: reevoocop
56
+ name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 0.53.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 0.53.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: fluentd
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -102,7 +102,7 @@ dependencies:
102
102
  version: '1.3'
103
103
  description: This is a fluentd input plugin. It reads logs from the systemd journal.
104
104
  email:
105
- - ed@reevoo.com
105
+ - edward-robinson@cookpad.com
106
106
  executables: []
107
107
  extensions: []
108
108
  extra_rdoc_files: []
@@ -112,7 +112,6 @@ files:
112
112
  - lib/fluent/plugin/filter_systemd_entry.rb
113
113
  - lib/fluent/plugin/in_systemd.rb
114
114
  - lib/fluent/plugin/systemd/entry_mutator.rb
115
- - lib/fluent/plugin/systemd/pos_writer.rb
116
115
  homepage: https://github.com/reevoo/fluent-plugin-systemd
117
116
  licenses:
118
117
  - MIT
@@ -128,12 +127,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
127
  version: '0'
129
128
  required_rubygems_version: !ruby/object:Gem::Requirement
130
129
  requirements:
131
- - - ">="
130
+ - - ">"
132
131
  - !ruby/object:Gem::Version
133
- version: '0'
132
+ version: 1.3.1
134
133
  requirements: []
135
134
  rubyforge_project:
136
- rubygems_version: 2.6.11
135
+ rubygems_version: 2.6.13
137
136
  signing_key:
138
137
  specification_version: 4
139
138
  summary: Input plugin to read from systemd journal.
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
- require "fluent/plugin/input"
3
-
4
- module Fluent
5
- module Plugin
6
- class SystemdInput < Input
7
- class PosWriter
8
- def initialize(pos_file, storage)
9
- @path = pos_file
10
- @lock = Mutex.new
11
- @storage = storage
12
- @cursor = nil
13
- @written_cursor = nil
14
- setup
15
- end
16
-
17
- def get(key)
18
- @storage ? @storage.get(key) : @cursor
19
- end
20
-
21
- def put(key, cursor)
22
- return @storage.put(key, cursor) if @storage
23
- @lock.synchronize { @cursor = cursor }
24
- end
25
-
26
- def path
27
- @path || @storage.path
28
- end
29
-
30
- def start
31
- return unless @path
32
- @running = true
33
- @thread = Thread.new(&method(:work))
34
- end
35
-
36
- def shutdown
37
- return unless @path
38
- @running = false
39
- @thread.join
40
- write_pos
41
- end
42
-
43
- private
44
-
45
- def setup
46
- if @storage.persistent
47
- migrate_to_storage if @path && File.exist?(@path)
48
- elsif @path
49
- @cursor = IO.read(@path).chomp if File.exist?(@path)
50
- @storage = nil
51
- end
52
- end
53
-
54
- def migrate_to_storage
55
- @storage.put(:journal, IO.read(@path).chomp)
56
- File.delete(@path)
57
- @path = nil
58
- end
59
-
60
- def work
61
- while @running
62
- write_pos
63
- sleep 1
64
- end
65
- end
66
-
67
- def write_pos
68
- @lock.synchronize do
69
- if @written_cursor != @cursor
70
- file = File.open(@path, "w+", 0o644)
71
- file.print @cursor
72
- file.close
73
- @written_cursor = @cursor
74
- end
75
- end
76
- end
77
- end
78
- end
79
- end
80
- end