logstash-core 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.

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