logstash-core 1.5.1.snapshot1-java → 1.5.2-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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bfdb72c84f82dbcc3a0fe2186266df55d9fa5ad1
4
- data.tar.gz: fd6f4f326ebcabd35cbfefca906d3e0ecc1e62c2
3
+ metadata.gz: c1d4a0fc2ffd05d5ca9bb3d6d9c8c1ffeeed3e8e
4
+ data.tar.gz: 62546e37ec4e051369782ea1f3ad37d444e774aa
5
5
  SHA512:
6
- metadata.gz: bbaa4a864f7c1f7ce118787f86a6786a7183d7de29788d73263b4b05a53514054ce7b8a733ee39361e652ac15899912b6e33c449a72cdbd68972634cb8c54a2b
7
- data.tar.gz: ceefa0a85beab7a89b10d99b0598276beabccc4023c095ece38e1f4d589cb3415aa40975199c5457dfd2804a29cf034c82f94a3b3915387fd2107467465b76a7
6
+ metadata.gz: 949ed2af6b2b3100f7bf57a708c8b3081d60cb310374f19262beef13fa9c8426154f9eb85c3ba26ed06a641a1a8dd4d0198949805c53838d485047fd542d347f
7
+ data.tar.gz: ab49a4f44669506b310d2f80195177f563bb513320a3e0d7e44d86ddfb28deb713756e69c9fac7d73a993dd7a3134406cfdf9278f09af9863e13ba38f1329c5e
@@ -172,14 +172,8 @@ class LogStash::Agent < Clamp::Command
172
172
 
173
173
  if [:info, :debug].include?(verbosity?) || debug? || verbose?
174
174
  show_version_ruby
175
-
176
- if RUBY_PLATFORM == "java"
177
- show_version_java
178
- end
179
-
180
- if [:debug].include?(verbosity?) || debug?
181
- show_gems
182
- end
175
+ show_version_java if LogStash::Environment.jruby?
176
+ show_gems if [:debug].include?(verbosity?) || debug?
183
177
  end
184
178
  end # def show_version
185
179
 
@@ -77,7 +77,7 @@ module LogStash
77
77
  end
78
78
 
79
79
  def windows?
80
- Gem.win_platform?
80
+ ::Gem.win_platform?
81
81
  end
82
82
 
83
83
  def vendor_path(path)
@@ -3,10 +3,10 @@ require "time"
3
3
  require "date"
4
4
  require "cabin"
5
5
  require "logstash/namespace"
6
- require "logstash/util/fieldreference"
7
6
  require "logstash/util/accessors"
8
7
  require "logstash/timestamp"
9
8
  require "logstash/json"
9
+ require "logstash/string_interpolation"
10
10
 
11
11
  # transcient pipeline events for normal in-flow signaling as opposed to
12
12
  # flow altering exceptions. for now having base classes is adequate and
@@ -217,57 +217,10 @@ class LogStash::Event
217
217
  #
218
218
  # If a %{name} value is an array, then we will join by ','
219
219
  # If a %{name} value does not exist, then no substitution occurs.
220
- #
221
- # TODO(sissel): It is not clear what the value of a field that
222
- # is an array (or hash?) should be. Join by comma? Something else?
223
220
  public
224
221
  def sprintf(format)
225
- if format.is_a?(Float) and
226
- (format < MIN_FLOAT_BEFORE_SCI_NOT or format >= MAX_FLOAT_BEFORE_SCI_NOT) then
227
- format = ("%.15f" % format).sub(/0*$/,"")
228
- else
229
- format = format.to_s
230
- end
231
- if format.index("%").nil?
232
- return format
233
- end
234
-
235
- return format.gsub(/%\{[^}]+\}/) do |tok|
236
- # Take the inside of the %{ ... }
237
- key = tok[2 ... -1]
238
-
239
- if key[0] == "+" && !@data.has_key?(TIMESTAMP)
240
- raise LogStash::Error, "Unable to format \"#{key}\" in string \"#{format}\", #{TIMESTAMP} field not found"
241
- end
242
-
243
- if key == "+%s"
244
- # Got %{+%s}, support for unix epoch time
245
- next @data[TIMESTAMP].to_i
246
- elsif key[0,1] == "+"
247
- t = @data[TIMESTAMP]
248
- formatter = org.joda.time.format.DateTimeFormat.forPattern(key[1 .. -1])\
249
- .withZone(org.joda.time.DateTimeZone::UTC)
250
- #next org.joda.time.Instant.new(t.tv_sec * 1000 + t.tv_usec / 1000).toDateTime.toString(formatter)
251
- # Invoke a specific Instant constructor to avoid this warning in JRuby
252
- # > ambiguous Java methods found, using org.joda.time.Instant(long)
253
- org.joda.time.Instant.java_class.constructor(Java::long).new_instance(
254
- t.tv_sec * 1000 + t.tv_usec / 1000
255
- ).to_java.toDateTime.toString(formatter)
256
- else
257
- value = self[key]
258
- case value
259
- when nil
260
- tok # leave the %{foo} if this field does not exist in this event.
261
- when Array
262
- value.join(",") # Join by ',' if value is an array
263
- when Hash
264
- LogStash::Json.dump(value) # Convert hashes to json
265
- else
266
- value # otherwise return the value
267
- end # case value
268
- end # 'key' checking
269
- end # format.gsub...
270
- end # def sprintf
222
+ LogStash::StringInterpolation.evaluate(self, format)
223
+ end
271
224
 
272
225
  def tag(value)
273
226
  # Generalize this method for more usability
@@ -4,6 +4,7 @@ require "logstash/event"
4
4
  require "logstash/logging"
5
5
  require "logstash/plugin"
6
6
  require "logstash/config/mixin"
7
+ require "logstash/util/decorators"
7
8
 
8
9
  class LogStash::Filters::Base < LogStash::Plugin
9
10
  include LogStash::Config::Mixin
@@ -179,21 +180,7 @@ class LogStash::Filters::Base < LogStash::Plugin
179
180
  # matches the filter's conditions (right type, etc)
180
181
  protected
181
182
  def filter_matched(event)
182
- @add_field.each do |field, value|
183
- field = event.sprintf(field)
184
- value = [value] if !value.is_a?(Array)
185
- value.each do |v|
186
- v = event.sprintf(v)
187
- if event.include?(field)
188
- event[field] = [event[field]] if !event[field].is_a?(Array)
189
- event[field] << v
190
- else
191
- event[field] = v
192
- end
193
- @logger.debug? and @logger.debug("filters/#{self.class.name}: adding value to field",
194
- :field => field, :value => value)
195
- end
196
- end
183
+ LogStash::Util::Decorators.add_fields(@add_field,event,"filters/#{self.class.name}")
197
184
 
198
185
  @remove_field.each do |field|
199
186
  field = event.sprintf(field)
@@ -202,12 +189,7 @@ class LogStash::Filters::Base < LogStash::Plugin
202
189
  event.remove(field)
203
190
  end
204
191
 
205
- @add_tag.each do |tag|
206
- tag = event.sprintf(tag)
207
- @logger.debug? and @logger.debug("filters/#{self.class.name}: adding tag",
208
- :tag => tag)
209
- (event["tags"] ||= []) << tag
210
- end
192
+ LogStash::Util::Decorators.add_tags(@add_tag,event,"filters/#{self.class.name}")
211
193
 
212
194
  @remove_tag.each do |tag|
213
195
  break if event["tags"].nil?
@@ -5,6 +5,7 @@ require "logstash/plugin"
5
5
  require "logstash/logging"
6
6
  require "logstash/config/mixin"
7
7
  require "logstash/codecs/base"
8
+ require "logstash/util/decorators"
8
9
 
9
10
  # This is the base class for Logstash inputs.
10
11
  class LogStash::Inputs::Base < LogStash::Plugin
@@ -109,14 +110,8 @@ class LogStash::Inputs::Base < LogStash::Plugin
109
110
  # Only set 'type' if not already set. This is backwards-compatible behavior
110
111
  event["type"] = @type if @type && !event.include?("type")
111
112
 
112
- if @tags.any?
113
- event["tags"] ||= []
114
- event["tags"] += @tags
115
- end
116
-
117
- @add_field.each do |field, value|
118
- event[field] = value
119
- end
113
+ LogStash::Util::Decorators.add_fields(@add_field,event,"inputs/#{self.class.name}")
114
+ LogStash::Util::Decorators.add_tags(@tags,event,"inputs/#{self.class.name}")
120
115
  end
121
116
 
122
117
  protected
@@ -92,4 +92,8 @@ module java::util::Collection
92
92
  duped.addAll(other)
93
93
  duped
94
94
  end
95
- end
95
+
96
+ def inspect
97
+ "<#{self.class.name}:#{self.hashCode} #{self.to_a(&:inspect)}>"
98
+ end
99
+ end
@@ -16,6 +16,7 @@ class LogStash::Runner
16
16
 
17
17
  def main(args)
18
18
  require "logstash/util"
19
+ require "logstash/util/java_version"
19
20
  require "stud/trap"
20
21
  require "stud/task"
21
22
  @startup_interruption_trap = Stud::trap("INT") { puts "Interrupted"; exit 0 }
@@ -27,6 +28,9 @@ class LogStash::Runner
27
28
  return 1
28
29
  end
29
30
 
31
+ # Print a warning to STDERR for bad java versions
32
+ LogStash::Util::JavaVersion.warn_on_bad_java_version
33
+
30
34
  Stud::untrap("INT", @startup_interruption_trap)
31
35
 
32
36
  task = run(args)
@@ -0,0 +1,139 @@
1
+ require "thread_safe"
2
+ require "forwardable"
3
+
4
+ module LogStash
5
+ module StringInterpolation
6
+ extend self
7
+
8
+ # Floats outside of these upper and lower bounds are forcibly converted
9
+ # to scientific notation by Float#to_s
10
+ MIN_FLOAT_BEFORE_SCI_NOT = 0.0001
11
+ MAX_FLOAT_BEFORE_SCI_NOT = 1000000000000000.0
12
+
13
+ CACHE = ThreadSafe::Cache.new
14
+ TEMPLATE_TAG_REGEXP = /%\{[^}]+\}/
15
+
16
+ def evaluate(event, template)
17
+ if template.is_a?(Float) && (template < MIN_FLOAT_BEFORE_SCI_NOT || template >= MAX_FLOAT_BEFORE_SCI_NOT)
18
+ return ("%.15f" % template).sub(/0*$/,"")
19
+ end
20
+
21
+ template = template.to_s
22
+
23
+ return template if not_cachable?(template)
24
+
25
+ compiled = CACHE.get_or_default(template, nil) || CACHE.put(template, compile_template(template))
26
+ compiled.evaluate(event)
27
+ end
28
+
29
+ private
30
+ def not_cachable?(template)
31
+ template.index("%").nil?
32
+ end
33
+
34
+ def compile_template(template)
35
+ nodes = Template.new
36
+
37
+ position = 0
38
+ matches = template.to_enum(:scan, TEMPLATE_TAG_REGEXP).map { |m| $~ }
39
+
40
+ matches.each do |match|
41
+ tag = match[0][2..-2]
42
+ start = match.offset(0).first
43
+ nodes << StaticNode.new(template[position..(start-1)]) if start > 0
44
+ nodes << identify(tag)
45
+ position = match.offset(0).last
46
+ end
47
+
48
+ if position < template.size - 1
49
+ nodes << StaticNode.new(template[position..-1])
50
+ end
51
+
52
+ optimize(nodes)
53
+ end
54
+
55
+ def optimize(nodes)
56
+ nodes.size == 1 ? nodes.first : nodes
57
+ end
58
+
59
+ def identify(tag)
60
+ if tag == "+%s"
61
+ EpocNode.new
62
+ elsif tag[0, 1] == "+"
63
+ DateNode.new(tag[1..-1])
64
+ else
65
+ KeyNode.new(tag)
66
+ end
67
+ end
68
+ end
69
+
70
+ class Template
71
+ extend Forwardable
72
+ def_delegators :@nodes, :<<, :push, :size, :first
73
+
74
+ def initialize
75
+ @nodes = []
76
+ end
77
+
78
+ def evaluate(event)
79
+ @nodes.collect { |node| node.evaluate(event) }.join
80
+ end
81
+ end
82
+
83
+ class EpocNode
84
+ def evaluate(event)
85
+ t = event.timestamp
86
+ raise LogStash::Error, "Unable to format in string \"#{@format}\", #{LogStash::Event::TIMESTAMP} field not found" unless t
87
+ t.to_i.to_s
88
+ end
89
+ end
90
+
91
+ class StaticNode
92
+ def initialize(content)
93
+ @content = content
94
+ end
95
+
96
+ def evaluate(event)
97
+ @content
98
+ end
99
+ end
100
+
101
+ class KeyNode
102
+ def initialize(key)
103
+ @key = key
104
+ end
105
+
106
+ def evaluate(event)
107
+ value = event[@key]
108
+
109
+ case value
110
+ when nil
111
+ "%{#{@key}}"
112
+ when Array
113
+ value.join(",")
114
+ when Hash
115
+ Logstash::Json.dump(value)
116
+ else
117
+ value
118
+ end
119
+ end
120
+ end
121
+
122
+ class DateNode
123
+ def initialize(format)
124
+ @format = format
125
+ @formatter = org.joda.time.format.DateTimeFormat.forPattern(@format)
126
+ .withZone(org.joda.time.DateTimeZone::UTC)
127
+ end
128
+
129
+ def evaluate(event)
130
+ t = event.timestamp
131
+
132
+ raise LogStash::Error, "Unable to format in string \"#{@format}\", #{LogStash::Event::TIMESTAMP} field not found" unless t
133
+
134
+ org.joda.time.Instant.java_class.constructor(Java::long).new_instance(
135
+ t.tv_sec * 1000 + t.tv_usec / 1000
136
+ ).to_java.toDateTime.toString(@formatter)
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/namespace"
4
+ require "logstash/util"
5
+
6
+ module LogStash::Util
7
+
8
+ # Decorators provides common manipulation on the event data.
9
+ module Decorators
10
+ extend self
11
+
12
+ @logger = Cabin::Channel.get(LogStash)
13
+
14
+ # fields is a hash of field => value
15
+ # where both `field` and `value` can use sprintf syntax.
16
+ def add_fields(fields,event, pluginname)
17
+ fields.each do |field, value|
18
+ field = event.sprintf(field)
19
+ value = Array(value)
20
+ value.each do |v|
21
+ v = event.sprintf(v)
22
+ if event.include?(field)
23
+ event[field] = Array(event[field])
24
+ event[field] << v
25
+ else
26
+ event[field] = v
27
+ end
28
+ @logger.debug? and @logger.debug("#{pluginname}: adding value to field",
29
+ :field => field, :value => value)
30
+ end
31
+ end
32
+ end
33
+
34
+ # tags is an array of string. sprintf syntax can be used.
35
+ def add_tags(tags, event, pluginname)
36
+ tags.each do |tag|
37
+ tag = event.sprintf(tag)
38
+ @logger.debug? and @logger.debug("#{pluginname}: adding tag",
39
+ :tag => tag)
40
+ (event["tags"] ||= []) << tag
41
+ end
42
+ end
43
+
44
+ end # module LogStash::Util::Decorators
45
+
46
+ end # module LogStash::Util
@@ -0,0 +1,61 @@
1
+ require 'cabin'
2
+
3
+ module LogStash::Util::JavaVersion
4
+ def self.logger
5
+ @logger ||= Cabin::Channel.get(LogStash)
6
+ end
7
+
8
+ # Print a warning if we're on a bad version of java
9
+ def self.warn_on_bad_java_version
10
+ if self.bad_java_version?(self.version)
11
+ msg = "!!! Please upgrade your java version, the current version '#{self.version}' may cause problems. We recommend a minimum version of 1.7.0_51"
12
+ STDERR.puts(msg)
13
+ logger.warn(msg)
14
+ end
15
+ end
16
+
17
+ # Return the current java version string. Returns nil if this is a non-java platform (e.g. MRI).
18
+ def self.version
19
+ return nil unless LogStash::Environment.jruby?
20
+ java.lang.System.getProperty("java.runtime.version")
21
+ end
22
+
23
+ # Takes a string of a java version ex: "1.8.0_24-beta"
24
+ # and returns a parsed map of the components.
25
+ # nil inputs will be returned as nil.
26
+ def self.parse_java_version(version_string)
27
+ return nil if version_string.nil?
28
+
29
+ # Crazy java versioning rules @ http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
30
+ # The regex below parses this all correctly http://rubular.com/r/sInQc3Nc7f
31
+
32
+ match = version_string.match(/\A(\d+)\.(\d+)\.(\d+)(_(\d+))?(-(.+))?\Z/)
33
+ major, minor, patch, ufull, update, bfull, build = match.captures
34
+
35
+ {
36
+ :full => version_string,
37
+ :major => major.to_i,
38
+ :minor => minor.to_i,
39
+ :patch => patch.to_i,
40
+ :update => update.to_i, # this is always coerced to an int (a nil will be zero) to make comparisons easier
41
+ :build => build # not an integer, could be b06 for instance!,
42
+ }
43
+ end
44
+
45
+ # Determine if the given java version string is a bad version of java
46
+ # If it is, return true, if it isn't return false.
47
+ # Accepts nil, returning nil.
48
+ def self.bad_java_version?(version_string)
49
+ return nil if version_string.nil?
50
+
51
+ parsed = parse_java_version(version_string)
52
+
53
+ if parsed[:major] == 1 && parsed[:minor] == 7 && parsed[:patch] == 0 && parsed[:update] < 51
54
+ true
55
+ elsif parsed[:major] == 1 && parsed[:minor] < 7
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,80 @@
1
+ module UnicodeTrimmer
2
+ # The largest possible unicode chars are 4 bytes
3
+ # http://stackoverflow.com/questions/9533258/what-is-the-maximum-number-of-bytes-for-a-utf-8-encoded-character
4
+ # http://tools.ietf.org/html/rfc3629
5
+ MAX_CHAR_BYTES = 4
6
+
7
+ # Takes a unicode string and makes sure it fits in a max of `desired_bytes`
8
+ # This aims to be somewhat efficient about this for the average case and get as close to
9
+ # O(1) as possible. Given certain distributions of multi-byte characters it'll be slower
10
+ # It tries to find the point the truncation *should* happen based on the average byte size.
11
+ # If that snips it in the wrong place it'll try to add or remove chars to get it to the right
12
+ # spot and preserve as much data as possible.
13
+ public
14
+ def self.trim_bytes(orig_str, desired_bytes)
15
+ return orig_str if orig_str.bytesize <= desired_bytes
16
+
17
+ pre_shortened = pre_shorten(orig_str, desired_bytes)
18
+
19
+ case pre_shortened.bytesize <=> desired_bytes
20
+ when 0
21
+ pre_shortened
22
+ when 1
23
+ shrink_bytes(pre_shortened, orig_str, desired_bytes)
24
+ when -1
25
+ grow_bytes(pre_shortened, orig_str, desired_bytes)
26
+ end
27
+ end
28
+
29
+ private
30
+ # Try to cut the string at the right place based on the avg. byte size
31
+ def self.pre_shorten(orig_str, desired_bytes)
32
+ # Compute the average size to get an idea of where should chop
33
+ orig_len = orig_str.length
34
+ orig_bs = orig_str.bytesize
35
+ avg_size = (orig_bs.to_f / orig_len.to_f)
36
+
37
+ # Try to do an initial shortening based on the average char size
38
+ # The goal here is to get us somewhere above or below the boundary quickly
39
+ orig_extra_bytes = orig_bs - desired_bytes
40
+ pre_shorten_by = (orig_extra_bytes / avg_size).to_i
41
+ orig_str.slice(0, orig_len - pre_shorten_by)
42
+ end
43
+
44
+ private
45
+ def self.grow_bytes(pre_shortened, orig_str, desired_bytes)
46
+ res_str = pre_shortened.clone()
47
+
48
+ loop do
49
+ bs = res_str.bytesize
50
+ deficit = desired_bytes - bs
51
+ lengthen_by = deficit / MAX_CHAR_BYTES
52
+ lengthen_by = 1 if lengthen_by < 1
53
+ append = orig_str.slice(res_str.length, lengthen_by)
54
+
55
+ break if (bs + append.bytesize) > desired_bytes
56
+
57
+ res_str << append
58
+ end
59
+
60
+ res_str
61
+ end
62
+
63
+ private
64
+ def self.shrink_bytes(pre_shortened, orig_str, desired_bytes)
65
+ res_str = pre_shortened.clone()
66
+
67
+ loop do
68
+ bs = res_str.bytesize
69
+ break if bs <= desired_bytes
70
+
71
+ extra = bs - desired_bytes
72
+ shorten_by = extra / MAX_CHAR_BYTES
73
+ shorten_by = 1 if shorten_by < 1
74
+
75
+ res_str.slice!(res_str.length - shorten_by)
76
+ end
77
+
78
+ res_str
79
+ end
80
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # The version of logstash.
3
- LOGSTASH_VERSION = "1.5.1.snapshot1"
3
+ LOGSTASH_VERSION = "1.5.2"
4
4
 
5
5
  # Note to authors: this should not include dashes because 'gem' barfs if
6
6
  # you include a dash in the version string.
@@ -18,10 +18,11 @@ Gem::Specification.new do |gem|
18
18
  gem.version = LOGSTASH_VERSION.gsub(/-/, '.')
19
19
 
20
20
  gem.add_runtime_dependency "cabin", "~> 0.7.0" #(Apache 2.0 license)
21
- gem.add_runtime_dependency "pry", "~> 0.10.1" #(Ruby license)
21
+ gem.add_runtime_dependency "pry", "~> 0.10.1" #(Ruby license)
22
22
  gem.add_runtime_dependency "stud", "~> 0.0.19" #(Apache 2.0 license)
23
23
  gem.add_runtime_dependency "clamp", "~> 0.6.5" #(MIT license) for command line args/flags
24
24
  gem.add_runtime_dependency "filesize", "0.0.4" #(MIT license) for :bytes config validator
25
+ gem.add_runtime_dependency "gems", "~> 0.8.3" #(MIT license)
25
26
 
26
27
  # TODO(sissel): Treetop 1.5.x doesn't seem to work well, but I haven't
27
28
  # investigated what the cause might be. -Jordan
@@ -32,7 +33,6 @@ Gem::Specification.new do |gem|
32
33
 
33
34
  # filetools and rakelib
34
35
  gem.add_runtime_dependency "minitar", "~> 0.5.4"
35
-
36
36
  gem.add_runtime_dependency "thread_safe", "~> 0.3.5" #(Apache 2.0 license)
37
37
 
38
38
  if RUBY_PLATFORM == 'java'
@@ -63,6 +63,10 @@ describe LogStash::Event do
63
63
  expect(subject.sprintf("%{+HH}")).to eq("00")
64
64
  end
65
65
 
66
+ it "should support mixed string" do
67
+ expect(subject.sprintf("foo %{+YYYY-MM-dd} %{type}")).to eq("foo 2013-01-01 sprintf")
68
+ end
69
+
66
70
  it "should raise error with %{+format} syntax when @timestamp field is missing", :if => RUBY_ENGINE == "jruby" do
67
71
  str = "logstash-%{+YYYY}"
68
72
  subj = subject.clone
@@ -0,0 +1,14 @@
1
+ # Useful module to help loading all logstash content when
2
+ # running coverage analysis
3
+ module CoverageHelper
4
+
5
+ SKIP_LIST = ["lib/bootstrap/rspec.rb", "lib/logstash/util/prctl.rb"]
6
+
7
+ def self.eager_load
8
+ Dir.glob("lib/**/*.rb") do |file|
9
+ next if SKIP_LIST.include?(file)
10
+ require file
11
+ end
12
+ end
13
+
14
+ end
@@ -1,6 +1,67 @@
1
1
  # encoding: utf-8
2
2
  require "spec_helper"
3
3
 
4
+ # use a dummy NOOP input to test Inputs::Base
5
+ class LogStash::Inputs::NOOP < LogStash::Inputs::Base
6
+ config_name "noop"
7
+ milestone 2
8
+
9
+ def register; end
10
+
11
+ end
12
+
13
+ describe "LogStash::Inputs::Base#decorate" do
14
+ it "should add tag" do
15
+ input = LogStash::Inputs::NOOP.new("tags" => "value")
16
+ evt = LogStash::Event.new({"type" => "noop"})
17
+ input.instance_eval {decorate(evt)}
18
+ expect(evt["tags"]).to eq(["value"])
19
+ end
20
+
21
+ it "should add multiple tag" do
22
+ input = LogStash::Inputs::NOOP.new("tags" => ["value1","value2"])
23
+ evt = LogStash::Event.new({"type" => "noop"})
24
+ input.instance_eval {decorate(evt)}
25
+ expect(evt["tags"]).to eq(["value1","value2"])
26
+ end
27
+
28
+ it "should allow duplicates tag" do
29
+ input = LogStash::Inputs::NOOP.new("tags" => ["value","value"])
30
+ evt = LogStash::Event.new({"type" => "noop"})
31
+ input.instance_eval {decorate(evt)}
32
+ expect(evt["tags"]).to eq(["value","value"])
33
+ end
34
+
35
+ it "should add tag with sprintf" do
36
+ input = LogStash::Inputs::NOOP.new("tags" => "%{type}")
37
+ evt = LogStash::Event.new({"type" => "noop"})
38
+ input.instance_eval {decorate(evt)}
39
+ expect(evt["tags"]).to eq(["noop"])
40
+ end
41
+
42
+ it "should add single field" do
43
+ input = LogStash::Inputs::NOOP.new("add_field" => {"field" => "value"})
44
+ evt = LogStash::Event.new({"type" => "noop"})
45
+ input.instance_eval {decorate(evt)}
46
+ expect(evt["field"]).to eq("value")
47
+ end
48
+
49
+ it "should add single field with sprintf" do
50
+ input = LogStash::Inputs::NOOP.new("add_field" => {"%{type}" => "%{type}"})
51
+ evt = LogStash::Event.new({"type" => "noop"})
52
+ input.instance_eval {decorate(evt)}
53
+ expect(evt["noop"]).to eq("noop")
54
+ end
55
+
56
+ it "should add multiple field" do
57
+ input = LogStash::Inputs::NOOP.new("add_field" => {"field" => ["value1", "value2"], "field2" => "value"})
58
+ evt = LogStash::Event.new({"type" => "noop"})
59
+ input.instance_eval {decorate(evt)}
60
+ expect(evt["field"]).to eq(["value1","value2"])
61
+ expect(evt["field2"]).to eq("value")
62
+ end
63
+ end
64
+
4
65
  describe "LogStash::Inputs::Base#fix_streaming_codecs" do
5
66
  it "should carry the charset setting along when switching" do
6
67
  require "logstash/inputs/tcp"
@@ -82,6 +82,23 @@ describe "Java integration" do
82
82
  context "Java::JavaUtil::Collection" do
83
83
  subject{Java::JavaUtil::ArrayList.new(initial_array)}
84
84
 
85
+ context "when inspecting" do
86
+ let(:items) { [:a, {:b => :c}] }
87
+ subject { java.util.ArrayList.new(items) }
88
+
89
+ it "should include the contents of the Collection" do
90
+ expect(subject.inspect).to include(items.inspect)
91
+ end
92
+
93
+ it "should include the class name" do
94
+ expect(subject.inspect).to include("ArrayList")
95
+ end
96
+
97
+ it "should include the hash code of the collection" do
98
+ expect(subject.inspect).to include(subject.hashCode.to_s)
99
+ end
100
+ end
101
+
85
102
  context "when deleting a unique instance" do
86
103
  let(:initial_array) {["foo", "bar"]}
87
104
 
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+ require 'rakelib/default_plugins'
3
+
4
+ describe "Project licenses" do
5
+
6
+ let(:expected_licenses) {
7
+ ##
8
+ # Expected licenses are Apache License 2.0, BSD license, MIT license and the ruby one,
9
+ # this not exclude that this list change in the feature.
10
+ ##
11
+ Regexp.union([ /mit/,
12
+ /apache*/,
13
+ /bsd/,
14
+ /ruby/,
15
+ /lgpl/])
16
+ }
17
+
18
+ shared_examples "runtime license test" do
19
+
20
+ subject(:gem_name) do |example|
21
+ example.metadata[:example_group][:parent_example_group][:description]
22
+ end
23
+
24
+ let(:spec) { Gem::Specification.find_all_by_name(gem_name)[0] }
25
+
26
+ it "have an expected license" do
27
+ spec.licenses.each do |license|
28
+ expect(license.downcase).to match(expected_licenses)
29
+ end
30
+ end
31
+
32
+ it "has runtime dependencies with expected licenses" do
33
+ spec.runtime_dependencies.map { |dep| dep.to_spec }.each do |runtime_spec|
34
+ next unless runtime_spec
35
+ runtime_spec.licenses.each do |license|
36
+ expect(license.downcase).to match(expected_licenses)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "logstash-core" do
43
+ it_behaves_like "runtime license test"
44
+ end
45
+
46
+ installed_plugins.each do |plugin|
47
+ describe plugin do
48
+ it_behaves_like "runtime license test"
49
+ end
50
+ end
51
+
52
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,10 @@
1
+ require_relative 'coverage_helper'
2
+ # In order to archive an expected coverage analysis we need to eager load
3
+ # all logstash code base, otherwise it will not get a good analysis.
4
+ CoverageHelper.eager_load if ENV['COVERAGE']
5
+
1
6
  require "logstash/devutils/rspec/spec_helper"
7
+
8
+ def installed_plugins
9
+ Gem::Specification.find_all.select { |spec| spec.metadata["logstash_plugin"] }.map { |plugin| plugin.name }
10
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'logstash/util/java_version'
3
+
4
+ describe "LogStash::Util::JavaVersion" do
5
+ subject(:mod) { LogStash::Util::JavaVersion }
6
+
7
+ it "should get the current java version if we're on Java" do
8
+ if LogStash::Environment.jruby?
9
+ expect(LogStash::Util::JavaVersion.version).to be_a(String)
10
+ end
11
+ end
12
+
13
+ it "should mark a bad beta version as bad" do
14
+ expect(mod.bad_java_version?("1.7.0_45-beta")).to be_truthy
15
+ end
16
+
17
+ it "should mark a bad standard version as bad" do
18
+ expect(mod.bad_java_version?("1.6.0")).to be_truthy
19
+ end
20
+
21
+ it "should mark a good standard java version as good" do
22
+ expect(mod.bad_java_version?("1.7.0_51")).to be_falsey
23
+ end
24
+
25
+ it "should mark a good beta version as good" do
26
+ expect(mod.bad_java_version?("1.8.0-beta")).to be_falsey
27
+ end
28
+
29
+ describe "parsing java versions" do
30
+ it "should return nil on a nil version" do
31
+ expect(mod.parse_java_version(nil)).to be_nil
32
+ end
33
+
34
+ shared_examples("version parsing") do |desc, string, major, minor, patch, update, build|
35
+ context("#{desc} with version #{string}") do
36
+ subject(:parsed) { LogStash::Util::JavaVersion.parse_java_version(string) }
37
+
38
+ it "should have the correct major version" do
39
+ expect(parsed[:major]).to eql(major)
40
+ end
41
+
42
+ it "should have the correct minor version" do
43
+ expect(parsed[:minor]).to eql(minor)
44
+ end
45
+
46
+ it "should have the correct patch version" do
47
+ expect(parsed[:patch]).to eql(patch)
48
+ end
49
+
50
+ it "should have the correct update version" do
51
+ expect(parsed[:update]).to eql(update)
52
+ end
53
+
54
+ it "should have the correct build string" do
55
+ expect(parsed[:build]).to eql(build)
56
+ end
57
+ end
58
+ end
59
+
60
+ include_examples("version parsing", "a plain version", "1.3.0", 1, 3, 0, 0, nil)
61
+ include_examples("version parsing", "an update", "1.4.0_03", 1, 4, 0, 3, nil)
62
+ include_examples("version parsing", "a build", "1.4.0-beta", 1, 4, 0, 0,"beta")
63
+ include_examples("version parsing", "an update+build", "1.4.0_03-beta", 1, 4, 0, 3, "beta")
64
+ end
65
+
66
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/util/unicode_trimmer"
4
+ require "flores/rspec"
5
+ require "flores/random"
6
+
7
+ RSpec.configure do |config|
8
+ Flores::RSpec.configure(config)
9
+ end
10
+
11
+ describe "truncating unicode strings correctly" do
12
+ context "with extra bytes before the snip" do
13
+ let(:ustr) { "Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!" }
14
+
15
+ it "should truncate to exact byte boundaries when possible" do
16
+ expect(UnicodeTrimmer.trim_bytes(ustr, 21).bytesize).to eql(21)
17
+ end
18
+
19
+ it "should truncate below the bytesize when splitting a byte" do
20
+ expect(UnicodeTrimmer.trim_bytes(ustr, 20).bytesize).to eql(18)
21
+ end
22
+
23
+ it "should not truncate the string when the bytesize is already OK" do
24
+ expect(UnicodeTrimmer.trim_bytes(ustr, ustr.bytesize)).to eql(ustr)
25
+ end
26
+ end
27
+
28
+ context "with extra bytes after the snip" do
29
+ let(:ustr) { ": 1<2 & 4+1>3, now 20% off! testing «ταБЬℓσ»" }
30
+
31
+ it "should truncate to exact byte boundaries when possible" do
32
+ expect(UnicodeTrimmer.trim_bytes(ustr, 21).bytesize).to eql(21)
33
+ end
34
+
35
+ it "should truncate below the bytesize when splitting a byte" do
36
+ expect(UnicodeTrimmer.trim_bytes(ustr, 52).bytesize).to eql(51)
37
+ end
38
+
39
+ it "should not truncate the string when the bytesize is already OK" do
40
+ expect(UnicodeTrimmer.trim_bytes(ustr, ustr.bytesize)).to eql(ustr)
41
+ end
42
+ end
43
+
44
+ context "randomized testing" do
45
+ let(:text) { Flores::Random.text(1..1000) }
46
+ let(:size) { Flores::Random.integer(1..text.bytesize) }
47
+ let(:expected_range) { (size - 4)..size }
48
+
49
+ stress_it "should be near the boundary of requested size" do
50
+ expect(expected_range).to include(UnicodeTrimmer.trim_bytes(text, size).bytesize)
51
+ end
52
+ end
53
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1.snapshot1
4
+ version: 1.5.2
5
5
  platform: java
6
6
  authors:
7
7
  - Jordan Sissel
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-06-11 00:00:00.000000000 Z
13
+ date: 2015-06-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: cabin
@@ -82,6 +82,20 @@ dependencies:
82
82
  version: 0.0.4
83
83
  prerelease: false
84
84
  type: :runtime
85
+ - !ruby/object:Gem::Dependency
86
+ name: gems
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ~>
90
+ - !ruby/object:Gem::Version
91
+ version: 0.8.3
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 0.8.3
97
+ prerelease: false
98
+ type: :runtime
85
99
  - !ruby/object:Gem::Dependency
86
100
  name: treetop
87
101
  version_requirements: !ruby/object:Gem::Requirement
@@ -192,20 +206,23 @@ files:
192
206
  - lib/logstash/program.rb
193
207
  - lib/logstash/runner.rb
194
208
  - lib/logstash/sized_queue.rb
209
+ - lib/logstash/string_interpolation.rb
195
210
  - lib/logstash/threadwatchdog.rb
196
211
  - lib/logstash/timestamp.rb
197
212
  - lib/logstash/util.rb
198
213
  - lib/logstash/util/accessors.rb
199
214
  - lib/logstash/util/buftok.rb
200
215
  - lib/logstash/util/charset.rb
201
- - lib/logstash/util/fieldreference.rb
216
+ - lib/logstash/util/decorators.rb
202
217
  - lib/logstash/util/filetools.rb
218
+ - lib/logstash/util/java_version.rb
203
219
  - lib/logstash/util/password.rb
204
220
  - lib/logstash/util/plugin_version.rb
205
221
  - lib/logstash/util/prctl.rb
206
222
  - lib/logstash/util/require-helper.rb
207
223
  - lib/logstash/util/retryable.rb
208
224
  - lib/logstash/util/socket_peer.rb
225
+ - lib/logstash/util/unicode_trimmer.rb
209
226
  - lib/logstash/version.rb
210
227
  - locales/en.yml
211
228
  - logstash-core.gemspec
@@ -218,19 +235,22 @@ files:
218
235
  - spec/core/plugin_spec.rb
219
236
  - spec/core/runner_spec.rb
220
237
  - spec/core/timestamp_spec.rb
238
+ - spec/coverage_helper.rb
221
239
  - spec/filters/base_spec.rb
222
240
  - spec/inputs/base_spec.rb
223
241
  - spec/lib/logstash/bundler_spec.rb
224
242
  - spec/lib/logstash/java_integration_spec.rb
243
+ - spec/license_spec.rb
225
244
  - spec/logstash/agent_spec.rb
226
245
  - spec/outputs/base_spec.rb
227
246
  - spec/spec_helper.rb
228
247
  - spec/util/accessors_spec.rb
229
248
  - spec/util/charset_spec.rb
230
- - spec/util/fieldeval_spec.rb
231
249
  - spec/util/gemfile_spec.rb
250
+ - spec/util/java_version_spec.rb
232
251
  - spec/util/json_spec.rb
233
252
  - spec/util/plugin_version_spec.rb
253
+ - spec/util/unicode_trimmer_spec.rb
234
254
  - spec/util_spec.rb
235
255
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
236
256
  licenses:
@@ -247,9 +267,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
247
267
  version: '0'
248
268
  required_rubygems_version: !ruby/object:Gem::Requirement
249
269
  requirements:
250
- - - '>'
270
+ - - '>='
251
271
  - !ruby/object:Gem::Version
252
- version: 1.3.1
272
+ version: '0'
253
273
  requirements: []
254
274
  rubyforge_project:
255
275
  rubygems_version: 2.2.2
@@ -266,17 +286,20 @@ test_files:
266
286
  - spec/core/plugin_spec.rb
267
287
  - spec/core/runner_spec.rb
268
288
  - spec/core/timestamp_spec.rb
289
+ - spec/coverage_helper.rb
269
290
  - spec/filters/base_spec.rb
270
291
  - spec/inputs/base_spec.rb
271
292
  - spec/lib/logstash/bundler_spec.rb
272
293
  - spec/lib/logstash/java_integration_spec.rb
294
+ - spec/license_spec.rb
273
295
  - spec/logstash/agent_spec.rb
274
296
  - spec/outputs/base_spec.rb
275
297
  - spec/spec_helper.rb
276
298
  - spec/util/accessors_spec.rb
277
299
  - spec/util/charset_spec.rb
278
- - spec/util/fieldeval_spec.rb
279
300
  - spec/util/gemfile_spec.rb
301
+ - spec/util/java_version_spec.rb
280
302
  - spec/util/json_spec.rb
281
303
  - spec/util/plugin_version_spec.rb
304
+ - spec/util/unicode_trimmer_spec.rb
282
305
  - spec/util_spec.rb
@@ -1,68 +0,0 @@
1
- # encoding: utf-8
2
- require "logstash/namespace"
3
- require "logstash/util"
4
-
5
- module LogStash::Util::FieldReference
6
-
7
- def compile(accessor)
8
- if accessor[0,1] != '['
9
- return <<-"CODE"
10
- lambda do |store, &block|
11
- return block.nil? ? store[#{accessor.inspect}] : block.call(store, #{accessor.inspect})
12
- end
13
- CODE
14
- end
15
-
16
- code = "lambda do |store, &block|\n"
17
- selectors = accessor.scan(/(?<=\[).+?(?=\])/)
18
- selectors.each_with_index do |tok, i|
19
- last = (i == selectors.count() - 1)
20
- code << " # [#{tok}]#{ last ? " (last selector)" : "" }\n"
21
-
22
- if last
23
- code << <<-"CODE"
24
- return block.call(store, #{tok.inspect}) unless block.nil?
25
- CODE
26
- end
27
-
28
- code << <<-"CODE"
29
- store = store.is_a?(Array) ? store[#{tok.to_i}] : store[#{tok.inspect}]
30
- return store if store.nil?
31
- CODE
32
-
33
- end
34
- code << "return store\nend"
35
- #puts code
36
- return code
37
- end # def compile
38
-
39
- def exec(accessor, store, &block)
40
- @__fieldeval_cache ||= {}
41
- @__fieldeval_cache[accessor] ||= eval(compile(accessor))
42
- return @__fieldeval_cache[accessor].call(store, &block)
43
- end
44
-
45
- def set(accessor, value, store)
46
- # The assignment can fail if the given field reference (accessor) does not exist
47
- # In this case, we'll want to set the value manually.
48
- if exec(accessor, store) { |hash, key| hash[key] = value }.nil?
49
- return (store[accessor] = value) if accessor[0,1] != "["
50
-
51
- # No existing element was found, so let's set one.
52
- *parents, key = accessor.scan(/(?<=\[)[^\]]+(?=\])/)
53
- parents.each do |p|
54
- if store.include?(p)
55
- store = store[p]
56
- else
57
- store[p] = {}
58
- store = store[p]
59
- end
60
- end
61
- store[key] = value
62
- end
63
-
64
- return value
65
- end
66
-
67
- extend self
68
- end # module LogStash::Util::FieldReference
@@ -1,96 +0,0 @@
1
- require "spec_helper"
2
- require "logstash/util/fieldreference"
3
-
4
- describe LogStash::Util::FieldReference, :if => true do
5
-
6
- context "using simple accessor" do
7
-
8
- it "should retrieve value" do
9
- str = "hello"
10
- m = eval(subject.compile(str))
11
- data = { "hello" => "world" }
12
- expect(m.call(data)).to eq(data[str])
13
- end
14
-
15
- it "should handle delete in block" do
16
- str = "simple"
17
- m = eval(subject.compile(str))
18
- data = { "simple" => "things" }
19
- m.call(data) { |obj, key| obj.delete(key) }
20
- expect(data).to be_empty
21
- end
22
-
23
- it "should handle assignment in block" do
24
- str = "simple"
25
- m = eval(subject.compile(str))
26
- data = {}
27
- expect(m.call(data) { |obj, key| obj[key] = "things" }).to eq("things")
28
- expect(data).to eq({ "simple" => "things" })
29
- end
30
-
31
- it "should handle assignment using set" do
32
- str = "simple"
33
- data = {}
34
- expect(subject.set(str, "things", data)).to eq("things")
35
- expect(data).to eq({ "simple" => "things" })
36
- end
37
- end
38
-
39
- context "using accessor path" do
40
-
41
- it "should retrieve shallow value" do
42
- str = "[hello]"
43
- m = eval(subject.compile(str))
44
- data = { "hello" => "world" }
45
- expect(m.call(data)).to eq("world")
46
- end
47
-
48
- it "should retrieve deep value" do
49
- str = "[hello][world]"
50
- m = eval(subject.compile(str))
51
- data = { "hello" => { "world" => "foo", "bar" => "baz" } }
52
- expect(m.call(data)).to eq(data["hello"]["world"])
53
- end
54
-
55
- it "should handle delete in block" do
56
- str = "[hello][world]"
57
- m = eval(subject.compile(str))
58
- data = { "hello" => { "world" => "foo", "bar" => "baz" } }
59
- m.call(data) { |obj, key| obj.delete(key) }
60
-
61
- # Make sure the "world" key is removed.
62
- expect(data["hello"]).to eq({ "bar" => "baz" })
63
- end
64
-
65
- it "should not handle assignment in block" do
66
- str = "[hello][world]"
67
- m = eval(subject.compile(str))
68
- data = {}
69
- expect(m.call(data) { |obj, key| obj[key] = "things" }).to be_nil
70
- expect(data).to be_empty
71
- end
72
-
73
- it "should set shallow value" do
74
- str = "[hello]"
75
- data = {}
76
- expect(subject.set(str, "foo", data)).to eq("foo")
77
- expect(data).to eq({ "hello" => "foo" })
78
- end
79
-
80
- it "should set deep value" do
81
- str = "[hello][world]"
82
- data = {}
83
- expect(subject.set(str, "foo", data)).to eq("foo")
84
- expect(data).to eq({ "hello" => { "world" => "foo" } })
85
- end
86
-
87
- it "should retrieve array item" do
88
- data = { "hello" => { "world" => ["a", "b"], "bar" => "baz" } }
89
- m = eval(subject.compile("[hello][world][0]"))
90
- expect(m.call(data)).to eq(data["hello"]["world"][0])
91
-
92
- m = eval(subject.compile("[hello][world][1]"))
93
- expect(m.call(data)).to eq(data["hello"]["world"][1])
94
- end
95
- end
96
- end