fluent-plugin-windows-eventlog 0.8.1 → 0.8.2

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.
data/Rakefile CHANGED
@@ -1,10 +1,10 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |test|
5
- test.libs << 'lib' << 'test'
6
- test.pattern = 'test/**/test_*.rb'
7
- test.verbose = true
8
- end
9
-
10
- task default: :test
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task default: :test
data/appveyor.yml CHANGED
@@ -1,24 +1,24 @@
1
- version: '{build}'
2
-
3
- # init:
4
- # - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
5
-
6
- install:
7
- - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
8
- - ruby --version
9
- - gem --version
10
- - ridk.cmd exec bundle install
11
- build: off
12
- test_script:
13
- - bundle exec rake test
14
- # - bundle exec rake test TESTOPTS=-v
15
-
16
- branches:
17
- only:
18
- - master
19
-
20
- # https://www.appveyor.com/docs/installed-software/#ruby
21
- environment:
22
- matrix:
23
- - ruby_version: "24-x64"
24
- - ruby_version: "24"
1
+ version: '{build}'
2
+
3
+ # init:
4
+ # - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
5
+
6
+ install:
7
+ - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
8
+ - ruby --version
9
+ - gem --version
10
+ - ridk.cmd exec bundle install
11
+ build: off
12
+ test_script:
13
+ - bundle exec rake test
14
+ # - bundle exec rake test TESTOPTS=-v
15
+
16
+ branches:
17
+ only:
18
+ - master
19
+
20
+ # https://www.appveyor.com/docs/installed-software/#ruby
21
+ environment:
22
+ matrix:
23
+ - ruby_version: "24-x64"
24
+ - ruby_version: "24"
@@ -1,28 +1,28 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "fluent-plugin-windows-eventlog"
7
- spec.version = "0.8.1"
8
- spec.authors = ["okahashi117", "Hiroshi Hatake", "Masahiro Nakagawa"]
9
- spec.email = ["naruki_okahashi@jbat.co.jp", "cosmo0920.oucc@gmail.com", "repeatedly@gmail.com"]
10
- spec.summary = %q{Fluentd Input plugin to read windows event log.}
11
- spec.description = %q{Fluentd Input plugin to read windows event log.}
12
- spec.homepage = "https://github.com/fluent/fluent-plugin-windows-eventlog"
13
- spec.license = "Apache-2.0"
14
-
15
- spec.files = `git ls-files -z`.split("\x0")
16
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
- spec.require_paths = ["lib"]
19
-
20
- spec.add_development_dependency "bundler"
21
- spec.add_development_dependency "rake"
22
- spec.add_development_dependency "test-unit", "~> 3.4.0"
23
- spec.add_development_dependency "nokogiri", [">= 1.10", "< 1.12"]
24
- spec.add_development_dependency "fluent-plugin-parser-winevt_xml", ">= 0.1.2"
25
- spec.add_runtime_dependency "fluentd", [">= 0.14.12", "< 2"]
26
- spec.add_runtime_dependency "win32-eventlog"
27
- spec.add_runtime_dependency "winevt_c", ">= 0.9.1"
28
- end
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fluent-plugin-windows-eventlog"
7
+ spec.version = "0.8.2"
8
+ spec.authors = ["okahashi117", "Hiroshi Hatake", "Masahiro Nakagawa"]
9
+ spec.email = ["naruki_okahashi@jbat.co.jp", "cosmo0920.oucc@gmail.com", "repeatedly@gmail.com"]
10
+ spec.summary = %q{Fluentd Input plugin to read windows event log.}
11
+ spec.description = %q{Fluentd Input plugin to read windows event log.}
12
+ spec.homepage = "https://github.com/fluent/fluent-plugin-windows-eventlog"
13
+ spec.license = "Apache-2.0"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "test-unit", "~> 3.4.0"
23
+ spec.add_development_dependency "nokogiri", [">= 1.10", "< 1.12"]
24
+ spec.add_development_dependency "fluent-plugin-parser-winevt_xml", ">= 0.1.2"
25
+ spec.add_runtime_dependency "fluentd", [">= 0.14.12", "< 2"]
26
+ spec.add_runtime_dependency "win32-eventlog"
27
+ spec.add_runtime_dependency "winevt_c", ">= 0.10.1"
28
+ end
@@ -1,30 +1,30 @@
1
- require 'nokogiri'
2
-
3
- class WinevtBookmarkDocument < Nokogiri::XML::SAX::Document
4
- attr_reader :result
5
-
6
- def initialize
7
- @result = {}
8
- super
9
- end
10
-
11
- def start_document
12
- end
13
-
14
- def start_element(name, attributes = [])
15
- if name == "Bookmark"
16
- @result[:channel] = attributes[0][1] rescue nil
17
- @result[:record_id] = attributes[1][1].to_i rescue nil
18
- @result[:is_current] = attributes[2][1].downcase == "true" rescue nil
19
- end
20
- end
21
-
22
- def characters(string)
23
- end
24
-
25
- def end_element(name, attributes = [])
26
- end
27
-
28
- def end_document
29
- end
30
- end
1
+ require 'nokogiri'
2
+
3
+ class WinevtBookmarkDocument < Nokogiri::XML::SAX::Document
4
+ attr_reader :result
5
+
6
+ def initialize
7
+ @result = {}
8
+ super
9
+ end
10
+
11
+ def start_document
12
+ end
13
+
14
+ def start_element(name, attributes = [])
15
+ if name == "Bookmark"
16
+ @result[:channel] = attributes[0][1] rescue nil
17
+ @result[:record_id] = attributes[1][1].to_i rescue nil
18
+ @result[:is_current] = attributes[2][1].downcase == "true" rescue nil
19
+ end
20
+ end
21
+
22
+ def characters(string)
23
+ end
24
+
25
+ def end_element(name, attributes = [])
26
+ end
27
+
28
+ def end_document
29
+ end
30
+ end
@@ -1,241 +1,241 @@
1
- require 'win32/eventlog'
2
- require 'fluent/plugin/input'
3
- require 'fluent/plugin'
4
-
5
- module Fluent::Plugin
6
- class WindowsEventLogInput < Input
7
- Fluent::Plugin.register_input('windows_eventlog', self)
8
-
9
- helpers :timer, :storage
10
-
11
- DEFAULT_STORAGE_TYPE = 'local'
12
- KEY_MAP = {"record_number" => [:record_number, :string],
13
- "time_generated" => [:time_generated, :string],
14
- "time_written" => [:time_written, :string],
15
- "event_id" => [:event_id, :string],
16
- "event_type" => [:event_type, :string],
17
- "event_category" => [:category, :string],
18
- "source_name" => [:source, :string],
19
- "computer_name" => [:computer, :string],
20
- "user" => [:user, :string],
21
- "description" => [:description, :string],
22
- "string_inserts" => [:string_inserts, :array]}
23
-
24
- config_param :tag, :string
25
- config_param :read_interval, :time, default: 2
26
- config_param :pos_file, :string, default: nil,
27
- obsoleted: "This section is not used anymore. Use 'store_pos' instead."
28
- config_param :channels, :array, default: ['application']
29
- config_param :keys, :array, default: []
30
- config_param :read_from_head, :bool, default: false
31
- config_param :from_encoding, :string, default: nil
32
- config_param :encoding, :string, default: nil
33
- desc "Parse 'description' field and set parsed result into event record. 'description' and 'string_inserts' fields are removed from the record"
34
- config_param :parse_description, :bool, default: false
35
-
36
- config_section :storage do
37
- config_set_default :usage, "positions"
38
- config_set_default :@type, DEFAULT_STORAGE_TYPE
39
- config_set_default :persistent, true
40
- end
41
-
42
- attr_reader :chs
43
-
44
- def initialize
45
- super
46
- @chs = []
47
- @keynames = []
48
- @tails = {}
49
- end
50
-
51
- def configure(conf)
52
- log.warn "in_windows_eventlog is deprecated. It will be removed in the future version."
53
- super
54
- @chs = @channels.map {|ch| ch.strip.downcase }.uniq
55
- if @chs.empty?
56
- raise Fluent::ConfigError, "windows_eventlog: 'channels' parameter is required on windows_eventlog input"
57
- end
58
- @keynames = @keys.map {|k| k.strip }.uniq
59
- if @keynames.empty?
60
- @keynames = KEY_MAP.keys
61
- end
62
- @keynames.delete('string_inserts') if @parse_description
63
-
64
- @tag = tag
65
- @stop = false
66
- configure_encoding
67
- @receive_handlers = if @encoding
68
- method(:encode_record)
69
- else
70
- method(:no_encode_record)
71
- end
72
- @pos_storage = storage_create(usage: "positions")
73
- end
74
-
75
- def configure_encoding
76
- unless @encoding
77
- if @from_encoding
78
- raise Fluent::ConfigError, "windows_eventlog: 'from_encoding' parameter must be specied with 'encoding' parameter."
79
- end
80
- end
81
-
82
- @encoding = parse_encoding_param(@encoding) if @encoding
83
- @from_encoding = parse_encoding_param(@from_encoding) if @from_encoding
84
- end
85
-
86
- def parse_encoding_param(encoding_name)
87
- begin
88
- Encoding.find(encoding_name) if encoding_name
89
- rescue ArgumentError => e
90
- raise Fluent::ConfigError, e.message
91
- end
92
- end
93
-
94
- def encode_record(record)
95
- if @encoding
96
- if @from_encoding
97
- record.encode!(@encoding, @from_encoding)
98
- else
99
- record.force_encoding(@encoding)
100
- end
101
- end
102
- end
103
-
104
- def no_encode_record(record)
105
- record
106
- end
107
-
108
- def start
109
- super
110
- @chs.each do |ch|
111
- start, num = @pos_storage.get(ch)
112
- if @read_from_head || (!num || num.zero?)
113
- el = Win32::EventLog.open(ch)
114
- @pos_storage.put(ch, [el.oldest_record_number - 1, 1])
115
- el.close
116
- end
117
- timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do
118
- on_notify(ch)
119
- end
120
- end
121
- end
122
-
123
- def escape_channel(ch)
124
- ch.gsub(/[^a-zA-Z0-9]/, '_')
125
- end
126
-
127
- def receive_lines(ch, lines)
128
- return if lines.empty?
129
- begin
130
- for r in lines
131
- h = {"channel" => ch}
132
- @keynames.each do |k|
133
- type = KEY_MAP[k][1]
134
- value = r.send(KEY_MAP[k][0])
135
- h[k]=case type
136
- when :string
137
- @receive_handlers.call(value.to_s)
138
- when :array
139
- value.map {|v| @receive_handlers.call(v.to_s)}
140
- else
141
- raise "Unknown value type: #{type}"
142
- end
143
- end
144
- parse_desc(h) if @parse_description
145
- #h = Hash[@keynames.map {|k| [k, r.send(KEY_MAP[k][0]).to_s]}]
146
- router.emit(@tag, Fluent::Engine.now, h)
147
- end
148
- rescue => e
149
- log.error "unexpected error", error: e
150
- log.error_backtrace
151
- end
152
- end
153
-
154
- def on_notify(ch)
155
- begin
156
- el = Win32::EventLog.open(ch)
157
- rescue => e
158
- log.error "Failed to open Windows Event log.", error: e
159
- end
160
-
161
- current_oldest_record_number = el.oldest_record_number
162
- current_total_records = el.total_records
163
-
164
- read_start, read_num = @pos_storage.get(ch)
165
-
166
- # if total_records is zero, oldest_record_number has no meaning.
167
- if current_total_records == 0
168
- return
169
- end
170
-
171
- if read_start == 0 && read_num == 0
172
- @pos_storage.put(ch, [current_oldest_record_number, current_total_records])
173
- return
174
- end
175
-
176
- current_end = current_oldest_record_number + current_total_records - 1
177
- old_end = read_start + read_num - 1
178
-
179
- if current_oldest_record_number < read_start
180
- # may be a record number rotated.
181
- current_end += 0xFFFFFFFF
182
- end
183
-
184
- if current_end < old_end
185
- # something occured.
186
- @pos_storage.put(ch, [current_oldest_record_number, current_total_records])
187
- return
188
- end
189
-
190
- winlogs = el.read(Win32::EventLog::SEEK_READ | Win32::EventLog::FORWARDS_READ, old_end + 1)
191
- receive_lines(ch, winlogs)
192
- @pos_storage.put(ch, [read_start, read_num + winlogs.size])
193
- ensure
194
- if el
195
- el.close
196
- end
197
- end
198
-
199
- GROUP_DELIMITER = "\r\n\r\n".freeze
200
- RECORD_DELIMITER = "\r\n\t".freeze
201
- FIELD_DELIMITER = "\t\t".freeze
202
- NONE_FIELD_DELIMITER = "\t".freeze
203
-
204
- def parse_desc(record)
205
- desc = record.delete('description'.freeze)
206
- return if desc.nil?
207
-
208
- elems = desc.split(GROUP_DELIMITER)
209
- record['description_title'] = elems.shift
210
- elems.each { |elem|
211
- parent_key = nil
212
- elem.split(RECORD_DELIMITER).each { |r|
213
- key, value = if r.index(FIELD_DELIMITER)
214
- r.split(FIELD_DELIMITER)
215
- else
216
- r.split(NONE_FIELD_DELIMITER)
217
- end
218
- key.chop! # remove ':' from key
219
- if value.nil?
220
- parent_key = to_key(key)
221
- else
222
- # parsed value sometimes contain unexpected "\t". So remove it.
223
- value.strip!
224
- if parent_key.nil?
225
- record[to_key(key)] = value
226
- else
227
- k = "#{parent_key}.#{to_key(key)}"
228
- record[k] = value
229
- end
230
- end
231
- }
232
- }
233
- end
234
-
235
- def to_key(key)
236
- key.downcase!
237
- key.gsub!(' '.freeze, '_'.freeze)
238
- key
239
- end
240
- end
241
- end
1
+ require 'win32/eventlog'
2
+ require 'fluent/plugin/input'
3
+ require 'fluent/plugin'
4
+
5
+ module Fluent::Plugin
6
+ class WindowsEventLogInput < Input
7
+ Fluent::Plugin.register_input('windows_eventlog', self)
8
+
9
+ helpers :timer, :storage
10
+
11
+ DEFAULT_STORAGE_TYPE = 'local'
12
+ KEY_MAP = {"record_number" => [:record_number, :string],
13
+ "time_generated" => [:time_generated, :string],
14
+ "time_written" => [:time_written, :string],
15
+ "event_id" => [:event_id, :string],
16
+ "event_type" => [:event_type, :string],
17
+ "event_category" => [:category, :string],
18
+ "source_name" => [:source, :string],
19
+ "computer_name" => [:computer, :string],
20
+ "user" => [:user, :string],
21
+ "description" => [:description, :string],
22
+ "string_inserts" => [:string_inserts, :array]}
23
+
24
+ config_param :tag, :string
25
+ config_param :read_interval, :time, default: 2
26
+ config_param :pos_file, :string, default: nil,
27
+ obsoleted: "This section is not used anymore. Use 'store_pos' instead."
28
+ config_param :channels, :array, default: ['application']
29
+ config_param :keys, :array, default: []
30
+ config_param :read_from_head, :bool, default: false
31
+ config_param :from_encoding, :string, default: nil
32
+ config_param :encoding, :string, default: nil
33
+ desc "Parse 'description' field and set parsed result into event record. 'description' and 'string_inserts' fields are removed from the record"
34
+ config_param :parse_description, :bool, default: false
35
+
36
+ config_section :storage do
37
+ config_set_default :usage, "positions"
38
+ config_set_default :@type, DEFAULT_STORAGE_TYPE
39
+ config_set_default :persistent, true
40
+ end
41
+
42
+ attr_reader :chs
43
+
44
+ def initialize
45
+ super
46
+ @chs = []
47
+ @keynames = []
48
+ @tails = {}
49
+ end
50
+
51
+ def configure(conf)
52
+ log.warn "in_windows_eventlog is deprecated. It will be removed in the future version."
53
+ super
54
+ @chs = @channels.map {|ch| ch.strip.downcase }.uniq
55
+ if @chs.empty?
56
+ raise Fluent::ConfigError, "windows_eventlog: 'channels' parameter is required on windows_eventlog input"
57
+ end
58
+ @keynames = @keys.map {|k| k.strip }.uniq
59
+ if @keynames.empty?
60
+ @keynames = KEY_MAP.keys
61
+ end
62
+ @keynames.delete('string_inserts') if @parse_description
63
+
64
+ @tag = tag
65
+ @stop = false
66
+ configure_encoding
67
+ @receive_handlers = if @encoding
68
+ method(:encode_record)
69
+ else
70
+ method(:no_encode_record)
71
+ end
72
+ @pos_storage = storage_create(usage: "positions")
73
+ end
74
+
75
+ def configure_encoding
76
+ unless @encoding
77
+ if @from_encoding
78
+ raise Fluent::ConfigError, "windows_eventlog: 'from_encoding' parameter must be specied with 'encoding' parameter."
79
+ end
80
+ end
81
+
82
+ @encoding = parse_encoding_param(@encoding) if @encoding
83
+ @from_encoding = parse_encoding_param(@from_encoding) if @from_encoding
84
+ end
85
+
86
+ def parse_encoding_param(encoding_name)
87
+ begin
88
+ Encoding.find(encoding_name) if encoding_name
89
+ rescue ArgumentError => e
90
+ raise Fluent::ConfigError, e.message
91
+ end
92
+ end
93
+
94
+ def encode_record(record)
95
+ if @encoding
96
+ if @from_encoding
97
+ record.encode!(@encoding, @from_encoding)
98
+ else
99
+ record.force_encoding(@encoding)
100
+ end
101
+ end
102
+ end
103
+
104
+ def no_encode_record(record)
105
+ record
106
+ end
107
+
108
+ def start
109
+ super
110
+ @chs.each do |ch|
111
+ start, num = @pos_storage.get(ch)
112
+ if @read_from_head || (!num || num.zero?)
113
+ el = Win32::EventLog.open(ch)
114
+ @pos_storage.put(ch, [el.oldest_record_number - 1, 1])
115
+ el.close
116
+ end
117
+ timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do
118
+ on_notify(ch)
119
+ end
120
+ end
121
+ end
122
+
123
+ def escape_channel(ch)
124
+ ch.gsub(/[^a-zA-Z0-9]/, '_')
125
+ end
126
+
127
+ def receive_lines(ch, lines)
128
+ return if lines.empty?
129
+ begin
130
+ for r in lines
131
+ h = {"channel" => ch}
132
+ @keynames.each do |k|
133
+ type = KEY_MAP[k][1]
134
+ value = r.send(KEY_MAP[k][0])
135
+ h[k]=case type
136
+ when :string
137
+ @receive_handlers.call(value.to_s)
138
+ when :array
139
+ value.map {|v| @receive_handlers.call(v.to_s)}
140
+ else
141
+ raise "Unknown value type: #{type}"
142
+ end
143
+ end
144
+ parse_desc(h) if @parse_description
145
+ #h = Hash[@keynames.map {|k| [k, r.send(KEY_MAP[k][0]).to_s]}]
146
+ router.emit(@tag, Fluent::Engine.now, h)
147
+ end
148
+ rescue => e
149
+ log.error "unexpected error", error: e
150
+ log.error_backtrace
151
+ end
152
+ end
153
+
154
+ def on_notify(ch)
155
+ begin
156
+ el = Win32::EventLog.open(ch)
157
+ rescue => e
158
+ log.error "Failed to open Windows Event log.", error: e
159
+ end
160
+
161
+ current_oldest_record_number = el.oldest_record_number
162
+ current_total_records = el.total_records
163
+
164
+ read_start, read_num = @pos_storage.get(ch)
165
+
166
+ # if total_records is zero, oldest_record_number has no meaning.
167
+ if current_total_records == 0
168
+ return
169
+ end
170
+
171
+ if read_start == 0 && read_num == 0
172
+ @pos_storage.put(ch, [current_oldest_record_number, current_total_records])
173
+ return
174
+ end
175
+
176
+ current_end = current_oldest_record_number + current_total_records - 1
177
+ old_end = read_start + read_num - 1
178
+
179
+ if current_oldest_record_number < read_start
180
+ # may be a record number rotated.
181
+ current_end += 0xFFFFFFFF
182
+ end
183
+
184
+ if current_end < old_end
185
+ # something occured.
186
+ @pos_storage.put(ch, [current_oldest_record_number, current_total_records])
187
+ return
188
+ end
189
+
190
+ winlogs = el.read(Win32::EventLog::SEEK_READ | Win32::EventLog::FORWARDS_READ, old_end + 1)
191
+ receive_lines(ch, winlogs)
192
+ @pos_storage.put(ch, [read_start, read_num + winlogs.size])
193
+ ensure
194
+ if el
195
+ el.close
196
+ end
197
+ end
198
+
199
+ GROUP_DELIMITER = "\r\n\r\n".freeze
200
+ RECORD_DELIMITER = "\r\n\t".freeze
201
+ FIELD_DELIMITER = "\t\t".freeze
202
+ NONE_FIELD_DELIMITER = "\t".freeze
203
+
204
+ def parse_desc(record)
205
+ desc = record.delete('description'.freeze)
206
+ return if desc.nil?
207
+
208
+ elems = desc.split(GROUP_DELIMITER)
209
+ record['description_title'] = elems.shift
210
+ elems.each { |elem|
211
+ parent_key = nil
212
+ elem.split(RECORD_DELIMITER).each { |r|
213
+ key, value = if r.index(FIELD_DELIMITER)
214
+ r.split(FIELD_DELIMITER)
215
+ else
216
+ r.split(NONE_FIELD_DELIMITER)
217
+ end
218
+ key.chop! # remove ':' from key
219
+ if value.nil?
220
+ parent_key = to_key(key)
221
+ else
222
+ # parsed value sometimes contain unexpected "\t". So remove it.
223
+ value.strip!
224
+ if parent_key.nil?
225
+ record[to_key(key)] = value
226
+ else
227
+ k = "#{parent_key}.#{to_key(key)}"
228
+ record[k] = value
229
+ end
230
+ end
231
+ }
232
+ }
233
+ end
234
+
235
+ def to_key(key)
236
+ key.downcase!
237
+ key.gsub!(' '.freeze, '_'.freeze)
238
+ key
239
+ end
240
+ end
241
+ end