class Fluent::Plugin::WindowsEventLog2Input
Constants
- DEFAULT_STORAGE_TYPE
- FIELD_DELIMITER
- GROUP_DELIMITER
These lines copied from in_windows_eventlog plugin: github.com/fluent/fluent-plugin-windows-eventlog/blob/528290d896a885c7721f850943daa3a43a015f3d/lib/fluent/plugin/in_windows_eventlog.rb#L192-L232
- KEY_MAP
- NONE_FIELD_DELIMITER
- RECORD_DELIMITER
Public Instance Methods
bookmark_validator(bookmarkXml, channel)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 255 def bookmark_validator(bookmarkXml, channel) return false if bookmarkXml.empty? evtxml = WinevtBookmarkDocument.new parser = Nokogiri::XML::SAX::Parser.new(evtxml) parser.parse(bookmarkXml) result = evtxml.result if !result.empty? && (result[:channel].downcase == channel.downcase) && result[:is_current] true else log.warn "This stored bookmark is incomplete for using. Referring `read_existing_events` parameter to subscribe: #{bookmarkXml}, channel: #{channel}" false end end
clear_subscritpions()
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 204 def clear_subscritpions @subscriptions.keys.each do |ch| subscription = @subscriptions.delete(ch) if subscription if subscription.cancel log.debug "channel (#{ch}) subscription is cancelled." subscription.close log.debug "channel (#{ch}) subscription handles are closed forcibly." end end end @timers.keys.each do |ch| timer = @timers.delete(ch) if timer event_loop_detach(timer) log.debug "channel (#{ch}) subscription watcher is detached." end end end
configure(conf)
click to toggle source
Calls superclass method
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 76 def configure(conf) super @session = nil @chs = [] @subscriptions = {} @all_chs = Winevt::EventLog::Channel.new @all_chs.force_enumerate = false @timers = {} if @read_all_channels @all_chs.each do |ch| uch = ch.strip.downcase @chs.push([uch, @read_existing_events]) end end @read_existing_events = @read_from_head || @read_existing_events if @channels.empty? && @subscribe_configs.empty? && !@read_all_channels @chs.push(['application', @read_existing_events, nil]) else @channels.map {|ch| ch.strip.downcase }.uniq.each do |uch| @chs.push([uch, @read_existing_events, nil]) end @subscribe_configs.each do |subscribe| if subscribe.remote_server @session = Winevt::EventLog::Session.new(subscribe.remote_server, subscribe.remote_domain, subscribe.remote_username, subscribe.remote_password) log.debug("connect to remote box (server: #{subscribe.remote_server}) domain: #{subscribe.remote_domain} username: #{subscribe.remote_username})") end subscribe.channels.map {|ch| ch.strip.downcase }.uniq.each do |uch| @chs.push([uch, subscribe.read_existing_events, @session]) end end end @chs.uniq! @keynames = @keys.map {|k| k.strip }.uniq if @keynames.empty? @keynames = KEY_MAP.keys end @tag = tag @bookmarks_storage = storage_create(usage: "bookmarks") @winevt_xml = false @parser = nil if @render_as_xml @parser = parser_create @winevt_xml = @parser.respond_to?(:winevt_xml?) && @parser.winevt_xml? class << self alias_method :on_notify, :on_notify_xml end else class << self alias_method :on_notify, :on_notify_hash end end if @render_as_xml && @preserve_qualifiers_on_hash raise Fluent::ConfigError, "preserve_qualifiers_on_hash must be used with Hash object rendering(render_as_xml as false)." end if !@render_as_xml && !@preserve_qualifiers_on_hash @keynames.delete('Qualifiers') elsif @parser.respond_to?(:preserve_qualifiers?) && !@parser.preserve_qualifiers? @keynames.delete('Qualifiers') end @keynames.delete('EventData') if @parse_description locale = Winevt::EventLog::Locale.new if @description_locale && unsupported_locale?(locale, @description_locale) raise Fluent::ConfigError, "'#{@description_locale}' is not supported. Supported locales are: #{locale.each.map{|code, _desc| code}.join(" ")}" end end
escape_channel(ch)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 270 def escape_channel(ch) ch.gsub(/[^a-zA-Z0-9\s]/, '_') end
initalize()
click to toggle source
Calls superclass method
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 70 def initalize super @chs = [] @keynames = [] end
on_notify(ch, subscribe)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 274 def on_notify(ch, subscribe) # for safety. end
on_notify_hash(ch, subscribe)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 319 def on_notify_hash(ch, subscribe) es = Fluent::MultiEventStream.new begin subscribe.each do |record, message, string_inserts| record["Description"] = message record["EventData"] = string_inserts h = {} @keynames.each do |k| type = KEY_MAP[k][1] value = record[KEY_MAP[k][0]] h[k]=case type when :string value.to_s when :array value.map {|v| v.to_s} else raise "Unknown value type: #{type}" end end parse_desc(h) if @parse_description es.add(Fluent::Engine.now, h) end router.emit_stream(@tag, es) @bookmarks_storage.put(ch, subscribe.bookmark) rescue Winevt::EventLog::Query::Error => e log.warn "Invalid Hash data on #{ch}.", error: e log.warn_backtrace end end
on_notify_xml(ch, subscribe)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 278 def on_notify_xml(ch, subscribe) es = Fluent::MultiEventStream.new begin subscribe.each do |xml, message, string_inserts| @parser.parse(xml) do |time, record| # record.has_key?("EventData") for none parser checking. if @winevt_xml record["Description"] = message record["EventData"] = string_inserts h = {} @keynames.each do |k| type = KEY_MAP[k][1] value = record[KEY_MAP[k][0]] h[k]=case type when :string value.to_s when :array value.map {|v| v.to_s} else raise "Unknown value type: #{type}" end end parse_desc(h) if @parse_description es.add(Fluent::Engine.now, h) else record["Description"] = message record["EventData"] = string_inserts # for none parser es.add(Fluent::Engine.now, record) end end end router.emit_stream(@tag, es) @bookmarks_storage.put(ch, subscribe.bookmark) rescue Winevt::EventLog::Query::Error => e log.warn "Invalid XML data on #{ch}.", error: e log.warn_backtrace end end
parse_desc(record)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 356 def parse_desc(record) desc = record.delete("Description".freeze) return if desc.nil? elems = desc.split(GROUP_DELIMITER) record['DescriptionTitle'] = elems.shift previous_key = nil elems.each { |elem| parent_key = nil elem.split(RECORD_DELIMITER).each { |r| key, value = if r.index(FIELD_DELIMITER) r.split(FIELD_DELIMITER) else r.split(NONE_FIELD_DELIMITER) end key = "" if key.nil? key.chop! # remove ':' from key if value.nil? parent_key = to_key(key) else # parsed value sometimes contain unexpected "\t". So remove it. value.strip! # merge empty key values into the previous non-empty key record. if key.empty? record[previous_key] = [record[previous_key], value].flatten.reject {|e| e.nil?} elsif parent_key.nil? record[to_key(key)] = value else k = "#{parent_key}.#{to_key(key)}" record[k] = value end end # XXX: This is for empty privileges record key. # We should investigate whether an another case exists or not. previous_key = to_key(key) unless key.empty? } } end
refresh_subscriptions()
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 192 def refresh_subscriptions clear_subscritpions @chs.each do |ch, read_existing_events, session| retry_on_error(ch) do ch, subscribe = subscription(ch, read_existing_events, session) @subscriptions[ch] = subscribe end end subscribe_channels(@subscriptions) end
retry_on_error(channel, times: 15) { || ... }
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 176 def retry_on_error(channel, times: 15) try = 0 begin log.debug "Retry to subscribe for #{channel}...." if try > 1 try += 1 yield log.info "Retry to subscribe for #{channel} succeeded." if try > 1 try = 0 rescue Winevt::EventLog::Subscribe::RemoteHandlerError => e raise ReconnectError, "Retrying limit is exceeded." if try > times log.warn "#{e.message}. Remaining retry count(s): #{times - try}" sleep 2**try retry end end
shutdown()
click to toggle source
Calls superclass method
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 164 def shutdown super @subscriptions.keys.each do |ch| subscription = @subscriptions.delete(ch) if subscription subscription.cancel log.debug "channel (#{ch}) subscription is canceled." end end end
start()
click to toggle source
Calls superclass method
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 155 def start super refresh_subscriptions if @refresh_subscription_interval timer_execute(:in_windows_eventlog_refresh_subscription_timer, @refresh_subscription_interval, &method(:refresh_subscriptions)) end end
subscribe_channels(subscriptions)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 246 def subscribe_channels(subscriptions) subscriptions.each do |ch, subscribe| @timers[ch] = timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do on_notify(ch, subscribe) end log.debug "channel (#{ch}) subscription is subscribed." end end
subscription(ch, read_existing_events, remote_session)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 224 def subscription(ch, read_existing_events, remote_session) bookmarkXml = @bookmarks_storage.get(ch) || "" bookmark = nil if bookmark_validator(bookmarkXml, ch) bookmark = Winevt::EventLog::Bookmark.new(bookmarkXml) end subscribe = Winevt::EventLog::Subscribe.new subscribe.read_existing_events = read_existing_events begin subscribe.subscribe(ch, "*", bookmark, remote_session) if !@render_as_xml && @preserve_qualifiers_on_hash subscribe.preserve_qualifiers = @preserve_qualifiers_on_hash end rescue Winevt::EventLog::Query::Error => e raise Fluent::ConfigError, "Invalid Bookmark XML is loaded. #{e}" end subscribe.render_as_xml = @render_as_xml subscribe.rate_limit = @rate_limit subscribe.locale = @description_locale if @description_locale [ch, subscribe] end
to_key(key)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 395 def to_key(key) key.downcase! key.gsub!(' '.freeze, '_'.freeze) key end
unsupported_locale?(locale, description_locale)
click to toggle source
# File lib/fluent/plugin/in_windows_eventlog2.rb, line 151 def unsupported_locale?(locale, description_locale) locale.each.select {|c, _d| c.downcase == description_locale.downcase}.empty? end