# { # "stamp": { # "utc?": false, # "field": "timestamp", # "pattern": [ "YYYY-MM-dd HH:mm:ss.SSS" ], # "target": "@timestamp" # } # } require 'date' require 'time' module Anschel class Filter def stamp conf, stats, log utc = conf.delete :utc? field = conf.delete :field pattern = conf.delete :pattern target = conf.delete :target precision = conf.delete(:precision) || 3 error_tag = conf.has_key?(:error_tag) ? conf[:error_tag] : 'stamp-error' raise 'Missing required "field" for "stamp" filter' if field.nil? raise 'Missing required "pattern" for "stamp" filter' if pattern.nil? patterns = pattern.is_a?(Array) ? pattern : [ pattern ] target ||= '@timestamp' field = field.to_sym target = target.to_sym parsers = patterns.map do |p| joda = org.joda.time.format.DateTimeFormat.forPattern p joda = joda.withDefaultYear Time.new.year joda = joda.withOffsetParsed end offset_s = utc ? Time.zone_offset(Time.now.zone).to_f : 0.0 stats.create 'filter-stamp' stats.create 'filter-stamp-skipped' stats.create 'filter-stamp-error' log.info event: 'filter-compiled', kind: 'stamp', \ utc?: utc, field: field, pattern: pattern, target: target lambda do |event| unless event[field] stats.inc 'filter-stamp-skipped' return event end if event[target] log.warn \ event: 'stamp-filter-warning', reason: 'event already has target field', utc?: utc, field: field, pattern: pattern, target: target, raw_event: event event[target] = \ DateTime.parse(event[target]).to_time.utc.iso8601(precision) return event end event_field = event[field].dup matched = false parsers.each do |joda| begin millis = joda.parseMillis event[field] event[target] = Time.at(0.001 * millis + offset_s).utc.iso8601(precision) stats.inc 'filter-stamp' matched = true rescue end break if matched end return filtered(event, conf) if matched log.warn \ event: 'stamp-filter-warning', reason: 'could not parse event', remediation: 'using current time for stamp', utc?: utc, field: field, pattern: pattern, target: target, raw_event: event if error_tag event[:tags] ||= [] event[:tags] << error_tag end event[target] = Time.now.utc.iso8601(precision) stats.inc 'filter-stamp-error' filtered event, conf end end end end