logstash-core 2.2.4.snapshot1

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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-core.rb +1 -0
  3. data/lib/logstash-core/logstash-core.rb +3 -0
  4. data/lib/logstash-core/version.rb +8 -0
  5. data/lib/logstash/agent.rb +391 -0
  6. data/lib/logstash/codecs/base.rb +50 -0
  7. data/lib/logstash/config/config_ast.rb +550 -0
  8. data/lib/logstash/config/cpu_core_strategy.rb +32 -0
  9. data/lib/logstash/config/defaults.rb +12 -0
  10. data/lib/logstash/config/file.rb +39 -0
  11. data/lib/logstash/config/grammar.rb +3503 -0
  12. data/lib/logstash/config/mixin.rb +518 -0
  13. data/lib/logstash/config/registry.rb +13 -0
  14. data/lib/logstash/environment.rb +98 -0
  15. data/lib/logstash/errors.rb +12 -0
  16. data/lib/logstash/filters/base.rb +205 -0
  17. data/lib/logstash/inputs/base.rb +116 -0
  18. data/lib/logstash/inputs/threadable.rb +18 -0
  19. data/lib/logstash/java_integration.rb +116 -0
  20. data/lib/logstash/json.rb +61 -0
  21. data/lib/logstash/logging.rb +91 -0
  22. data/lib/logstash/namespace.rb +13 -0
  23. data/lib/logstash/output_delegator.rb +172 -0
  24. data/lib/logstash/outputs/base.rb +91 -0
  25. data/lib/logstash/patches.rb +5 -0
  26. data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
  27. data/lib/logstash/patches/cabin.rb +35 -0
  28. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  29. data/lib/logstash/patches/rubygems.rb +38 -0
  30. data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
  31. data/lib/logstash/pipeline.rb +499 -0
  32. data/lib/logstash/pipeline_reporter.rb +114 -0
  33. data/lib/logstash/plugin.rb +120 -0
  34. data/lib/logstash/program.rb +14 -0
  35. data/lib/logstash/runner.rb +124 -0
  36. data/lib/logstash/shutdown_watcher.rb +100 -0
  37. data/lib/logstash/util.rb +203 -0
  38. data/lib/logstash/util/buftok.rb +139 -0
  39. data/lib/logstash/util/charset.rb +35 -0
  40. data/lib/logstash/util/decorators.rb +52 -0
  41. data/lib/logstash/util/defaults_printer.rb +31 -0
  42. data/lib/logstash/util/filetools.rb +186 -0
  43. data/lib/logstash/util/java_version.rb +66 -0
  44. data/lib/logstash/util/password.rb +25 -0
  45. data/lib/logstash/util/plugin_version.rb +56 -0
  46. data/lib/logstash/util/prctl.rb +10 -0
  47. data/lib/logstash/util/retryable.rb +40 -0
  48. data/lib/logstash/util/socket_peer.rb +7 -0
  49. data/lib/logstash/util/unicode_trimmer.rb +81 -0
  50. data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
  51. data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
  52. data/lib/logstash/version.rb +14 -0
  53. data/locales/en.yml +204 -0
  54. data/logstash-core.gemspec +58 -0
  55. data/spec/conditionals_spec.rb +429 -0
  56. data/spec/logstash/agent_spec.rb +85 -0
  57. data/spec/logstash/config/config_ast_spec.rb +146 -0
  58. data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
  59. data/spec/logstash/config/defaults_spec.rb +10 -0
  60. data/spec/logstash/config/mixin_spec.rb +158 -0
  61. data/spec/logstash/environment_spec.rb +56 -0
  62. data/spec/logstash/filters/base_spec.rb +251 -0
  63. data/spec/logstash/inputs/base_spec.rb +74 -0
  64. data/spec/logstash/java_integration_spec.rb +304 -0
  65. data/spec/logstash/json_spec.rb +96 -0
  66. data/spec/logstash/output_delegator_spec.rb +144 -0
  67. data/spec/logstash/outputs/base_spec.rb +40 -0
  68. data/spec/logstash/patches_spec.rb +90 -0
  69. data/spec/logstash/pipeline_reporter_spec.rb +85 -0
  70. data/spec/logstash/pipeline_spec.rb +455 -0
  71. data/spec/logstash/plugin_spec.rb +169 -0
  72. data/spec/logstash/runner_spec.rb +68 -0
  73. data/spec/logstash/shutdown_watcher_spec.rb +113 -0
  74. data/spec/logstash/util/buftok_spec.rb +31 -0
  75. data/spec/logstash/util/charset_spec.rb +74 -0
  76. data/spec/logstash/util/defaults_printer_spec.rb +50 -0
  77. data/spec/logstash/util/java_version_spec.rb +79 -0
  78. data/spec/logstash/util/plugin_version_spec.rb +64 -0
  79. data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
  80. data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
  81. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
  82. data/spec/logstash/util_spec.rb +35 -0
  83. metadata +364 -0
@@ -0,0 +1,203 @@
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
+ def self.set_thread_plugin(plugin)
28
+ Thread.current[:plugin] = plugin
29
+ end
30
+
31
+ def self.get_thread_id(thread)
32
+ if RUBY_ENGINE == "jruby"
33
+ JRuby.reference(thread).native_thread.id
34
+ else
35
+ raise Exception.new("Native thread IDs aren't supported outside of JRuby")
36
+ end
37
+ end
38
+
39
+ def self.thread_info(thread)
40
+ backtrace = thread.backtrace.map do |line|
41
+ line.gsub(LogStash::Environment::LOGSTASH_HOME, "[...]")
42
+ end
43
+
44
+ blocked_on = case backtrace.first
45
+ when /in `push'/ then "blocked_on_push"
46
+ when /(?:pipeline|base).*pop/ then "waiting_for_events"
47
+ else nil
48
+ end
49
+
50
+ {
51
+ "thread_id" => get_thread_id(thread),
52
+ "name" => thread[:name],
53
+ "plugin" => (thread[:plugin] ? thread[:plugin].debug_info : nil),
54
+ "backtrace" => backtrace,
55
+ "blocked_on" => blocked_on,
56
+ "status" => thread.status,
57
+ "current_call" => backtrace.first
58
+ }
59
+ end
60
+
61
+
62
+ # Merge hash 'src' into 'dst' nondestructively
63
+ #
64
+ # Duplicate keys will become array values
65
+ #
66
+ # [ src["foo"], dst["foo"] ]
67
+ def self.hash_merge(dst, src)
68
+ src.each do |name, svalue|
69
+ if dst.include?(name)
70
+ dvalue = dst[name]
71
+ if dvalue.is_a?(Hash) && svalue.is_a?(Hash)
72
+ dvalue = hash_merge(dvalue, svalue)
73
+ elsif svalue.is_a?(Array)
74
+ if dvalue.is_a?(Array)
75
+ # merge arrays without duplicates.
76
+ dvalue |= svalue
77
+ else
78
+ dvalue = [dvalue] | svalue
79
+ end
80
+ else
81
+ if dvalue.is_a?(Array)
82
+ dvalue << svalue unless dvalue.include?(svalue)
83
+ else
84
+ dvalue = [dvalue, svalue] unless dvalue == svalue
85
+ end
86
+ end
87
+
88
+ dst[name] = dvalue
89
+ else
90
+ # dst doesn't have this key, just set it.
91
+ dst[name] = svalue
92
+ end
93
+ end
94
+
95
+ return dst
96
+ end # def self.hash_merge
97
+
98
+ # Merge hash 'src' into 'dst' nondestructively
99
+ #
100
+ # Duplicate keys will become array values
101
+ # Arrays merged will simply be appended.
102
+ #
103
+ # [ src["foo"], dst["foo"] ]
104
+ def self.hash_merge_with_dups(dst, src)
105
+ src.each do |name, svalue|
106
+ if dst.include?(name)
107
+ dvalue = dst[name]
108
+ if dvalue.is_a?(Hash) && svalue.is_a?(Hash)
109
+ dvalue = hash_merge(dvalue, svalue)
110
+ elsif svalue.is_a?(Array)
111
+ if dvalue.is_a?(Array)
112
+ # merge arrays without duplicates.
113
+ dvalue += svalue
114
+ else
115
+ dvalue = [dvalue] + svalue
116
+ end
117
+ else
118
+ if dvalue.is_a?(Array)
119
+ dvalue << svalue unless dvalue.include?(svalue)
120
+ else
121
+ dvalue = [dvalue, svalue] unless dvalue == svalue
122
+ end
123
+ end
124
+
125
+ dst[name] = dvalue
126
+ else
127
+ # dst doesn't have this key, just set it.
128
+ dst[name] = svalue
129
+ end
130
+ end
131
+
132
+ return dst
133
+ end # def self.hash_merge
134
+
135
+ def self.hash_merge_many(*hashes)
136
+ dst = {}
137
+ hashes.each do |hash|
138
+ hash_merge_with_dups(dst, hash)
139
+ end
140
+ return dst
141
+ end # def hash_merge_many
142
+
143
+
144
+ # nomalize method definition based on platform.
145
+ # normalize is used to convert an object create through
146
+ # json deserialization from JrJackson in :raw mode to pure Ruby
147
+ # to support these pure Ruby object monkey patches.
148
+ # see logstash/json.rb and logstash/java_integration.rb
149
+
150
+ if LogStash::Environment.jruby?
151
+ require "java"
152
+
153
+ # recursively convert any Java LinkedHashMap and ArrayList to pure Ruby.
154
+ # will not recurse into pure Ruby objects. Pure Ruby object should never
155
+ # contain LinkedHashMap and ArrayList since these are only created at
156
+ # initial deserialization, anything after (deeper) will be pure Ruby.
157
+ def self.normalize(o)
158
+ case o
159
+ when Java::JavaUtil::LinkedHashMap
160
+ o.inject({}){|r, (k, v)| r[k] = normalize(v); r}
161
+ when Java::JavaUtil::ArrayList
162
+ o.map{|i| normalize(i)}
163
+ else
164
+ o
165
+ end
166
+ end
167
+
168
+ else
169
+
170
+ # identity function, pure Ruby object don't need normalization.
171
+ def self.normalize(o); o; end
172
+ end
173
+
174
+ def self.stringify_symbols(o)
175
+ case o
176
+ when Hash
177
+ o.inject({}){|r, (k, v)| r[k.is_a?(Symbol) ? k.to_s : k] = stringify_symbols(v); r}
178
+ when Array
179
+ o.map{|i| stringify_symbols(i)}
180
+ when Symbol
181
+ o.to_s
182
+ else
183
+ o
184
+ end
185
+ end
186
+
187
+ def self.deep_clone(o)
188
+ case o
189
+ when Hash
190
+ o.inject({}) {|h, (k,v)| h[k] = deep_clone(v); h }
191
+ when Array
192
+ o.map {|v| deep_clone(v) }
193
+ when Fixnum, Symbol, IO, TrueClass, FalseClass, NilClass
194
+ o
195
+ when LogStash::Codecs::Base
196
+ o.clone
197
+ when String
198
+ o.clone #need to keep internal state e.g. frozen
199
+ else
200
+ Marshal.load(Marshal.dump(o))
201
+ end
202
+ end
203
+ 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
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/util"
4
+
5
+ class LogStash::Util::Charset
6
+ attr_accessor :logger
7
+
8
+ def initialize(charset)
9
+ @charset = charset
10
+ @charset_encoding = Encoding.find(charset)
11
+ end
12
+
13
+ def convert(data)
14
+ data.force_encoding(@charset_encoding)
15
+
16
+ # NON UTF-8 charset declared.
17
+ # Let's convert it (as cleanly as possible) into UTF-8 so we can use it with JSON, etc.
18
+ return data.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace) unless @charset_encoding == Encoding::UTF_8
19
+
20
+ # UTF-8 charset declared.
21
+ # Some users don't know the charset of their logs or just don't know they
22
+ # can set the charset setting.
23
+ unless data.valid_encoding?
24
+ # A silly hack to help convert some of the unknown bytes to
25
+ # somewhat-readable escape codes. The [1..-2] is to trim the quotes
26
+ # ruby puts on the value.
27
+ return data.inspect[1..-2].tap do |escaped|
28
+ @logger.warn("Received an event that has a different character encoding than you configured.", :text => escaped, :expected_charset => @charset)
29
+ end
30
+ end
31
+
32
+ return data
33
+ end # def convert
34
+
35
+ end # class LogStash::Util::Charset
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/util"
4
+
5
+ module LogStash::Util
6
+
7
+ # Decorators provides common manipulation on the event data.
8
+ module Decorators
9
+ extend self
10
+
11
+ @logger = Cabin::Channel.get(LogStash)
12
+
13
+ # fields is a hash of field => value
14
+ # where both `field` and `value` can use sprintf syntax.
15
+ def add_fields(fields,event, pluginname)
16
+ fields.each do |field, value|
17
+ field = event.sprintf(field)
18
+ value = Array(value)
19
+ value.each do |v|
20
+ v = event.sprintf(v)
21
+ if event.include?(field)
22
+ # note below that the array field needs to be updated then reassigned to the event.
23
+ # this is important because a construct like event[field] << v will not work
24
+ # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
25
+ a = Array(event[field])
26
+ a << v
27
+ event[field] = a
28
+ else
29
+ event[field] = v
30
+ end
31
+ @logger.debug? and @logger.debug("#{pluginname}: adding value to field", :field => field, :value => value)
32
+ end
33
+ end
34
+ end
35
+
36
+ # tags is an array of string. sprintf syntax can be used.
37
+ def add_tags(tags, event, pluginname)
38
+ tags.each do |tag|
39
+ tag = event.sprintf(tag)
40
+ @logger.debug? and @logger.debug("#{pluginname}: adding tag", :tag => tag)
41
+ # note below that the tags array field needs to be updated then reassigned to the event.
42
+ # this is important because a construct like event["tags"] << tag will not work
43
+ # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
44
+ tags = event["tags"] || []
45
+ tags << tag
46
+ event["tags"] = tags
47
+ end
48
+ end
49
+
50
+ end # module LogStash::Util::Decorators
51
+
52
+ end # module LogStash::Util
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/util"
4
+ require "logstash/util/worker_threads_default_printer"
5
+
6
+
7
+ # This class exists to format the settings for defaults used
8
+ module LogStash module Util class DefaultsPrinter
9
+ def self.print(settings)
10
+ new(settings).print
11
+ end
12
+
13
+ def initialize(settings)
14
+ @settings = settings
15
+ @printers = [workers]
16
+ end
17
+
18
+ def print
19
+ collector = []
20
+ @printers.each do |printer|
21
+ printer.visit(collector)
22
+ end
23
+ "Settings: " + collector.join(', ')
24
+ end
25
+
26
+ private
27
+
28
+ def workers
29
+ WorkerThreadsDefaultPrinter.new(@settings)
30
+ end
31
+ end end end