logstash-core-event 2.2.4.snapshot1
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 +7 -0
 - data/lib/logstash-core-event.rb +1 -0
 - data/lib/logstash-core-event/logstash-core-event.rb +5 -0
 - data/lib/logstash-core-event/version.rb +8 -0
 - data/lib/logstash/event.rb +278 -0
 - data/lib/logstash/string_interpolation.rb +150 -0
 - data/lib/logstash/timestamp.rb +103 -0
 - data/lib/logstash/util/accessors.rb +123 -0
 - data/logstash-core-event.gemspec +23 -0
 - data/spec/logstash/event_spec.rb +534 -0
 - data/spec/logstash/timestamp_spec.rb +109 -0
 - data/spec/logstash/util/accessors_spec.rb +179 -0
 - metadata +59 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 55afe526e0375965caa5d655bd0d15cefb96b7de
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b5604ec9b6181049186cd4976d804a81fa147dcf
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: f008f7a9f74fbbfc0e40db9fcee97e06e73e4e4e8ea091bdc368e5f267b398859be1375a3ed5a162e992f354381211e68a6bb2e70da4e0e562f14098631299ae
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: f76d2ce6b55a825fb0578a34c53d296bde2274fa34e8ea9b7c48b70187300e5ca8f338cda511fc92ad9d13093b04f3bb5d6926b18df9b0bf9cbf1d214e2348ca
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "logstash-core-event/logstash-core-event"
         
     | 
| 
         @@ -0,0 +1,278 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "time"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "date"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "cabin"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "logstash/namespace"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "logstash/util/accessors"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "logstash/timestamp"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require "logstash/json"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require "logstash/string_interpolation"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # transcient pipeline events for normal in-flow signaling as opposed to
         
     | 
| 
      
 12 
     | 
    
         
            +
            # flow altering exceptions. for now having base classes is adequate and
         
     | 
| 
      
 13 
     | 
    
         
            +
            # in the future it might be necessary to refactor using like a BaseEvent
         
     | 
| 
      
 14 
     | 
    
         
            +
            # class to have a common interface for all pileline events to support
         
     | 
| 
      
 15 
     | 
    
         
            +
            # eventual queueing persistence for example, TBD.
         
     | 
| 
      
 16 
     | 
    
         
            +
            class LogStash::ShutdownEvent; end
         
     | 
| 
      
 17 
     | 
    
         
            +
            class LogStash::FlushEvent; end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            module LogStash
         
     | 
| 
      
 20 
     | 
    
         
            +
              FLUSH = LogStash::FlushEvent.new
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              # LogStash::SHUTDOWN is used by plugins
         
     | 
| 
      
 23 
     | 
    
         
            +
              SHUTDOWN = LogStash::ShutdownEvent.new
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            # the logstash event object.
         
     | 
| 
      
 27 
     | 
    
         
            +
            #
         
     | 
| 
      
 28 
     | 
    
         
            +
            # An event is simply a tuple of (timestamp, data).
         
     | 
| 
      
 29 
     | 
    
         
            +
            # The 'timestamp' is an ISO8601 timestamp. Data is anything - any message,
         
     | 
| 
      
 30 
     | 
    
         
            +
            # context, references, etc that are relevant to this event.
         
     | 
| 
      
 31 
     | 
    
         
            +
            #
         
     | 
| 
      
 32 
     | 
    
         
            +
            # Internally, this is represented as a hash with only two guaranteed fields.
         
     | 
| 
      
 33 
     | 
    
         
            +
            #
         
     | 
| 
      
 34 
     | 
    
         
            +
            # * "@timestamp" - an ISO8601 timestamp representing the time the event
         
     | 
| 
      
 35 
     | 
    
         
            +
            #   occurred at.
         
     | 
| 
      
 36 
     | 
    
         
            +
            # * "@version" - the version of the schema. Currently "1"
         
     | 
| 
      
 37 
     | 
    
         
            +
            #
         
     | 
| 
      
 38 
     | 
    
         
            +
            # They are prefixed with an "@" symbol to avoid clashing with your
         
     | 
| 
      
 39 
     | 
    
         
            +
            # own custom fields.
         
     | 
| 
      
 40 
     | 
    
         
            +
            #
         
     | 
| 
      
 41 
     | 
    
         
            +
            # When serialized, this is represented in JSON. For example:
         
     | 
| 
      
 42 
     | 
    
         
            +
            #
         
     | 
| 
      
 43 
     | 
    
         
            +
            #     {
         
     | 
| 
      
 44 
     | 
    
         
            +
            #       "@timestamp": "2013-02-09T20:39:26.234Z",
         
     | 
| 
      
 45 
     | 
    
         
            +
            #       "@version": "1",
         
     | 
| 
      
 46 
     | 
    
         
            +
            #       message: "hello world"
         
     | 
| 
      
 47 
     | 
    
         
            +
            #     }
         
     | 
| 
      
 48 
     | 
    
         
            +
            class LogStash::Event
         
     | 
| 
      
 49 
     | 
    
         
            +
              class DeprecatedMethod < StandardError; end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              CHAR_PLUS = "+"
         
     | 
| 
      
 52 
     | 
    
         
            +
              TIMESTAMP = "@timestamp"
         
     | 
| 
      
 53 
     | 
    
         
            +
              VERSION = "@version"
         
     | 
| 
      
 54 
     | 
    
         
            +
              VERSION_ONE = "1"
         
     | 
| 
      
 55 
     | 
    
         
            +
              TIMESTAMP_FAILURE_TAG = "_timestampparsefailure"
         
     | 
| 
      
 56 
     | 
    
         
            +
              TIMESTAMP_FAILURE_FIELD = "_@timestamp"
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              METADATA = "@metadata".freeze
         
     | 
| 
      
 59 
     | 
    
         
            +
              METADATA_BRACKETS = "[#{METADATA}]".freeze
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              # Floats outside of these upper and lower bounds are forcibly converted
         
     | 
| 
      
 62 
     | 
    
         
            +
              # to scientific notation by Float#to_s
         
     | 
| 
      
 63 
     | 
    
         
            +
              MIN_FLOAT_BEFORE_SCI_NOT = 0.0001
         
     | 
| 
      
 64 
     | 
    
         
            +
              MAX_FLOAT_BEFORE_SCI_NOT = 1000000000000000.0
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              DEFAULT_LOGGER = Cabin::Channel.get(LogStash)
         
     | 
| 
      
 67 
     | 
    
         
            +
              @@logger = DEFAULT_LOGGER
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              def initialize(data = {})
         
     | 
| 
      
 70 
     | 
    
         
            +
                @cancelled = false
         
     | 
| 
      
 71 
     | 
    
         
            +
                @data = data
         
     | 
| 
      
 72 
     | 
    
         
            +
                @accessors = LogStash::Util::Accessors.new(data)
         
     | 
| 
      
 73 
     | 
    
         
            +
                @data[VERSION] ||= VERSION_ONE
         
     | 
| 
      
 74 
     | 
    
         
            +
                ts = @data[TIMESTAMP]
         
     | 
| 
      
 75 
     | 
    
         
            +
                @data[TIMESTAMP] = ts ? init_timestamp(ts) : LogStash::Timestamp.now
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                @metadata = @data.delete(METADATA) || {}
         
     | 
| 
      
 78 
     | 
    
         
            +
                @metadata_accessors = LogStash::Util::Accessors.new(@metadata)
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              def cancel
         
     | 
| 
      
 82 
     | 
    
         
            +
                @cancelled = true
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              def uncancel
         
     | 
| 
      
 86 
     | 
    
         
            +
                @cancelled = false
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              def cancelled?
         
     | 
| 
      
 90 
     | 
    
         
            +
                @cancelled
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
              # Create a deep-ish copy of this event.
         
     | 
| 
      
 94 
     | 
    
         
            +
              def clone
         
     | 
| 
      
 95 
     | 
    
         
            +
                copy = {}
         
     | 
| 
      
 96 
     | 
    
         
            +
                @data.each do |k,v|
         
     | 
| 
      
 97 
     | 
    
         
            +
                  # TODO(sissel): Recurse if this is a hash/array?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  copy[k] = begin v.clone rescue v end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                self.class.new(copy)
         
     | 
| 
      
 102 
     | 
    
         
            +
              end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 105 
     | 
    
         
            +
                "#{timestamp.to_iso8601} #{self.sprintf("%{host} %{message}")}"
         
     | 
| 
      
 106 
     | 
    
         
            +
              end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              def timestamp
         
     | 
| 
      
 109 
     | 
    
         
            +
                @data[TIMESTAMP]
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              def timestamp=(val)
         
     | 
| 
      
 113 
     | 
    
         
            +
                @data[TIMESTAMP] = val
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
              def [](fieldref)
         
     | 
| 
      
 117 
     | 
    
         
            +
                if fieldref.start_with?(METADATA_BRACKETS)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  @metadata_accessors.get(fieldref[METADATA_BRACKETS.length .. -1])
         
     | 
| 
      
 119 
     | 
    
         
            +
                elsif fieldref == METADATA
         
     | 
| 
      
 120 
     | 
    
         
            +
                  @metadata
         
     | 
| 
      
 121 
     | 
    
         
            +
                else
         
     | 
| 
      
 122 
     | 
    
         
            +
                  @accessors.get(fieldref)
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
              end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
              def []=(fieldref, value)
         
     | 
| 
      
 127 
     | 
    
         
            +
                if fieldref == TIMESTAMP && !value.is_a?(LogStash::Timestamp)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  raise TypeError, "The field '@timestamp' must be a (LogStash::Timestamp, not a #{value.class} (#{value})"
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
                if fieldref.start_with?(METADATA_BRACKETS)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  @metadata_accessors.set(fieldref[METADATA_BRACKETS.length .. -1], value)
         
     | 
| 
      
 132 
     | 
    
         
            +
                elsif fieldref == METADATA
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @metadata = value
         
     | 
| 
      
 134 
     | 
    
         
            +
                  @metadata_accessors = LogStash::Util::Accessors.new(@metadata)
         
     | 
| 
      
 135 
     | 
    
         
            +
                else
         
     | 
| 
      
 136 
     | 
    
         
            +
                  @accessors.set(fieldref, value)
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
              end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
              def to_json(*args)
         
     | 
| 
      
 141 
     | 
    
         
            +
                # ignore arguments to respect accepted to_json method signature
         
     | 
| 
      
 142 
     | 
    
         
            +
                LogStash::Json.dump(@data)
         
     | 
| 
      
 143 
     | 
    
         
            +
              end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
              def to_hash
         
     | 
| 
      
 146 
     | 
    
         
            +
                @data
         
     | 
| 
      
 147 
     | 
    
         
            +
              end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
              def overwrite(event)
         
     | 
| 
      
 150 
     | 
    
         
            +
                # pickup new event @data and also pickup @accessors
         
     | 
| 
      
 151 
     | 
    
         
            +
                # otherwise it will be pointing on previous data
         
     | 
| 
      
 152 
     | 
    
         
            +
                @data = event.instance_variable_get(:@data)
         
     | 
| 
      
 153 
     | 
    
         
            +
                @accessors = event.instance_variable_get(:@accessors)
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                #convert timestamp if it is a String
         
     | 
| 
      
 156 
     | 
    
         
            +
                if @data[TIMESTAMP].is_a?(String)
         
     | 
| 
      
 157 
     | 
    
         
            +
                  @data[TIMESTAMP] = LogStash::Timestamp.parse_iso8601(@data[TIMESTAMP])
         
     | 
| 
      
 158 
     | 
    
         
            +
                end
         
     | 
| 
      
 159 
     | 
    
         
            +
              end
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
              def include?(fieldref)
         
     | 
| 
      
 162 
     | 
    
         
            +
                if fieldref.start_with?(METADATA_BRACKETS)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  @metadata_accessors.include?(fieldref[METADATA_BRACKETS.length .. -1])
         
     | 
| 
      
 164 
     | 
    
         
            +
                elsif fieldref == METADATA
         
     | 
| 
      
 165 
     | 
    
         
            +
                  true
         
     | 
| 
      
 166 
     | 
    
         
            +
                else
         
     | 
| 
      
 167 
     | 
    
         
            +
                  @accessors.include?(fieldref)
         
     | 
| 
      
 168 
     | 
    
         
            +
                end
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
              # Append an event to this one.
         
     | 
| 
      
 172 
     | 
    
         
            +
              def append(event)
         
     | 
| 
      
 173 
     | 
    
         
            +
                # non-destructively merge that event with ourselves.
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                # no need to reset @accessors here because merging will not disrupt any existing field paths
         
     | 
| 
      
 176 
     | 
    
         
            +
                # and if new ones are created they will be picked up.
         
     | 
| 
      
 177 
     | 
    
         
            +
                LogStash::Util.hash_merge(@data, event.to_hash)
         
     | 
| 
      
 178 
     | 
    
         
            +
              end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
              # Remove a field or field reference. Returns the value of that field when deleted
         
     | 
| 
      
 181 
     | 
    
         
            +
              def remove(fieldref)
         
     | 
| 
      
 182 
     | 
    
         
            +
                @accessors.del(fieldref)
         
     | 
| 
      
 183 
     | 
    
         
            +
              end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
              # sprintf. This could use a better method name.
         
     | 
| 
      
 186 
     | 
    
         
            +
              # The idea is to take an event and convert it to a string based on
         
     | 
| 
      
 187 
     | 
    
         
            +
              # any format values, delimited by %{foo} where 'foo' is a field or
         
     | 
| 
      
 188 
     | 
    
         
            +
              # metadata member.
         
     | 
| 
      
 189 
     | 
    
         
            +
              #
         
     | 
| 
      
 190 
     | 
    
         
            +
              # For example, if the event has type == "foo" and host == "bar"
         
     | 
| 
      
 191 
     | 
    
         
            +
              # then this string:
         
     | 
| 
      
 192 
     | 
    
         
            +
              #   "type is %{type} and source is %{host}"
         
     | 
| 
      
 193 
     | 
    
         
            +
              # will return
         
     | 
| 
      
 194 
     | 
    
         
            +
              #   "type is foo and source is bar"
         
     | 
| 
      
 195 
     | 
    
         
            +
              #
         
     | 
| 
      
 196 
     | 
    
         
            +
              # If a %{name} value is an array, then we will join by ','
         
     | 
| 
      
 197 
     | 
    
         
            +
              # If a %{name} value does not exist, then no substitution occurs.
         
     | 
| 
      
 198 
     | 
    
         
            +
              def sprintf(format)
         
     | 
| 
      
 199 
     | 
    
         
            +
                LogStash::StringInterpolation.evaluate(self, format)
         
     | 
| 
      
 200 
     | 
    
         
            +
              end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
              def tag(value)
         
     | 
| 
      
 203 
     | 
    
         
            +
                # Generalize this method for more usability
         
     | 
| 
      
 204 
     | 
    
         
            +
                self["tags"] ||= []
         
     | 
| 
      
 205 
     | 
    
         
            +
                self["tags"] << value unless self["tags"].include?(value)
         
     | 
| 
      
 206 
     | 
    
         
            +
              end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
              def to_hash_with_metadata
         
     | 
| 
      
 209 
     | 
    
         
            +
                @metadata.empty? ? to_hash : to_hash.merge(METADATA => @metadata)
         
     | 
| 
      
 210 
     | 
    
         
            +
              end
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
              def to_json_with_metadata(*args)
         
     | 
| 
      
 213 
     | 
    
         
            +
                # ignore arguments to respect accepted to_json method signature
         
     | 
| 
      
 214 
     | 
    
         
            +
                LogStash::Json.dump(to_hash_with_metadata)
         
     | 
| 
      
 215 
     | 
    
         
            +
              end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
              # this is used by logstash-devutils spec_helper.rb to monkey patch the Event field setter []=
         
     | 
| 
      
 218 
     | 
    
         
            +
              # and add systematic encoding validation on every field set in specs.
         
     | 
| 
      
 219 
     | 
    
         
            +
              # TODO: (colin) this should be moved, probably in logstash-devutils ?
         
     | 
| 
      
 220 
     | 
    
         
            +
              def self.validate_value(value)
         
     | 
| 
      
 221 
     | 
    
         
            +
                case value
         
     | 
| 
      
 222 
     | 
    
         
            +
                when String
         
     | 
| 
      
 223 
     | 
    
         
            +
                  raise("expected UTF-8 encoding for value=#{value}, encoding=#{value.encoding.inspect}") unless value.encoding == Encoding::UTF_8
         
     | 
| 
      
 224 
     | 
    
         
            +
                  raise("invalid UTF-8 encoding for value=#{value}, encoding=#{value.encoding.inspect}") unless value.valid_encoding?
         
     | 
| 
      
 225 
     | 
    
         
            +
                  value
         
     | 
| 
      
 226 
     | 
    
         
            +
                when Array
         
     | 
| 
      
 227 
     | 
    
         
            +
                  value.each{|v| validate_value(v)} # don't map, return original object
         
     | 
| 
      
 228 
     | 
    
         
            +
                  value
         
     | 
| 
      
 229 
     | 
    
         
            +
                else
         
     | 
| 
      
 230 
     | 
    
         
            +
                  value
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
              # depracated public methods
         
     | 
| 
      
 235 
     | 
    
         
            +
              # TODO: (colin) since these depracated mothods are still exposed in 2.x we should remove them in 3.0
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
              def unix_timestamp
         
     | 
| 
      
 238 
     | 
    
         
            +
                raise DeprecatedMethod
         
     | 
| 
      
 239 
     | 
    
         
            +
              end
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
              def ruby_timestamp
         
     | 
| 
      
 242 
     | 
    
         
            +
                raise DeprecatedMethod
         
     | 
| 
      
 243 
     | 
    
         
            +
              end
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
              def fields
         
     | 
| 
      
 246 
     | 
    
         
            +
                raise DeprecatedMethod
         
     | 
| 
      
 247 
     | 
    
         
            +
              end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
              # set a new logger for all Event instances
         
     | 
| 
      
 250 
     | 
    
         
            +
              # there is no point in changing it at runtime for other reasons than in tests/specs.
         
     | 
| 
      
 251 
     | 
    
         
            +
              # @param logger [Cabin::Channel] logger instance that will be used by all Event instances
         
     | 
| 
      
 252 
     | 
    
         
            +
              def self.logger=(logger)
         
     | 
| 
      
 253 
     | 
    
         
            +
                @@logger = logger
         
     | 
| 
      
 254 
     | 
    
         
            +
              end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
              private
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
              def logger
         
     | 
| 
      
 259 
     | 
    
         
            +
                @@logger
         
     | 
| 
      
 260 
     | 
    
         
            +
              end
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
              def init_timestamp(o)
         
     | 
| 
      
 263 
     | 
    
         
            +
                begin
         
     | 
| 
      
 264 
     | 
    
         
            +
                  timestamp = LogStash::Timestamp.coerce(o)
         
     | 
| 
      
 265 
     | 
    
         
            +
                  return timestamp if timestamp
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
                  logger.warn("Unrecognized #{TIMESTAMP} value, setting current time to #{TIMESTAMP}, original in #{TIMESTAMP_FAILURE_FIELD}field", :value => o.inspect)
         
     | 
| 
      
 268 
     | 
    
         
            +
                rescue LogStash::TimestampParserError => e
         
     | 
| 
      
 269 
     | 
    
         
            +
                  logger.warn("Error parsing #{TIMESTAMP} string, setting current time to #{TIMESTAMP}, original in #{TIMESTAMP_FAILURE_FIELD} field", :value => o.inspect, :exception => e.message)
         
     | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                @data["tags"] ||= []
         
     | 
| 
      
 273 
     | 
    
         
            +
                @data["tags"] << TIMESTAMP_FAILURE_TAG unless @data["tags"].include?(TIMESTAMP_FAILURE_TAG)
         
     | 
| 
      
 274 
     | 
    
         
            +
                @data[TIMESTAMP_FAILURE_FIELD] = o
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                LogStash::Timestamp.now
         
     | 
| 
      
 277 
     | 
    
         
            +
              end
         
     | 
| 
      
 278 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,150 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "thread_safe"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "forwardable"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module LogStash
         
     | 
| 
      
 6 
     | 
    
         
            +
              module StringInterpolation
         
     | 
| 
      
 7 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # Floats outside of these upper and lower bounds are forcibly converted
         
     | 
| 
      
 10 
     | 
    
         
            +
                # to scientific notation by Float#to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
                MIN_FLOAT_BEFORE_SCI_NOT = 0.0001
         
     | 
| 
      
 12 
     | 
    
         
            +
                MAX_FLOAT_BEFORE_SCI_NOT = 1000000000000000.0
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                CACHE = ThreadSafe::Cache.new
         
     | 
| 
      
 15 
     | 
    
         
            +
                TEMPLATE_TAG_REGEXP = /%\{[^}]+\}/
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def evaluate(event, template)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  if template.is_a?(Float) && (template < MIN_FLOAT_BEFORE_SCI_NOT || template >= MAX_FLOAT_BEFORE_SCI_NOT)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return ("%.15f" % template).sub(/0*$/,"")
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  template = template.to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  return template if not_cachable?(template)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  compiled = CACHE.get_or_default(template, nil) || CACHE.put(template, compile_template(template))
         
     | 
| 
      
 27 
     | 
    
         
            +
                  compiled.evaluate(event)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                # clear the global compiled templates cache
         
     | 
| 
      
 31 
     | 
    
         
            +
                def clear_cache
         
     | 
| 
      
 32 
     | 
    
         
            +
                  CACHE.clear
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                # @return [Fixnum] the compiled templates cache size
         
     | 
| 
      
 36 
     | 
    
         
            +
                def cache_size
         
     | 
| 
      
 37 
     | 
    
         
            +
                  CACHE.size
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                private
         
     | 
| 
      
 41 
     | 
    
         
            +
                def not_cachable?(template)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  template.index("%").nil?
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def compile_template(template)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  nodes = Template.new
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  position = 0
         
     | 
| 
      
 49 
     | 
    
         
            +
                  matches = template.to_enum(:scan, TEMPLATE_TAG_REGEXP).map { |m| $~ }
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  matches.each do |match|
         
     | 
| 
      
 52 
     | 
    
         
            +
                    tag = match[0][2..-2]
         
     | 
| 
      
 53 
     | 
    
         
            +
                    start = match.offset(0).first
         
     | 
| 
      
 54 
     | 
    
         
            +
                    nodes << StaticNode.new(template[position..(start-1)]) if start > 0
         
     | 
| 
      
 55 
     | 
    
         
            +
                    nodes << identify(tag)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    position = match.offset(0).last
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  if position < template.size
         
     | 
| 
      
 60 
     | 
    
         
            +
                    nodes << StaticNode.new(template[position..-1])
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  optimize(nodes)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def optimize(nodes)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  nodes.size == 1 ?  nodes.first : nodes
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                def identify(tag)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  if tag == "+%s"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    EpocNode.new
         
     | 
| 
      
 73 
     | 
    
         
            +
                  elsif tag[0, 1] == "+"
         
     | 
| 
      
 74 
     | 
    
         
            +
                    DateNode.new(tag[1..-1])
         
     | 
| 
      
 75 
     | 
    
         
            +
                  else
         
     | 
| 
      
 76 
     | 
    
         
            +
                    KeyNode.new(tag)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              class Template
         
     | 
| 
      
 82 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 83 
     | 
    
         
            +
                def_delegators :@nodes, :<<, :push, :size, :first
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @nodes = []
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def evaluate(event)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @nodes.collect { |node| node.evaluate(event) }.join
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              class EpocNode
         
     | 
| 
      
 95 
     | 
    
         
            +
                def evaluate(event)
         
     | 
| 
      
 96 
     | 
    
         
            +
                  t = event.timestamp
         
     | 
| 
      
 97 
     | 
    
         
            +
                  raise LogStash::Error, "Unable to format in string \"#{@format}\", #{LogStash::Event::TIMESTAMP} field not found" unless t
         
     | 
| 
      
 98 
     | 
    
         
            +
                  t.to_i.to_s
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
              class StaticNode
         
     | 
| 
      
 103 
     | 
    
         
            +
                def initialize(content)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  @content = content
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                def evaluate(event)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  @content
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              class KeyNode
         
     | 
| 
      
 113 
     | 
    
         
            +
                def initialize(key)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  @key = key
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                def evaluate(event)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  value = event[@key]
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  case value
         
     | 
| 
      
 121 
     | 
    
         
            +
                  when nil
         
     | 
| 
      
 122 
     | 
    
         
            +
                    "%{#{@key}}"
         
     | 
| 
      
 123 
     | 
    
         
            +
                  when Array
         
     | 
| 
      
 124 
     | 
    
         
            +
                    value.join(",")
         
     | 
| 
      
 125 
     | 
    
         
            +
                  when Hash
         
     | 
| 
      
 126 
     | 
    
         
            +
                    LogStash::Json.dump(value)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  else
         
     | 
| 
      
 128 
     | 
    
         
            +
                    value
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
              end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              class DateNode
         
     | 
| 
      
 134 
     | 
    
         
            +
                def initialize(format)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  @format = format
         
     | 
| 
      
 136 
     | 
    
         
            +
                  @formatter = org.joda.time.format.DateTimeFormat.forPattern(@format)
         
     | 
| 
      
 137 
     | 
    
         
            +
                      .withZone(org.joda.time.DateTimeZone::UTC)
         
     | 
| 
      
 138 
     | 
    
         
            +
                end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                def evaluate(event)
         
     | 
| 
      
 141 
     | 
    
         
            +
                  t = event.timestamp
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                  raise LogStash::Error, "Unable to format in string \"#{@format}\", #{LogStash::Event::TIMESTAMP} field not found" unless t
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  org.joda.time.Instant.java_class.constructor(Java::long).new_instance(
         
     | 
| 
      
 146 
     | 
    
         
            +
                    t.tv_sec * 1000 + t.tv_usec / 1000
         
     | 
| 
      
 147 
     | 
    
         
            +
                  ).to_java.toDateTime.toString(@formatter)
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
              end
         
     | 
| 
      
 150 
     | 
    
         
            +
            end
         
     |