fluent-plugin-windows-eventlog 0.2.2 → 0.4.3
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 +5 -5
- data/.gitignore +14 -14
- data/CHANGELOG.md +32 -0
- data/Gemfile +4 -4
- data/LICENSE.txt +203 -203
- data/README.md +285 -132
- data/Rakefile +10 -10
- data/appveyor.yml +24 -34
- data/fluent-plugin-winevtlog.gemspec +28 -25
- data/lib/fluent/plugin/in_windows_eventlog.rb +234 -234
- data/lib/fluent/plugin/in_windows_eventlog2.rb +242 -0
- data/test/generate-windows-event.rb +47 -47
- data/test/helper.rb +33 -32
- data/test/plugin/test_in_windows_eventlog2.rb +261 -0
- data/test/plugin/test_in_winevtlog.rb +48 -48
- metadata +50 -4
@@ -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
|
data/test/helper.rb
CHANGED
@@ -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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|