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