logstash-event 1.1.5
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.
- data/LICENSE +14 -0
- data/lib/logstash-event.rb +3 -0
- data/lib/logstash/event.rb +283 -0
- data/lib/logstash/namespace.rb +14 -0
- data/lib/logstash/time.rb +32 -0
- data/lib/logstash/version.rb +5 -0
- metadata +52 -0
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright 2009-2011 Jordan Sissel, Pete Fritchman, and contributors.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
14
|
+
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require "json"
|
2
|
+
require "logstash/time"
|
3
|
+
require "logstash/namespace"
|
4
|
+
require "uri"
|
5
|
+
require "time"
|
6
|
+
|
7
|
+
# General event type.
|
8
|
+
# Basically a light wrapper on top of a hash.
|
9
|
+
#
|
10
|
+
# TODO(sissel): properly handle lazy properties like parsed time formats, urls,
|
11
|
+
# etc, as necessary.
|
12
|
+
class LogStash::Event
|
13
|
+
public
|
14
|
+
def initialize(data=nil)
|
15
|
+
@cancelled = false
|
16
|
+
|
17
|
+
@data = {
|
18
|
+
"@source" => "unknown",
|
19
|
+
"@tags" => [],
|
20
|
+
"@fields" => {},
|
21
|
+
}
|
22
|
+
@data.merge!(data) unless data.nil?
|
23
|
+
@data["@timestamp"] ||= LogStash::Time.now
|
24
|
+
end # def initialize
|
25
|
+
|
26
|
+
if RUBY_ENGINE == "jruby"
|
27
|
+
@@date_parser = Java::org.joda.time.format.ISODateTimeFormat.dateTimeParser.withOffsetParsed
|
28
|
+
else
|
29
|
+
# TODO(sissel): LOGSTASH-217
|
30
|
+
@@date_parser ||= nil
|
31
|
+
end
|
32
|
+
|
33
|
+
public
|
34
|
+
def self.from_json(json)
|
35
|
+
return LogStash::Event.new(JSON.parse(json))
|
36
|
+
end # def self.from_json
|
37
|
+
|
38
|
+
public
|
39
|
+
def cancel
|
40
|
+
@cancelled = true
|
41
|
+
end # def cancel
|
42
|
+
|
43
|
+
public
|
44
|
+
def cancelled?
|
45
|
+
return @cancelled
|
46
|
+
end # def cancelled?
|
47
|
+
|
48
|
+
# Create a deep-ish copy of this event.
|
49
|
+
public
|
50
|
+
def clone
|
51
|
+
newdata = @data.clone
|
52
|
+
newdata["@fields"] = {}
|
53
|
+
fields.each do |k,v|
|
54
|
+
newdata["@fields"][k] = v.clone
|
55
|
+
end
|
56
|
+
return LogStash::Event.new(newdata)
|
57
|
+
end # def clone
|
58
|
+
|
59
|
+
public
|
60
|
+
def to_s
|
61
|
+
return self.sprintf("%{@timestamp} %{@source}: %{@message}")
|
62
|
+
end # def to_s
|
63
|
+
|
64
|
+
public
|
65
|
+
def timestamp; @data["@timestamp"]; end # def timestamp
|
66
|
+
def timestamp=(val); @data["@timestamp"] = val; end # def timestamp=
|
67
|
+
|
68
|
+
public
|
69
|
+
def unix_timestamp
|
70
|
+
if RUBY_ENGINE != "jruby"
|
71
|
+
# This is really slow. See LOGSTASH-217
|
72
|
+
return Time.parse(timestamp).to_f
|
73
|
+
else
|
74
|
+
time = @@date_parser.parseDateTime(timestamp)
|
75
|
+
return time.getMillis.to_f / 1000
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
public
|
80
|
+
def source; @data["@source"]; end # def source
|
81
|
+
def source=(val)
|
82
|
+
uri = URI.parse(val) rescue nil
|
83
|
+
val = uri if uri
|
84
|
+
if val.is_a?(URI)
|
85
|
+
@data["@source"] = val.to_s
|
86
|
+
@data["@source_host"] = val.host
|
87
|
+
@data["@source_path"] = val.path
|
88
|
+
else
|
89
|
+
@data["@source"] = val
|
90
|
+
@data["@source_host"] = val
|
91
|
+
end
|
92
|
+
end # def source=
|
93
|
+
|
94
|
+
public
|
95
|
+
def source_host; @data["@source_host"]; end # def source_host
|
96
|
+
def source_host=(val); @data["@source_host"] = val; end # def source_host=
|
97
|
+
|
98
|
+
public
|
99
|
+
def source_path; @data["@source_path"]; end # def source_path
|
100
|
+
def source_path=(val); @data["@source_path"] = val; end # def source_path=
|
101
|
+
|
102
|
+
public
|
103
|
+
def message; @data["@message"]; end # def message
|
104
|
+
def message=(val); @data["@message"] = val; end # def message=
|
105
|
+
|
106
|
+
public
|
107
|
+
def type; @data["@type"]; end # def type
|
108
|
+
def type=(val); @data["@type"] = val; end # def type=
|
109
|
+
|
110
|
+
public
|
111
|
+
def tags; @data["@tags"]; end # def tags
|
112
|
+
def tags=(val); @data["@tags"] = val; end # def tags=
|
113
|
+
|
114
|
+
# field-related access
|
115
|
+
public
|
116
|
+
def [](key)
|
117
|
+
# If the key isn't in fields and it starts with an "@" sign, get it out of data instead of fields
|
118
|
+
if ! @data["@fields"].has_key?(key) and key.slice(0,1) == "@"
|
119
|
+
return @data[key]
|
120
|
+
# Exists in @fields (returns value) or doesn't start with "@" (return null)
|
121
|
+
else
|
122
|
+
return @data["@fields"][key]
|
123
|
+
end
|
124
|
+
end # def []
|
125
|
+
|
126
|
+
public
|
127
|
+
def []=(key, value)
|
128
|
+
if @data.has_key?(key)
|
129
|
+
@data[key] = value
|
130
|
+
else
|
131
|
+
@data["@fields"][key] = value
|
132
|
+
end
|
133
|
+
end # def []=
|
134
|
+
|
135
|
+
def fields; return @data["@fields"] end # def fields
|
136
|
+
|
137
|
+
public
|
138
|
+
def to_json(*args); return @data.to_json(*args) end # def to_json
|
139
|
+
def to_hash; return @data end # def to_hash
|
140
|
+
|
141
|
+
public
|
142
|
+
def overwrite(event)
|
143
|
+
@data = event.to_hash
|
144
|
+
end
|
145
|
+
|
146
|
+
public
|
147
|
+
def include?(key)
|
148
|
+
return (@data.include?(key) or @data["@fields"].include?(key))
|
149
|
+
end # def include?
|
150
|
+
|
151
|
+
# Append an event to this one.
|
152
|
+
public
|
153
|
+
def append(event)
|
154
|
+
if event.message
|
155
|
+
if self.message
|
156
|
+
self.message += "\n" + event.message
|
157
|
+
else
|
158
|
+
self.message = event.message
|
159
|
+
end
|
160
|
+
end
|
161
|
+
self.tags |= event.tags
|
162
|
+
|
163
|
+
# Append all fields
|
164
|
+
event.fields.each do |name, value|
|
165
|
+
if self.fields.include?(name)
|
166
|
+
if !self.fields[name].is_a?(Array)
|
167
|
+
self.fields[name] = [self.fields[name]]
|
168
|
+
end
|
169
|
+
if value.is_a?(Array)
|
170
|
+
self.fields[name] |= value
|
171
|
+
else
|
172
|
+
self.fields[name] << value unless self.fields[name].include?(value)
|
173
|
+
end
|
174
|
+
else
|
175
|
+
self.fields[name] = value
|
176
|
+
end
|
177
|
+
end # event.fields.each
|
178
|
+
end # def append
|
179
|
+
|
180
|
+
# Remove a field
|
181
|
+
public
|
182
|
+
def remove(field)
|
183
|
+
if @data.has_key?(field)
|
184
|
+
@data.delete(field)
|
185
|
+
else
|
186
|
+
@data["@fields"].delete(field)
|
187
|
+
end
|
188
|
+
end # def remove
|
189
|
+
|
190
|
+
# sprintf. This could use a better method name.
|
191
|
+
# The idea is to take an event and convert it to a string based on
|
192
|
+
# any format values, delimited by %{foo} where 'foo' is a field or
|
193
|
+
# metadata member.
|
194
|
+
#
|
195
|
+
# For example, if the event has @type == "foo" and @source == "bar"
|
196
|
+
# then this string:
|
197
|
+
# "type is %{@type} and source is %{@source}"
|
198
|
+
# will return
|
199
|
+
# "type is foo and source is bar"
|
200
|
+
#
|
201
|
+
# If a %{name} value is an array, then we will join by ','
|
202
|
+
# If a %{name} value does not exist, then no substitution occurs.
|
203
|
+
#
|
204
|
+
# TODO(sissel): It is not clear what the value of a field that
|
205
|
+
# is an array (or hash?) should be. Join by comma? Something else?
|
206
|
+
public
|
207
|
+
def sprintf(format)
|
208
|
+
if format.index("%").nil?
|
209
|
+
return format
|
210
|
+
end
|
211
|
+
|
212
|
+
return format.gsub(/%\{[^}]+\}/) do |tok|
|
213
|
+
# Take the inside of the %{ ... }
|
214
|
+
key = tok[2 ... -1]
|
215
|
+
|
216
|
+
if key == "+%s"
|
217
|
+
# Got %{+%s}, support for unix epoch time
|
218
|
+
if RUBY_ENGINE != "jruby"
|
219
|
+
# This is really slow. See LOGSTASH-217
|
220
|
+
Date.parse(self.timestamp).to_i
|
221
|
+
else
|
222
|
+
datetime = @@date_parser.parseDateTime(self.timestamp)
|
223
|
+
(datetime.getMillis / 1000).to_i
|
224
|
+
end
|
225
|
+
elsif key[0,1] == "+"
|
226
|
+
# We got a %{+TIMEFORMAT} so use joda to format it.
|
227
|
+
if RUBY_ENGINE != "jruby"
|
228
|
+
# This is really slow. See LOGSTASH-217
|
229
|
+
datetime = Date.parse(self.timestamp)
|
230
|
+
format = key[1 .. -1]
|
231
|
+
datetime.strftime(format)
|
232
|
+
else
|
233
|
+
datetime = @@date_parser.parseDateTime(self.timestamp)
|
234
|
+
format = key[1 .. -1]
|
235
|
+
datetime.toString(format) # return requested time format
|
236
|
+
end
|
237
|
+
else
|
238
|
+
# Use an event field.
|
239
|
+
value = nil
|
240
|
+
obj = self
|
241
|
+
|
242
|
+
# If the top-level value exists, use that and don't try
|
243
|
+
# to "look" into data structures.
|
244
|
+
if self[key]
|
245
|
+
value = self[key]
|
246
|
+
else
|
247
|
+
# "." is what ES uses to access structured data, so adopt that
|
248
|
+
# idea here, too. "foo.bar" will access key "bar" under hash "foo".
|
249
|
+
key.split('.').each do |segment|
|
250
|
+
if obj
|
251
|
+
value = obj[segment] rescue nil
|
252
|
+
obj = obj[segment] rescue nil
|
253
|
+
else
|
254
|
+
value = nil
|
255
|
+
break
|
256
|
+
end
|
257
|
+
end # key.split.each
|
258
|
+
end # if self[key]
|
259
|
+
|
260
|
+
case value
|
261
|
+
when nil
|
262
|
+
tok # leave the %{foo} if this field does not exist in this event.
|
263
|
+
when Array
|
264
|
+
value.join(",") # Join by ',' if value is an array
|
265
|
+
when Hash
|
266
|
+
value.to_json # Convert hashes to json
|
267
|
+
else
|
268
|
+
value # otherwise return the value
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end # def sprintf
|
273
|
+
|
274
|
+
public
|
275
|
+
def ==(other)
|
276
|
+
#puts "#{self.class.name}#==(#{other.inspect})"
|
277
|
+
if !other.is_a?(self.class)
|
278
|
+
return false
|
279
|
+
end
|
280
|
+
|
281
|
+
return other.to_hash == self.to_hash
|
282
|
+
end # def ==
|
283
|
+
end # class LogStash::Event
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$: << File.join(File.dirname(__FILE__), "..", "..", "vendor", "bundle")
|
2
|
+
|
3
|
+
module LogStash
|
4
|
+
module Inputs; end
|
5
|
+
module Outputs; end
|
6
|
+
module Filters; end
|
7
|
+
module Search; end
|
8
|
+
module Config; end
|
9
|
+
module File; end
|
10
|
+
module Web; end
|
11
|
+
module Util; end
|
12
|
+
|
13
|
+
SHUTDOWN = :shutdown
|
14
|
+
end # module LogStash
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "logstash/namespace"
|
2
|
+
|
3
|
+
# Provide our own Time wrapper for ISO8601 support
|
4
|
+
# Example:
|
5
|
+
# >> LogStash::Time.now.to_iso8601
|
6
|
+
# => "2010-10-17 00:25:24.619014-0700"
|
7
|
+
#
|
8
|
+
# >> LogStash::Time.now.utc.to_iso8601
|
9
|
+
# => "2010-10-17 07:25:26.788704Z"
|
10
|
+
module LogStash::Time
|
11
|
+
if RUBY_ENGINE == "jruby"
|
12
|
+
require "java"
|
13
|
+
DateTime = org.joda.time.DateTime
|
14
|
+
DateTimeZone = org.joda.time.DateTimeZone
|
15
|
+
def self.now
|
16
|
+
# org.joda.time.DateTime#to_s returns the time in ISO8601 form :)
|
17
|
+
# Could call DateTime.new(DateTimeZone::UTC) but JRuby calls the
|
18
|
+
# DateTime#new(Object) constructor instead of the
|
19
|
+
# DateTime#new(DateTimeZone) constructor. I was unable to get java_send to invoke this constructor,
|
20
|
+
# so instead I have to do DateTime#new#withZone(UTC)
|
21
|
+
return DateTime.new.withZone(DateTimeZone::UTC).to_s
|
22
|
+
end # def initialize
|
23
|
+
else
|
24
|
+
# Otherwise, use ruby stdlib Time, which is much slower than Joda.
|
25
|
+
ISO8601_STRFTIME = "%04d-%02d-%02dT%02d:%02d:%02d.%06d%+03d:00".freeze
|
26
|
+
def self.now
|
27
|
+
now = Time.new.utc
|
28
|
+
return sprintf(ISO8601_STRFTIME, now.year, now.month, now.day, now.hour,
|
29
|
+
now.min, now.sec, now.tv_usec, now.utc_offset / 3600)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end # module LogStash::Time
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logstash-event
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jordan Sissel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Library that contains the classes required to create LogStash events
|
15
|
+
email:
|
16
|
+
- jls@semicomplete.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/logstash-event.rb
|
22
|
+
- lib/logstash/event.rb
|
23
|
+
- lib/logstash/namespace.rb
|
24
|
+
- lib/logstash/time.rb
|
25
|
+
- lib/logstash/version.rb
|
26
|
+
- LICENSE
|
27
|
+
homepage: https://github.com/logstash/logstash
|
28
|
+
licenses:
|
29
|
+
- Apache License (2.0)
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 1.8.24
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: Library that contains the classes required to create LogStash events
|
52
|
+
test_files: []
|