logstash-core 1.5.1.snapshot1-java → 1.5.2-java

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.

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