logstash-core 1.5.0.beta2-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of logstash-core might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-event.rb +2 -0
  3. data/lib/logstash.rb +4 -0
  4. data/lib/logstash/JRUBY-PR1448.rb +32 -0
  5. data/lib/logstash/agent.rb +355 -0
  6. data/lib/logstash/bundler.rb +124 -0
  7. data/lib/logstash/codecs/base.rb +50 -0
  8. data/lib/logstash/config/config_ast.rb +508 -0
  9. data/lib/logstash/config/file.rb +39 -0
  10. data/lib/logstash/config/grammar.rb +3503 -0
  11. data/lib/logstash/config/mixin.rb +495 -0
  12. data/lib/logstash/config/registry.rb +13 -0
  13. data/lib/logstash/environment.rb +168 -0
  14. data/lib/logstash/errors.rb +12 -0
  15. data/lib/logstash/event.rb +310 -0
  16. data/lib/logstash/filters/base.rb +239 -0
  17. data/lib/logstash/gemfile.rb +175 -0
  18. data/lib/logstash/inputs/base.rb +137 -0
  19. data/lib/logstash/inputs/threadable.rb +18 -0
  20. data/lib/logstash/java_integration.rb +41 -0
  21. data/lib/logstash/json.rb +53 -0
  22. data/lib/logstash/logging.rb +91 -0
  23. data/lib/logstash/multiqueue.rb +53 -0
  24. data/lib/logstash/namespace.rb +17 -0
  25. data/lib/logstash/outputs/base.rb +124 -0
  26. data/lib/logstash/patches.rb +3 -0
  27. data/lib/logstash/patches/bugfix_jruby_2558.rb +50 -0
  28. data/lib/logstash/patches/cabin.rb +34 -0
  29. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  30. data/lib/logstash/pipeline.rb +305 -0
  31. data/lib/logstash/plugin.rb +177 -0
  32. data/lib/logstash/pluginmanager.rb +17 -0
  33. data/lib/logstash/pluginmanager/install.rb +112 -0
  34. data/lib/logstash/pluginmanager/list.rb +38 -0
  35. data/lib/logstash/pluginmanager/main.rb +22 -0
  36. data/lib/logstash/pluginmanager/maven_tools_patch.rb +12 -0
  37. data/lib/logstash/pluginmanager/uninstall.rb +49 -0
  38. data/lib/logstash/pluginmanager/update.rb +50 -0
  39. data/lib/logstash/pluginmanager/util.rb +88 -0
  40. data/lib/logstash/program.rb +15 -0
  41. data/lib/logstash/runner.rb +167 -0
  42. data/lib/logstash/sized_queue.rb +8 -0
  43. data/lib/logstash/threadwatchdog.rb +37 -0
  44. data/lib/logstash/timestamp.rb +97 -0
  45. data/lib/logstash/util.rb +152 -0
  46. data/lib/logstash/util/accessors.rb +88 -0
  47. data/lib/logstash/util/buftok.rb +139 -0
  48. data/lib/logstash/util/charset.rb +35 -0
  49. data/lib/logstash/util/fieldreference.rb +68 -0
  50. data/lib/logstash/util/filetools.rb +185 -0
  51. data/lib/logstash/util/password.rb +25 -0
  52. data/lib/logstash/util/plugin_version.rb +43 -0
  53. data/lib/logstash/util/prctl.rb +11 -0
  54. data/lib/logstash/util/require-helper.rb +18 -0
  55. data/lib/logstash/util/retryable.rb +39 -0
  56. data/lib/logstash/util/socket_peer.rb +7 -0
  57. data/lib/logstash/version.rb +6 -0
  58. data/locales/en.yml +176 -0
  59. metadata +427 -0
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/logging"
4
+
5
+ require "thread" # for SizedQueue
6
+ class LogStash::SizedQueue < SizedQueue
7
+ # TODO(sissel): Soon will implement push/pop stats, etc
8
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/logging"
4
+
5
+ class LogStash::ThreadWatchdog
6
+ attr_accessor :logger
7
+ attr_accessor :threads
8
+
9
+ class TimeoutError < StandardError; end
10
+
11
+ public
12
+ def initialize(threads, watchdog_timeout=10)
13
+ @threads = threads
14
+ @watchdog_timeout = watchdog_timeout
15
+ end # def initialize
16
+
17
+ public
18
+ def watch
19
+ while sleep(1)
20
+ cutoff = Time.now - @watchdog_timeout
21
+ @threads.each do |t|
22
+ watchdog = t[:watchdog]
23
+ if watchdog and watchdog <= cutoff
24
+ age = Time.now - watchdog
25
+ @logger.fatal("thread watchdog timeout",
26
+ :thread => t,
27
+ :backtrace => t.backtrace,
28
+ :thread_watchdog => watchdog,
29
+ :age => age,
30
+ :cutoff => @watchdog_timeout,
31
+ :state => t[:watchdog_state])
32
+ raise TimeoutError, "watchdog timeout"
33
+ end
34
+ end
35
+ end
36
+ end # def watch
37
+ end # class LogStash::ThreadWatchdog
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+ require "logstash/environment"
3
+ require "logstash/json"
4
+ require "forwardable"
5
+ require "date"
6
+ require "time"
7
+
8
+ module LogStash
9
+ class TimestampParserError < StandardError; end
10
+
11
+ class Timestamp
12
+ extend Forwardable
13
+ include Comparable
14
+
15
+ def_delegators :@time, :tv_usec, :usec, :year, :iso8601, :to_i, :tv_sec, :to_f, :to_edn, :<=>, :+
16
+
17
+ attr_reader :time
18
+
19
+ ISO8601_STRFTIME = "%04d-%02d-%02dT%02d:%02d:%02d.%06d%+03d:00".freeze
20
+ ISO8601_PRECISION = 3
21
+
22
+ def initialize(time = Time.new)
23
+ @time = time.utc
24
+ end
25
+
26
+ def self.at(*args)
27
+ Timestamp.new(::Time.at(*args))
28
+ end
29
+
30
+ def self.parse(*args)
31
+ Timestamp.new(::Time.parse(*args))
32
+ end
33
+
34
+ def self.now
35
+ Timestamp.new(::Time.now)
36
+ end
37
+
38
+ # coerce tries different strategies based on the time object class to convert into a Timestamp.
39
+ # @param [String, Time, Timestamp] time the time object to try coerce
40
+ # @return [Timestamp, nil] Timestamp will be returned if successful otherwise nil
41
+ # @raise [TimestampParserError] on String with invalid format
42
+ def self.coerce(time)
43
+ case time
44
+ when String
45
+ LogStash::Timestamp.parse_iso8601(time)
46
+ when LogStash::Timestamp
47
+ time
48
+ when Time
49
+ LogStash::Timestamp.new(time)
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ if LogStash::Environment.jruby?
56
+ JODA_ISO8601_PARSER = org.joda.time.format.ISODateTimeFormat.dateTimeParser
57
+ UTC = org.joda.time.DateTimeZone.forID("UTC")
58
+
59
+ def self.parse_iso8601(t)
60
+ millis = JODA_ISO8601_PARSER.parseMillis(t)
61
+ LogStash::Timestamp.at(millis / 1000, (millis % 1000) * 1000)
62
+ rescue => e
63
+ raise(TimestampParserError, "invalid timestamp string #{t.inspect}, error=#{e.inspect}")
64
+ end
65
+
66
+ else
67
+
68
+ def self.parse_iso8601(t)
69
+ # warning, ruby's Time.parse is *really* terrible and slow.
70
+ LogStash::Timestamp.new(::Time.parse(t))
71
+ rescue => e
72
+ raise(TimestampParserError, "invalid timestamp string #{t.inspect}, error=#{e.inspect}")
73
+ end
74
+ end
75
+
76
+ def utc
77
+ @time.utc # modifies the receiver
78
+ self
79
+ end
80
+ alias_method :gmtime, :utc
81
+
82
+ def to_json(*args)
83
+ # ignore arguments to respect accepted to_json method signature
84
+ "\"" + to_iso8601 + "\""
85
+ end
86
+ alias_method :inspect, :to_json
87
+
88
+ def to_iso8601
89
+ @iso8601 ||= @time.iso8601(ISO8601_PRECISION)
90
+ end
91
+ alias_method :to_s, :to_iso8601
92
+
93
+ def -(value)
94
+ @time - (value.is_a?(Timestamp) ? value.time : value)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/environment"
4
+
5
+ module LogStash::Util
6
+ UNAME = case RbConfig::CONFIG["host_os"]
7
+ when /^linux/; "linux"
8
+ else; RbConfig::CONFIG["host_os"]
9
+ end
10
+
11
+ PR_SET_NAME = 15
12
+ def self.set_thread_name(name)
13
+ if RUBY_ENGINE == "jruby"
14
+ # Keep java and ruby thread names in sync.
15
+ Java::java.lang.Thread.currentThread.setName(name)
16
+ end
17
+ Thread.current[:name] = name
18
+
19
+ if UNAME == "linux"
20
+ require "logstash/util/prctl"
21
+ # prctl PR_SET_NAME allows up to 16 bytes for a process name
22
+ # since MRI 1.9, JRuby, and Rubinius use system threads for this.
23
+ LibC.prctl(PR_SET_NAME, name[0..16], 0, 0, 0)
24
+ end
25
+ end # def set_thread_name
26
+
27
+ # Merge hash 'src' into 'dst' nondestructively
28
+ #
29
+ # Duplicate keys will become array values
30
+ #
31
+ # [ src["foo"], dst["foo"] ]
32
+ def self.hash_merge(dst, src)
33
+ src.each do |name, svalue|
34
+ if dst.include?(name)
35
+ dvalue = dst[name]
36
+ if dvalue.is_a?(Hash) && svalue.is_a?(Hash)
37
+ dvalue = hash_merge(dvalue, svalue)
38
+ elsif svalue.is_a?(Array)
39
+ if dvalue.is_a?(Array)
40
+ # merge arrays without duplicates.
41
+ dvalue |= svalue
42
+ else
43
+ dvalue = [dvalue] | svalue
44
+ end
45
+ else
46
+ if dvalue.is_a?(Array)
47
+ dvalue << svalue unless dvalue.include?(svalue)
48
+ else
49
+ dvalue = [dvalue, svalue] unless dvalue == svalue
50
+ end
51
+ end
52
+
53
+ dst[name] = dvalue
54
+ else
55
+ # dst doesn't have this key, just set it.
56
+ dst[name] = svalue
57
+ end
58
+ end
59
+
60
+ return dst
61
+ end # def self.hash_merge
62
+
63
+ # Merge hash 'src' into 'dst' nondestructively
64
+ #
65
+ # Duplicate keys will become array values
66
+ # Arrays merged will simply be appended.
67
+ #
68
+ # [ src["foo"], dst["foo"] ]
69
+ def self.hash_merge_with_dups(dst, src)
70
+ src.each do |name, svalue|
71
+ if dst.include?(name)
72
+ dvalue = dst[name]
73
+ if dvalue.is_a?(Hash) && svalue.is_a?(Hash)
74
+ dvalue = hash_merge(dvalue, svalue)
75
+ elsif svalue.is_a?(Array)
76
+ if dvalue.is_a?(Array)
77
+ # merge arrays without duplicates.
78
+ dvalue += svalue
79
+ else
80
+ dvalue = [dvalue] + svalue
81
+ end
82
+ else
83
+ if dvalue.is_a?(Array)
84
+ dvalue << svalue unless dvalue.include?(svalue)
85
+ else
86
+ dvalue = [dvalue, svalue] unless dvalue == svalue
87
+ end
88
+ end
89
+
90
+ dst[name] = dvalue
91
+ else
92
+ # dst doesn't have this key, just set it.
93
+ dst[name] = svalue
94
+ end
95
+ end
96
+
97
+ return dst
98
+ end # def self.hash_merge
99
+
100
+ def self.hash_merge_many(*hashes)
101
+ dst = {}
102
+ hashes.each do |hash|
103
+ hash_merge_with_dups(dst, hash)
104
+ end
105
+ return dst
106
+ end # def hash_merge_many
107
+
108
+
109
+ # nomalize method definition based on platform.
110
+ # normalize is used to convert an object create through
111
+ # json deserialization from JrJackson in :raw mode to pure Ruby
112
+ # to support these pure Ruby object monkey patches.
113
+ # see logstash/json.rb and logstash/java_integration.rb
114
+
115
+ if LogStash::Environment.jruby?
116
+ require "java"
117
+
118
+ # recursively convert any Java LinkedHashMap and ArrayList to pure Ruby.
119
+ # will not recurse into pure Ruby objects. Pure Ruby object should never
120
+ # contain LinkedHashMap and ArrayList since these are only created at
121
+ # initial deserialization, anything after (deeper) will be pure Ruby.
122
+ def self.normalize(o)
123
+ case o
124
+ when Java::JavaUtil::LinkedHashMap
125
+ o.inject({}){|r, (k, v)| r[k] = normalize(v); r}
126
+ when Java::JavaUtil::ArrayList
127
+ o.map{|i| normalize(i)}
128
+ else
129
+ o
130
+ end
131
+ end
132
+
133
+ else
134
+
135
+ # identity function, pure Ruby object don't need normalization.
136
+ def self.normalize(o); o; end
137
+ end
138
+
139
+ def self.stringify_symbols(o)
140
+ case o
141
+ when Hash
142
+ o.inject({}){|r, (k, v)| r[k.is_a?(Symbol) ? k.to_s : k] = stringify_symbols(v); r}
143
+ when Array
144
+ o.map{|i| stringify_symbols(i)}
145
+ when Symbol
146
+ o.to_s
147
+ else
148
+ o
149
+ end
150
+ end
151
+
152
+ end # module LogStash::Util
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/namespace"
4
+ require "logstash/util"
5
+
6
+ module LogStash::Util
7
+
8
+ # PathCache is a singleton which globally caches a parsed fields path for the path to the
9
+ # container hash and key in that hash.
10
+ module PathCache
11
+ extend self
12
+
13
+ def get(accessor)
14
+ @cache ||= {}
15
+ @cache[accessor] ||= parse(accessor)
16
+ end
17
+
18
+ def parse(accessor)
19
+ path = accessor.split(/[\[\]]/).select{|s| !s.empty?}
20
+ [path.pop, path]
21
+ end
22
+ end
23
+
24
+ # Accessors uses a lookup table to speedup access of an accessor field of the type
25
+ # "[hello][world]" to the underlying store hash into {"hello" => {"world" => "foo"}}
26
+ class Accessors
27
+
28
+ def initialize(store)
29
+ @store = store
30
+ @lut = {}
31
+ end
32
+
33
+ def get(accessor)
34
+ target, key = lookup(accessor)
35
+ unless target.nil?
36
+ target.is_a?(Array) ? target[key.to_i] : target[key]
37
+ end
38
+ end
39
+
40
+ def set(accessor, value)
41
+ target, key = store_and_lookup(accessor)
42
+ target[target.is_a?(Array) ? key.to_i : key] = value
43
+ end
44
+
45
+ def strict_set(accessor, value)
46
+ set(accessor, LogStash::Event.validate_value(value))
47
+ end
48
+
49
+ def del(accessor)
50
+ target, key = lookup(accessor)
51
+ unless target.nil?
52
+ target.is_a?(Array) ? target.delete_at(key.to_i) : target.delete(key)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def lookup(accessor)
59
+ target, key = lookup_path(accessor)
60
+ if target.nil?
61
+ [target, key]
62
+ else
63
+ @lut[accessor] = [target, key]
64
+ end
65
+ end
66
+
67
+ def store_and_lookup(accessor)
68
+ @lut[accessor] ||= store_path(accessor)
69
+ end
70
+
71
+ def lookup_path(accessor)
72
+ key, path = PathCache.get(accessor)
73
+ target = path.inject(@store) do |r, k|
74
+ if r.nil?
75
+ return nil
76
+ end
77
+ r[r.is_a?(Array) ? k.to_i : k]
78
+ end
79
+ [target, key]
80
+ end
81
+
82
+ def store_path(accessor)
83
+ key, path = PathCache.get(accessor)
84
+ target = path.inject(@store) {|r, k| r[r.is_a?(Array) ? k.to_i : k] ||= {}}
85
+ [target, key]
86
+ end
87
+ end # class Accessors
88
+ end # module LogStash::Util
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+ # BufferedTokenizer - Statefully split input data by a specifiable token
3
+ #
4
+ # Authors:: Tony Arcieri, Martin Emde
5
+ #
6
+ #----------------------------------------------------------------------------
7
+ #
8
+ # Copyright (C) 2006-07 by Tony Arcieri and Martin Emde
9
+ #
10
+ # Distributed under the Ruby license (http://www.ruby-lang.org/en/LICENSE.txt)
11
+ #
12
+ #---------------------------------------------------------------------------
13
+ #
14
+
15
+ # (C)2006 Tony Arcieri, Martin Emde
16
+ # Distributed under the Ruby license (http://www.ruby-lang.org/en/LICENSE.txt)
17
+
18
+ # BufferedTokenizer takes a delimiter upon instantiation, or acts line-based
19
+ # by default. It allows input to be spoon-fed from some outside source which
20
+ # receives arbitrary length datagrams which may-or-may-not contain the token
21
+ # by which entities are delimited.
22
+ #
23
+ # Commonly used to parse lines out of incoming data:
24
+ #
25
+ # module LineBufferedConnection
26
+ # def receive_data(data)
27
+ # (@buffer ||= BufferedTokenizer.new).extract(data).each do |line|
28
+ # receive_line(line)
29
+ # end
30
+ # end
31
+ # end
32
+
33
+ module FileWatch; class BufferedTokenizer
34
+ # New BufferedTokenizers will operate on lines delimited by "\n" by default
35
+ # or allow you to specify any delimiter token you so choose, which will then
36
+ # be used by String#split to tokenize the input data
37
+ def initialize(delimiter = "\n", size_limit = nil)
38
+ # Store the specified delimiter
39
+ @delimiter = delimiter
40
+
41
+ # Store the specified size limitation
42
+ @size_limit = size_limit
43
+
44
+ # The input buffer is stored as an array. This is by far the most efficient
45
+ # approach given language constraints (in C a linked list would be a more
46
+ # appropriate data structure). Segments of input data are stored in a list
47
+ # which is only joined when a token is reached, substantially reducing the
48
+ # number of objects required for the operation.
49
+ @input = []
50
+
51
+ # Size of the input buffer
52
+ @input_size = 0
53
+ end
54
+
55
+ # Extract takes an arbitrary string of input data and returns an array of
56
+ # tokenized entities, provided there were any available to extract. This
57
+ # makes for easy processing of datagrams using a pattern like:
58
+ #
59
+ # tokenizer.extract(data).map { |entity| Decode(entity) }.each do ...
60
+ def extract(data)
61
+ # Extract token-delimited entities from the input string with the split command.
62
+ # There's a bit of craftiness here with the -1 parameter. Normally split would
63
+ # behave no differently regardless of if the token lies at the very end of the
64
+ # input buffer or not (i.e. a literal edge case) Specifying -1 forces split to
65
+ # return "" in this case, meaning that the last entry in the list represents a
66
+ # new segment of data where the token has not been encountered
67
+ entities = data.split @delimiter, -1
68
+
69
+ # Check to see if the buffer has exceeded capacity, if we're imposing a limit
70
+ if @size_limit
71
+ raise 'input buffer full' if @input_size + entities.first.size > @size_limit
72
+ @input_size += entities.first.size
73
+ end
74
+
75
+ # Move the first entry in the resulting array into the input buffer. It represents
76
+ # the last segment of a token-delimited entity unless it's the only entry in the list.
77
+ @input << entities.shift
78
+
79
+ # If the resulting array from the split is empty, the token was not encountered
80
+ # (not even at the end of the buffer). Since we've encountered no token-delimited
81
+ # entities this go-around, return an empty array.
82
+ return [] if entities.empty?
83
+
84
+ # At this point, we've hit a token, or potentially multiple tokens. Now we can bring
85
+ # together all the data we've buffered from earlier calls without hitting a token,
86
+ # and add it to our list of discovered entities.
87
+ entities.unshift @input.join
88
+
89
+ =begin
90
+ # Note added by FC, 10Jul07. This paragraph contains a regression. It breaks
91
+ # empty tokens. Think of the empty line that delimits an HTTP header. It will have
92
+ # two "\n" delimiters in a row, and this code mishandles the resulting empty token.
93
+ # It someone figures out how to fix the problem, we can re-enable this code branch.
94
+ # Multi-character token support.
95
+ # Split any tokens that were incomplete on the last iteration buf complete now.
96
+ entities.map! do |e|
97
+ e.split @delimiter, -1
98
+ end
99
+ # Flatten the resulting array. This has the side effect of removing the empty
100
+ # entry at the end that was produced by passing -1 to split. Add it again if
101
+ # necessary.
102
+ if (entities[-1] == [])
103
+ entities.flatten! << []
104
+ else
105
+ entities.flatten!
106
+ end
107
+ =end
108
+
109
+ # Now that we've hit a token, joined the input buffer and added it to the entities
110
+ # list, we can go ahead and clear the input buffer. All of the segments that were
111
+ # stored before the join can now be garbage collected.
112
+ @input.clear
113
+
114
+ # The last entity in the list is not token delimited, however, thanks to the -1
115
+ # passed to split. It represents the beginning of a new list of as-yet-untokenized
116
+ # data, so we add it to the start of the list.
117
+ @input << entities.pop
118
+
119
+ # Set the new input buffer size, provided we're keeping track
120
+ @input_size = @input.first.size if @size_limit
121
+
122
+ # Now we're left with the list of extracted token-delimited entities we wanted
123
+ # in the first place. Hooray!
124
+ entities
125
+ end
126
+
127
+ # Flush the contents of the input buffer, i.e. return the input buffer even though
128
+ # a token has not yet been encountered
129
+ def flush
130
+ buffer = @input.join
131
+ @input.clear
132
+ buffer
133
+ end
134
+
135
+ # Is the buffer empty?
136
+ def empty?
137
+ @input.empty?
138
+ end
139
+ end; end