fluent-plugin-windows-eventlog 0.2.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,242 @@
1
+ require 'winevt'
2
+ require 'fluent/plugin/input'
3
+ require 'fluent/plugin'
4
+
5
+ module Fluent::Plugin
6
+ class WindowsEventLog2Input < Input
7
+ Fluent::Plugin.register_input('windows_eventlog2', self)
8
+
9
+ helpers :timer, :storage, :parser
10
+
11
+ DEFAULT_STORAGE_TYPE = 'local'
12
+ KEY_MAP = {"ProviderName" => ["ProviderName", :string],
13
+ "ProviderGUID" => ["ProviderGUID", :string],
14
+ "EventID" => ["EventID", :string],
15
+ "Qualifiers" => ["Qualifiers", :string],
16
+ "Level" => ["Level", :string],
17
+ "Task" => ["Task", :string],
18
+ "Opcode" => ["Opcode", :string],
19
+ "Keywords" => ["Keywords", :string],
20
+ "TimeCreated" => ["TimeCreated", :string],
21
+ "EventRecordID" => ["EventRecordID", :string],
22
+ "ActivityID" => ["ActivityID", :string],
23
+ "RelatedActivityID" => ["RelatedActivityID", :string],
24
+ "ProcessID" => ["ProcessID", :string],
25
+ "ThreadID" => ["ThreadID", :string],
26
+ "Channel" => ["Channel", :string],
27
+ "Computer" => ["Computer", :string],
28
+ "UserID" => ["UserID", :string],
29
+ "Version" => ["Version", :string],
30
+ "Description" => ["Description", :string],
31
+ "EventData" => ["EventData", :array]}
32
+
33
+ config_param :tag, :string
34
+ config_param :read_interval, :time, default: 2
35
+ config_param :channels, :array, default: ['application']
36
+ config_param :keys, :array, default: []
37
+ config_param :read_from_head, :bool, default: false
38
+ config_param :parse_description, :bool, default: false
39
+ config_param :render_as_xml, :bool, default: true
40
+ config_param :rate_limit, :integer, default: Winevt::EventLog::Subscribe::RATE_INFINITE
41
+
42
+ config_section :storage do
43
+ config_set_default :usage, "bookmarks"
44
+ config_set_default :@type, DEFAULT_STORAGE_TYPE
45
+ config_set_default :persistent, true
46
+ end
47
+
48
+ config_section :parse do
49
+ config_set_default :@type, 'winevt_xml'
50
+ config_set_default :estimate_current_event, false
51
+ end
52
+
53
+ def initalize
54
+ super
55
+ @chs = []
56
+ @keynames = []
57
+ end
58
+
59
+ def configure(conf)
60
+ super
61
+ @chs = @channels.map {|ch| ch.strip.downcase }.uniq
62
+ @keynames = @keys.map {|k| k.strip }.uniq
63
+ if @keynames.empty?
64
+ @keynames = KEY_MAP.keys
65
+ end
66
+ @keynames.delete('Qualifiers') unless @render_as_xml
67
+ @keynames.delete('EventData') if @parse_description
68
+
69
+ @tag = tag
70
+ @tailing = @read_from_head ? false : true
71
+ @bookmarks_storage = storage_create(usage: "bookmarks")
72
+ @winevt_xml = false
73
+ if @render_as_xml
74
+ @parser = parser_create
75
+ @winevt_xml = @parser.respond_to?(:winevt_xml?) && @parser.winevt_xml?
76
+ class << self
77
+ alias_method :on_notify, :on_notify_xml
78
+ end
79
+ else
80
+ class << self
81
+ alias_method :on_notify, :on_notify_hash
82
+ end
83
+ end
84
+ end
85
+
86
+ def start
87
+ super
88
+
89
+ @chs.each do |ch|
90
+ bookmarkXml = @bookmarks_storage.get(ch) || ""
91
+ subscribe = Winevt::EventLog::Subscribe.new
92
+ bookmark = unless bookmarkXml.empty?
93
+ Winevt::EventLog::Bookmark.new(bookmarkXml)
94
+ else
95
+ nil
96
+ end
97
+ subscribe.tail = @tailing
98
+ begin
99
+ subscribe.subscribe(ch, "*", bookmark)
100
+ rescue Winevt::EventLog::Query::Error => e
101
+ raise Fluent::ConfigError, "Invalid Bookmark XML is loaded. #{e}"
102
+ end
103
+ subscribe.render_as_xml = @render_as_xml
104
+ subscribe.rate_limit = @rate_limit
105
+ timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do
106
+ on_notify(ch, subscribe)
107
+ end
108
+ end
109
+ end
110
+
111
+ def escape_channel(ch)
112
+ ch.gsub(/[^a-zA-Z0-9]/, '_')
113
+ end
114
+
115
+ def on_notify(ch, subscribe)
116
+ # for safety.
117
+ end
118
+
119
+ def on_notify_xml(ch, subscribe)
120
+ es = Fluent::MultiEventStream.new
121
+ begin
122
+ subscribe.each do |xml, message, string_inserts|
123
+ @parser.parse(xml) do |time, record|
124
+ # record.has_key?("EventData") for none parser checking.
125
+ if @winevt_xml
126
+ record["Description"] = message
127
+ record["EventData"] = string_inserts
128
+
129
+ h = {}
130
+ @keynames.each do |k|
131
+ type = KEY_MAP[k][1]
132
+ value = record[KEY_MAP[k][0]]
133
+ h[k]=case type
134
+ when :string
135
+ value.to_s
136
+ when :array
137
+ value.map {|v| v.to_s}
138
+ else
139
+ raise "Unknown value type: #{type}"
140
+ end
141
+ end
142
+ parse_desc(h) if @parse_description
143
+ es.add(Fluent::Engine.now, h)
144
+ else
145
+ record["Description"] = message
146
+ record["EventData"] = string_inserts
147
+ # for none parser
148
+ es.add(Fluent::Engine.now, record)
149
+ end
150
+ end
151
+ end
152
+ rescue Winevt::EventLog::Query::Error => e
153
+ log.warn "Invalid XML data", error: e
154
+ log.warn_backtrace
155
+ end
156
+ router.emit_stream(@tag, es)
157
+ @bookmarks_storage.put(ch, subscribe.bookmark)
158
+ end
159
+
160
+ def on_notify_hash(ch, subscribe)
161
+ es = Fluent::MultiEventStream.new
162
+ begin
163
+ subscribe.each do |record, message, string_inserts|
164
+ record["Description"] = message
165
+ record["EventData"] = string_inserts
166
+ h = {}
167
+ @keynames.each do |k|
168
+ type = KEY_MAP[k][1]
169
+ value = record[KEY_MAP[k][0]]
170
+ h[k]=case type
171
+ when :string
172
+ value.to_s
173
+ when :array
174
+ value.map {|v| v.to_s}
175
+ else
176
+ raise "Unknown value type: #{type}"
177
+ end
178
+ end
179
+ parse_desc(h) if @parse_description
180
+ es.add(Fluent::Engine.now, h)
181
+ end
182
+ rescue Winevt::EventLog::Query::Error => e
183
+ log.warn "Invalid Hash data", error: e
184
+ log.warn_backtrace
185
+ end
186
+ router.emit_stream(@tag, es)
187
+ @bookmarks_storage.put(ch, subscribe.bookmark)
188
+ end
189
+
190
+ #### These lines copied from in_windows_eventlog plugin:
191
+ #### https://github.com/fluent/fluent-plugin-windows-eventlog/blob/528290d896a885c7721f850943daa3a43a015f3d/lib/fluent/plugin/in_windows_eventlog.rb#L192-L232
192
+ GROUP_DELIMITER = "\r\n\r\n".freeze
193
+ RECORD_DELIMITER = "\r\n\t".freeze
194
+ FIELD_DELIMITER = "\t\t".freeze
195
+ NONE_FIELD_DELIMITER = "\t".freeze
196
+
197
+ def parse_desc(record)
198
+ desc = record.delete("Description".freeze)
199
+ return if desc.nil?
200
+
201
+ elems = desc.split(GROUP_DELIMITER)
202
+ record['DescriptionTitle'] = elems.shift
203
+ previous_key = nil
204
+ elems.each { |elem|
205
+ parent_key = nil
206
+ elem.split(RECORD_DELIMITER).each { |r|
207
+ key, value = if r.index(FIELD_DELIMITER)
208
+ r.split(FIELD_DELIMITER)
209
+ else
210
+ r.split(NONE_FIELD_DELIMITER)
211
+ end
212
+ key.chop! # remove ':' from key
213
+ if value.nil?
214
+ parent_key = to_key(key)
215
+ else
216
+ # parsed value sometimes contain unexpected "\t". So remove it.
217
+ value.strip!
218
+ # merge empty key values into the previous non-empty key record.
219
+ if key.empty?
220
+ record[previous_key] = [record[previous_key], value].flatten
221
+ elsif parent_key.nil?
222
+ record[to_key(key)] = value
223
+ else
224
+ k = "#{parent_key}.#{to_key(key)}"
225
+ record[k] = value
226
+ end
227
+ end
228
+ # XXX: This is for empty privileges record key.
229
+ # We should investigate whether an another case exists or not.
230
+ previous_key = to_key(key) unless key.empty?
231
+ }
232
+ }
233
+ end
234
+
235
+ def to_key(key)
236
+ key.downcase!
237
+ key.gsub!(' '.freeze, '_'.freeze)
238
+ key
239
+ end
240
+ ####
241
+ end
242
+ end
@@ -1,47 +1,47 @@
1
- require 'win32/eventlog'
2
-
3
- class EventLog
4
- def initialize
5
- @logger = Win32::EventLog.new
6
- @app_source = "fluent-plugins"
7
- end
8
-
9
- def info(event_id, message)
10
- @logger.report_event(
11
- source: @app_source,
12
- event_type: Win32::EventLog::INFO_TYPE,
13
- event_id: event_id,
14
- data: message
15
- )
16
- end
17
-
18
- def warn(event_id, message)
19
- @logger.report_event(
20
- source: @app_source,
21
- event_type: Win32::EventLog::WARN_TYPE,
22
- event_id: event_id,
23
- data: message
24
- )
25
- end
26
-
27
- def crit(event_id, message)
28
- @logger.report_event(
29
- source: @app_source,
30
- event_type: Win32::EventLog::ERROR_TYPE,
31
- event_id: event_id,
32
- data: message
33
- )
34
- end
35
-
36
- end
37
-
38
- module Fluent
39
- module Plugin
40
- class EventService
41
- def run
42
- eventlog = EventLog.new()
43
- eventlog.info(65500, "Hi, from fluentd-plugins!! at " + Time.now.strftime("%Y/%m/%d %H:%M:%S "))
44
- end
45
- end
46
- end
47
- end
1
+ require 'win32/eventlog'
2
+
3
+ class EventLog
4
+ def initialize
5
+ @logger = Win32::EventLog.new
6
+ @app_source = "fluent-plugins"
7
+ end
8
+
9
+ def info(event_id, message)
10
+ @logger.report_event(
11
+ source: @app_source,
12
+ event_type: Win32::EventLog::INFO_TYPE,
13
+ event_id: event_id,
14
+ data: message
15
+ )
16
+ end
17
+
18
+ def warn(event_id, message)
19
+ @logger.report_event(
20
+ source: @app_source,
21
+ event_type: Win32::EventLog::WARN_TYPE,
22
+ event_id: event_id,
23
+ data: message
24
+ )
25
+ end
26
+
27
+ def crit(event_id, message)
28
+ @logger.report_event(
29
+ source: @app_source,
30
+ event_type: Win32::EventLog::ERROR_TYPE,
31
+ event_id: event_id,
32
+ data: message
33
+ )
34
+ end
35
+
36
+ end
37
+
38
+ module Fluent
39
+ module Plugin
40
+ class EventService
41
+ def run
42
+ eventlog = EventLog.new()
43
+ eventlog.info(65500, "Hi, from fluentd-plugins!! at " + Time.now.strftime("%Y/%m/%d %H:%M:%S "))
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,32 +1,33 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'test/unit'
11
-
12
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
- $LOAD_PATH.unshift(File.dirname(__FILE__))
14
- require 'fluent/test'
15
- unless ENV.has_key?('VERBOSE')
16
- nulllogger = Object.new
17
- nulllogger.instance_eval {|obj|
18
- def method_missing(method, *args)
19
- # pass
20
- end
21
- }
22
- $log = nulllogger
23
- end
24
-
25
- require 'fluent/test/driver/input'
26
- require 'fluent/plugin/in_windows_eventlog'
27
-
28
- class Test::Unit::TestCase
29
- end
30
- require 'fluent/test/helpers'
31
-
32
- include Fluent::Test::Helpers
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/test/driver/input'
26
+ require 'fluent/plugin/in_windows_eventlog'
27
+ require 'fluent/plugin/in_windows_eventlog2'
28
+
29
+ class Test::Unit::TestCase
30
+ end
31
+ require 'fluent/test/helpers'
32
+
33
+ include Fluent::Test::Helpers
@@ -0,0 +1,261 @@
1
+ require 'helper'
2
+ require 'fileutils'
3
+ require 'generate-windows-event'
4
+
5
+ class WindowsEventLog2InputTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ Fluent::Test.setup
9
+ end
10
+
11
+ CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
12
+ config_element("storage", "", {
13
+ '@type' => 'local',
14
+ 'persistent' => false
15
+ })
16
+ ])
17
+
18
+ def create_driver(conf = CONFIG)
19
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::WindowsEventLog2Input).configure(conf)
20
+ end
21
+
22
+ def test_configure
23
+ d = create_driver CONFIG
24
+ assert_equal 'fluent.eventlog', d.instance.tag
25
+ assert_equal 2, d.instance.read_interval
26
+ assert_equal ['application'], d.instance.channels
27
+ assert_false d.instance.read_from_head
28
+ assert_true d.instance.render_as_xml
29
+ end
30
+
31
+ def test_parse_desc
32
+ d = create_driver
33
+ desc =<<-DESC
34
+ A user's local group membership was enumerated.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\tLogon ID:\t\t0x3185B1\r\n\r\nUser:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x50b8\r\n\tProcess Name:\t\tC:\\msys64\\usr\\bin\\make.exe
35
+ DESC
36
+ h = {"Description" => desc}
37
+ expected = {"DescriptionTitle" => "A user's local group membership was enumerated.",
38
+ "subject.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
39
+ "subject.account_name" => "Administrator",
40
+ "subject.account_domain" => "DESKTOP-FLUENTTEST",
41
+ "subject.logon_id" => "0x3185B1",
42
+ "user.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
43
+ "user.account_name" => "Administrator",
44
+ "user.account_domain" => "DESKTOP-FLUENTTEST",
45
+ "process_information.process_id" => "0x50b8",
46
+ "process_information.process_name" => "C:\\msys64\\usr\\bin\\make.exe"}
47
+ d.instance.parse_desc(h)
48
+ assert_equal(expected, h)
49
+ end
50
+
51
+ def test_parse_privileges_description
52
+ d = create_driver
53
+ desc = ["Special privileges assigned to new logon.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-ZZ\r\n\t",
54
+ "AccountName:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3E7\r\n\r\n",
55
+ "Privileges:\t\tSeAssignPrimaryTokenPrivilege\r\n\t\t\tSeTcbPrivilege\r\n\t\t\t",
56
+ "SeSecurityPrivilege\r\n\t\t\tSeTakeOwnershipPrivilege\r\n\t\t\tSeLoadDriverPrivilege\r\n\t\t\t",
57
+ "SeBackupPrivilege\r\n\t\t\tSeRestorePrivilege\r\n\t\t\tSeDebugPrivilege\r\n\t\t\t",
58
+ "SeAuditPrivilege\r\n\t\t\tSeSystemEnvironmentPrivilege\r\n\t\t\tSeImpersonatePrivilege\r\n\t\t\t",
59
+ "SeDelegateSessionUserImpersonatePrivilege"].join("")
60
+
61
+ h = {"Description" => desc}
62
+ expected = {"DescriptionTitle" => "Special privileges assigned to new logon.",
63
+ "subject.security_id" => "S-X-Y-ZZ",
64
+ "subject.accountname" => "SYSTEM",
65
+ "subject.account_domain" => "NT AUTHORITY",
66
+ "subject.logon_id" => "0x3E7",
67
+ "privileges" => ["SeAssignPrimaryTokenPrivilege",
68
+ "SeTcbPrivilege",
69
+ "SeSecurityPrivilege",
70
+ "SeTakeOwnershipPrivilege",
71
+ "SeLoadDriverPrivilege",
72
+ "SeBackupPrivilege",
73
+ "SeRestorePrivilege",
74
+ "SeDebugPrivilege",
75
+ "SeAuditPrivilege",
76
+ "SeSystemEnvironmentPrivilege",
77
+ "SeImpersonatePrivilege",
78
+ "SeDelegateSessionUserImpersonatePrivilege"]}
79
+ d.instance.parse_desc(h)
80
+ assert_equal(expected, h)
81
+ end
82
+
83
+ def test_write
84
+ d = create_driver
85
+
86
+ service = Fluent::Plugin::EventService.new
87
+
88
+ d.run(expect_emits: 1) do
89
+ service.run
90
+ end
91
+
92
+ assert(d.events.length >= 1)
93
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
94
+ record = event.last
95
+
96
+ assert_equal("Application", record["Channel"])
97
+ assert_equal("65500", record["EventID"])
98
+ assert_equal("4", record["Level"])
99
+ assert_equal("fluent-plugins", record["ProviderName"])
100
+ end
101
+
102
+ CONFIG_KEYS = config_element("ROOT", "", {
103
+ "tag" => "fluent.eventlog",
104
+ "keys" => ["EventID", "Level", "Channel", "ProviderName"]
105
+ }, [
106
+ config_element("storage", "", {
107
+ '@type' => 'local',
108
+ 'persistent' => false
109
+ })
110
+ ])
111
+ def test_write_with_keys
112
+ d = create_driver(CONFIG_KEYS)
113
+
114
+ service = Fluent::Plugin::EventService.new
115
+
116
+ d.run(expect_emits: 1) do
117
+ service.run
118
+ end
119
+
120
+ assert(d.events.length >= 1)
121
+ event = d.events.last
122
+ record = event.last
123
+
124
+ expected = {"EventID" => "65500",
125
+ "Level" => "4",
126
+ "Channel" => "Application",
127
+ "ProviderName" => "fluent-plugins"}
128
+
129
+ assert_equal(expected, record)
130
+ end
131
+
132
+ class HashRendered < self
133
+ def test_write
134
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
135
+ "render_as_xml" => false}, [
136
+ config_element("storage", "", {
137
+ '@type' => 'local',
138
+ 'persistent' => false
139
+ })
140
+ ]))
141
+
142
+ service = Fluent::Plugin::EventService.new
143
+
144
+ d.run(expect_emits: 1) do
145
+ service.run
146
+ end
147
+
148
+ assert(d.events.length >= 1)
149
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
150
+ record = event.last
151
+
152
+ assert_false(d.instance.render_as_xml)
153
+ assert_equal("Application", record["Channel"])
154
+ assert_equal("65500", record["EventID"])
155
+ assert_equal("4", record["Level"])
156
+ assert_equal("fluent-plugins", record["ProviderName"])
157
+ end
158
+ end
159
+
160
+ class PersistBookMark < self
161
+ TEST_PLUGIN_STORAGE_PATH = File.join( File.dirname(File.dirname(__FILE__)), 'tmp', 'in_windows_eventlog2', 'store' )
162
+ CONFIG2 = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
163
+ config_element("storage", "", {
164
+ '@type' => 'local',
165
+ '@id' => 'test-02',
166
+ 'path' => File.join(TEST_PLUGIN_STORAGE_PATH,
167
+ 'json', 'test-02.json'),
168
+ 'persistent' => true,
169
+ })
170
+ ])
171
+
172
+ def setup
173
+ FileUtils.rm_rf(TEST_PLUGIN_STORAGE_PATH)
174
+ FileUtils.mkdir_p(File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
175
+ FileUtils.chmod_R(0755, File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
176
+ end
177
+
178
+ def test_write
179
+ d = create_driver(CONFIG2)
180
+
181
+ assert !File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
182
+
183
+ service = Fluent::Plugin::EventService.new
184
+
185
+ d.run(expect_emits: 1) do
186
+ service.run
187
+ end
188
+
189
+ assert(d.events.length >= 1)
190
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
191
+ record = event.last
192
+
193
+ prev_id = record["EventRecordID"].to_i
194
+ assert_equal("Application", record["Channel"])
195
+ assert_equal("65500", record["EventID"])
196
+ assert_equal("4", record["Level"])
197
+ assert_equal("fluent-plugins", record["ProviderName"])
198
+
199
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
200
+
201
+ d2 = create_driver(CONFIG2)
202
+ d2.run(expect_emits: 1) do
203
+ service.run
204
+ end
205
+
206
+ assert(d2.events.length == 1) # should be tailing after previous context.
207
+ event2 = d2.events.last
208
+ record2 = event2.last
209
+
210
+ curr_id = record2["EventRecordID"].to_i
211
+ assert(curr_id > prev_id)
212
+
213
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
214
+ end
215
+
216
+ def test_start_with_invalid_bookmark
217
+ invalid_storage_contents = <<-EOS
218
+ <BookmarkList>\r\n <Bookmark Channel='Application' RecordId='20063' IsCurrent='true'/>\r\n
219
+ EOS
220
+ d = create_driver(CONFIG2)
221
+ storage = d.instance.instance_variable_get(:@bookmarks_storage)
222
+ storage.put('application', invalid_storage_contents)
223
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
224
+
225
+ d2 = create_driver(CONFIG2)
226
+ assert_raise(Fluent::ConfigError) do
227
+ d2.instance.start
228
+ end
229
+ end
230
+ end
231
+
232
+ def test_write_with_none_parser
233
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
234
+ config_element("storage", "", {
235
+ '@type' => 'local',
236
+ 'persistent' => false
237
+ }),
238
+ config_element("parse", "", {
239
+ '@type' => 'none',
240
+ }),
241
+ ]))
242
+
243
+ service = Fluent::Plugin::EventService.new
244
+
245
+ d.run(expect_emits: 1) do
246
+ service.run
247
+ end
248
+
249
+ assert(d.events.length >= 1)
250
+ event = d.events.last
251
+ record = event.last
252
+
253
+ assert do
254
+ # record should be {message: <RAW XML EventLog>}.
255
+ record["message"]
256
+ end
257
+
258
+ assert_true(record.has_key?("Description"))
259
+ assert_true(record.has_key?("EventData"))
260
+ end
261
+ end