logstash-core 2.0.1.snapshot1-java → 2.1.0-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.

@@ -24,6 +24,41 @@ module LogStash::Util
24
24
  end
25
25
  end # def set_thread_name
26
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
+
27
62
  # Merge hash 'src' into 'dst' nondestructively
28
63
  #
29
64
  # Duplicate keys will become array values
@@ -20,7 +20,7 @@ module LogStash module Util class DefaultsPrinter
20
20
  @printers.each do |printer|
21
21
  printer.visit(collector)
22
22
  end
23
- "Default settings used: " + collector.join(', ')
23
+ "Settings: " + collector.join(', ')
24
24
  end
25
25
 
26
26
  private
@@ -6,11 +6,23 @@ require "logstash/util"
6
6
  module LogStash module Util class WorkerThreadsDefaultPrinter
7
7
 
8
8
  def initialize(settings)
9
- @setting = settings.fetch('filter-workers', 1)
9
+ @setting = settings.fetch('filter-workers', 0)
10
+ @default = settings.fetch('default-filter-workers', 0)
10
11
  end
11
12
 
12
13
  def visit(collector)
13
- collector.push "Filter workers: #{@setting}"
14
+ visit_setting(collector)
15
+ visit_default(collector)
16
+ end
17
+
18
+ def visit_setting(collector)
19
+ return if @setting == 0
20
+ collector.push("User set filter workers: #{@setting}")
21
+ end
22
+
23
+ def visit_default(collector)
24
+ return if @default == 0
25
+ collector.push "Default filter workers: #{@default}"
14
26
  end
15
27
 
16
28
  end end end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # The version of logstash.
3
- LOGSTASH_VERSION = "2.0.1.snapshot1"
3
+ LOGSTASH_VERSION = "2.1.0"
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.
@@ -187,3 +187,8 @@ en:
187
187
  debug: |+
188
188
  Most verbose logging. This causes 'debug'
189
189
  level logs to be emitted.
190
+ unsafe_shutdown: |+
191
+ Force logstash to exit during shutdown even
192
+ if there are still inflight events in memory.
193
+ By default, logstash will refuse to quit until all
194
+ received events have been pushed to the outputs.
@@ -23,7 +23,7 @@ Gem::Specification.new do |gem|
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
25
  gem.add_runtime_dependency "gems", "~> 0.8.3" #(MIT license)
26
- gem.add_runtime_dependency "concurrent-ruby", "~> 0.9.1"
26
+ gem.add_runtime_dependency "concurrent-ruby", "0.9.2"
27
27
  gem.add_runtime_dependency "jruby-openssl", ">= 0.9.11" # Required to support TLSv1.2
28
28
 
29
29
  # TODO(sissel): Treetop 1.5.x doesn't seem to work well, but I haven't
@@ -35,6 +35,7 @@ Gem::Specification.new do |gem|
35
35
 
36
36
  # filetools and rakelib
37
37
  gem.add_runtime_dependency "minitar", "~> 0.5.4"
38
+ gem.add_runtime_dependency "rubyzip", "~> 1.1.7"
38
39
  gem.add_runtime_dependency "thread_safe", "~> 0.3.5" #(Apache 2.0 license)
39
40
 
40
41
  if RUBY_PLATFORM == 'java'
@@ -496,4 +496,23 @@ describe LogStash::Event do
496
496
  subject{LogStash::Event.new(LogStash::Json.load(LogStash::Json.dump(event_hash)))}
497
497
  end
498
498
  end
499
+
500
+
501
+ describe "#to_s" do
502
+ let(:timestamp) { LogStash::Timestamp.new }
503
+ let(:event1) { LogStash::Event.new({ "@timestamp" => timestamp, "host" => "foo", "message" => "bar"}) }
504
+ let(:event2) { LogStash::Event.new({ "host" => "bar", "message" => "foo"}) }
505
+
506
+ it "should cache only one template" do
507
+ LogStash::StringInterpolation::CACHE.clear
508
+ expect {
509
+ event1.to_s
510
+ event2.to_s
511
+ }.to change { LogStash::StringInterpolation::CACHE.size }.by(1)
512
+ end
513
+
514
+ it "return the string containing the timestamp, the host and the message" do
515
+ expect(event1.to_s).to eq("#{timestamp.to_iso8601} #{event1["host"]} #{event1["message"]}")
516
+ end
517
+ end
499
518
  end
@@ -53,20 +53,127 @@ class DummyOutput < LogStash::Outputs::Base
53
53
  end
54
54
  end
55
55
 
56
+ class DummyFilter < LogStash::Filters::Base
57
+ config_name "dummyfilter"
58
+ milestone 2
59
+
60
+ def register() end
61
+
62
+ def filter(event) end
63
+
64
+ def threadsafe?() false; end
65
+
66
+ def close() end
67
+ end
68
+
69
+ class DummySafeFilter < LogStash::Filters::Base
70
+ config_name "dummysafefilter"
71
+ milestone 2
72
+
73
+ def register() end
74
+
75
+ def filter(event) end
76
+
77
+ def threadsafe?() true; end
78
+
79
+ def close() end
80
+ end
81
+
56
82
  class TestPipeline < LogStash::Pipeline
57
- attr_reader :outputs
83
+ attr_reader :outputs, :filter_threads, :settings, :logger
58
84
  end
59
85
 
60
86
  describe LogStash::Pipeline do
87
+ let(:worker_thread_count) { 8 }
88
+ let(:safe_thread_count) { 1 }
89
+ let(:override_thread_count) { 42 }
90
+
91
+ describe "defaulting the filter workers based on thread safety" do
92
+ before(:each) do
93
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
94
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
95
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
96
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummyfilter").and_return(DummyFilter)
97
+ allow(LogStash::Plugin).to receive(:lookup).with("filter", "dummysafefilter").and_return(DummySafeFilter)
98
+ allow(LogStash::Config::CpuCoreStrategy).to receive(:fifty_percent).and_return(worker_thread_count)
99
+ end
100
+
101
+ context "when there are some not threadsafe filters" do
102
+ let(:test_config_with_filters) {
103
+ <<-eos
104
+ input {
105
+ dummyinput {}
106
+ }
107
+
108
+ filter {
109
+ dummyfilter {}
110
+ }
111
+
112
+ output {
113
+ dummyoutput {}
114
+ }
115
+ eos
116
+ }
117
+
118
+ context "when there is no command line -w N set" do
119
+ it "starts one filter thread" do
120
+ msg = "Defaulting filter worker threads to 1 because there are some" +
121
+ " filters that might not work with multiple worker threads"
122
+ pipeline = TestPipeline.new(test_config_with_filters)
123
+ expect(pipeline.logger).to receive(:warn).with(msg,
124
+ {:count_was=>worker_thread_count, :filters=>["dummyfilter"]})
125
+ pipeline.run
126
+ expect(pipeline.filter_threads.size).to eq(safe_thread_count)
127
+ end
128
+ end
129
+
130
+ context "when there is command line -w N set" do
131
+ it "starts multiple filter thread" do
132
+ msg = "Warning: Manual override - there are filters that might" +
133
+ " not work with multiple worker threads"
134
+ pipeline = TestPipeline.new(test_config_with_filters)
135
+ expect(pipeline.logger).to receive(:warn).with(msg,
136
+ {:worker_threads=> override_thread_count, :filters=>["dummyfilter"]})
137
+ pipeline.configure("filter-workers", override_thread_count)
138
+ pipeline.run
139
+ expect(pipeline.filter_threads.size).to eq(override_thread_count)
140
+ end
141
+ end
142
+ end
143
+
144
+ context "when there are threadsafe filters only" do
145
+ let(:test_config_with_filters) {
146
+ <<-eos
147
+ input {
148
+ dummyinput {}
149
+ }
150
+
151
+ filter {
152
+ dummysafefilter {}
153
+ }
61
154
 
62
- context "close" do
155
+ output {
156
+ dummyoutput {}
157
+ }
158
+ eos
159
+ }
63
160
 
64
- before(:each) do
65
- allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
66
- allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
67
- allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
161
+ it "starts multiple filter threads" do
162
+ pipeline = TestPipeline.new(test_config_with_filters)
163
+ pipeline.run
164
+ expect(pipeline.filter_threads.size).to eq(worker_thread_count)
165
+ end
166
+ end
68
167
  end
69
168
 
169
+ context "close" do
170
+ before(:each) do
171
+ allow(LogStash::Plugin).to receive(:lookup).with("input", "dummyinput").and_return(DummyInput)
172
+ allow(LogStash::Plugin).to receive(:lookup).with("codec", "plain").and_return(DummyCodec)
173
+ allow(LogStash::Plugin).to receive(:lookup).with("output", "dummyoutput").and_return(DummyOutput)
174
+ end
175
+
176
+
70
177
  let(:test_config_without_output_workers) {
71
178
  <<-eos
72
179
  input {
@@ -191,6 +298,5 @@ context "close" do
191
298
  expect(subject[2]["foo"]).to eq("bar")
192
299
  end
193
300
  end
194
-
195
301
  end
196
302
  end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+ require "logstash/shutdown_controller"
4
+
5
+ describe LogStash::ShutdownController do
6
+
7
+ let(:check_every) { 0.01 }
8
+ let(:check_threshold) { 100 }
9
+ subject { LogStash::ShutdownController.new(pipeline, check_every) }
10
+ let(:pipeline) { double("pipeline") }
11
+ report_count = 0
12
+
13
+ before :each do
14
+ allow(LogStash::Report).to receive(:from_pipeline).and_wrap_original do |m, *args|
15
+ report_count += 1
16
+ m.call(*args)
17
+ end
18
+ end
19
+
20
+ after :each do
21
+ report_count = 0
22
+ end
23
+
24
+ context "when pipeline is stalled" do
25
+ let(:increasing_count) { (1..5000).to_a.map {|i| { "total" => i } } }
26
+ before :each do
27
+ allow(pipeline).to receive(:inflight_count).and_return(*increasing_count)
28
+ allow(pipeline).to receive(:stalling_threads) { { } }
29
+ end
30
+
31
+ describe ".unsafe_shutdown = true" do
32
+ let(:abort_threshold) { subject.abort_threshold }
33
+ let(:report_every) { subject.report_every }
34
+
35
+ before :each do
36
+ subject.class.unsafe_shutdown = true
37
+ end
38
+
39
+ it "should force the shutdown" do
40
+ expect(subject).to receive(:force_exit).once
41
+ subject.start
42
+ end
43
+
44
+ it "should do exactly \"abort_threshold\" stall checks" do
45
+ allow(subject).to receive(:force_exit)
46
+ expect(subject).to receive(:shutdown_stalled?).exactly(abort_threshold).times.and_call_original
47
+ subject.start
48
+ end
49
+
50
+ it "should do exactly \"abort_threshold\"*\"report_every\" stall checks" do
51
+ allow(subject).to receive(:force_exit)
52
+ expect(LogStash::Report).to receive(:from_pipeline).exactly(abort_threshold*report_every).times.and_call_original
53
+ subject.start
54
+ end
55
+ end
56
+
57
+ describe ".unsafe_shutdown = false" do
58
+
59
+ before :each do
60
+ subject.class.unsafe_shutdown = false
61
+ end
62
+
63
+ it "shouldn't force the shutdown" do
64
+ expect(subject).to_not receive(:force_exit)
65
+ thread = Thread.new(subject) {|subject| subject.start }
66
+ sleep 0.1 until report_count > check_threshold
67
+ thread.kill
68
+ end
69
+ end
70
+ end
71
+
72
+ context "when pipeline is not stalled" do
73
+ let(:decreasing_count) { (1..5000).to_a.reverse.map {|i| { "total" => i } } }
74
+ before :each do
75
+ allow(pipeline).to receive(:inflight_count).and_return(*decreasing_count)
76
+ allow(pipeline).to receive(:stalling_threads) { { } }
77
+ end
78
+
79
+ describe ".unsafe_shutdown = true" do
80
+
81
+ before :each do
82
+ subject.class.unsafe_shutdown = true
83
+ end
84
+
85
+ it "should force the shutdown" do
86
+ expect(subject).to_not receive(:force_exit)
87
+ thread = Thread.new(subject) {|subject| subject.start }
88
+ sleep 0.1 until report_count > check_threshold
89
+ thread.kill
90
+ end
91
+ end
92
+
93
+ describe ".unsafe_shutdown = false" do
94
+
95
+ before :each do
96
+ subject.class.unsafe_shutdown = false
97
+ end
98
+
99
+ it "shouldn't force the shutdown" do
100
+ expect(subject).to_not receive(:force_exit)
101
+ thread = Thread.new(subject) {|subject| subject.start }
102
+ sleep 0.1 until report_count > check_threshold
103
+ thread.kill
104
+ end
105
+ end
106
+ end
107
+ end
@@ -12,6 +12,7 @@ describe "Project licenses" do
12
12
  Regexp.union([ /mit/,
13
13
  /apache*/,
14
14
  /bsd/,
15
+ /artistic 2.*/,
15
16
  /ruby/,
16
17
  /lgpl/])
17
18
  }
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'pluginmanager/main'
4
+
5
+ describe LogStash::PluginManager::Install do
6
+ let(:cmd) { LogStash::PluginManager::Install.new("install") }
7
+
8
+ before(:each) do
9
+ expect(cmd).to receive(:validate_cli_options!).and_return(nil)
10
+ end
11
+
12
+ context "when validating plugins" do
13
+ let(:sources) { ["https://rubygems.org", "http://localhost:9292"] }
14
+
15
+ before(:each) do
16
+ expect(cmd).to receive(:plugins_gems).and_return([["dummy", nil]])
17
+ expect(cmd).to receive(:install_gems_list!).and_return(nil)
18
+ expect(cmd).to receive(:remove_unused_locally_installed_gems!).and_return(nil)
19
+ cmd.verify = true
20
+ end
21
+
22
+ it "should load all the sources defined in the Gemfile" do
23
+ expect(cmd.gemfile.gemset).to receive(:sources).and_return(sources)
24
+ expect(LogStash::PluginManager).to receive(:logstash_plugin?).with("dummy", nil, {:rubygems_source => sources}).and_return(true)
25
+ cmd.execute
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'pluginmanager/main'
4
+
5
+ describe LogStash::PluginManager::Update do
6
+ let(:cmd) { LogStash::PluginManager::Update.new("update") }
7
+ let(:sources) { cmd.gemfile.gemset.sources }
8
+
9
+ before(:each) do
10
+ expect(cmd).to receive(:find_latest_gem_specs).and_return({})
11
+ allow(cmd).to receive(:warn_local_gems).and_return(nil)
12
+ expect(cmd).to receive(:display_updated_plugins).and_return(nil)
13
+ expect_any_instance_of(LogStash::Bundler).to receive(:invoke!).with(:clean => true)
14
+ end
15
+
16
+ it "pass all gem sources to the bundle update command" do
17
+ sources = cmd.gemfile.gemset.sources
18
+ expect_any_instance_of(LogStash::Bundler).to receive(:invoke!).with(:update => [], :rubygems_source => sources)
19
+ cmd.execute
20
+ end
21
+
22
+ context "when skipping validation" do
23
+ let(:cmd) { LogStash::PluginManager::Update.new("update") }
24
+ let(:plugin) { OpenStruct.new(:name => "dummy", :options => {} ) }
25
+
26
+ before(:each) do
27
+ expect(cmd.gemfile).to receive(:find).with(plugin).and_return(plugin)
28
+ expect(cmd.gemfile).to receive(:save).and_return(nil)
29
+ expect(cmd).to receive(:plugins_to_update).and_return([plugin])
30
+ expect_any_instance_of(LogStash::Bundler).to receive(:invoke!).with(:update => [plugin], :rubygems_source => sources).and_return(nil)
31
+ end
32
+
33
+ it "skips version verification when ask for it" do
34
+ cmd.verify = false
35
+ expect(cmd).to_not receive(:validates_version)
36
+ cmd.execute
37
+ end
38
+ end
39
+ end