logstash-core 5.0.0.alpha2.snapshot2-java → 5.0.0.alpha3-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.

Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/lib/logstash-core/version.rb +1 -1
  3. data/lib/logstash/agent.rb +48 -31
  4. data/lib/logstash/api/{lib/helpers/app_helpers.rb → app_helpers.rb} +0 -0
  5. data/lib/logstash/api/command_factory.rb +34 -0
  6. data/lib/logstash/api/commands/base.rb +25 -0
  7. data/lib/logstash/api/commands/stats.rb +105 -0
  8. data/lib/logstash/api/commands/system/basicinfo_command.rb +23 -0
  9. data/lib/logstash/api/commands/system/plugins_command.rb +35 -0
  10. data/lib/logstash/api/modules/base.rb +43 -0
  11. data/lib/logstash/api/modules/node.rb +24 -0
  12. data/lib/logstash/api/modules/node_stats.rb +59 -0
  13. data/lib/logstash/api/modules/plugins.rb +15 -0
  14. data/lib/logstash/api/modules/root.rb +15 -0
  15. data/lib/logstash/api/modules/stats.rb +63 -0
  16. data/lib/logstash/api/rack_app.rb +33 -0
  17. data/lib/logstash/api/service.rb +73 -0
  18. data/lib/logstash/config/config_ast.rb +23 -18
  19. data/lib/logstash/config/loader.rb +4 -4
  20. data/lib/logstash/config/mixin.rb +10 -21
  21. data/lib/logstash/environment.rb +29 -0
  22. data/lib/logstash/filters/base.rb +2 -2
  23. data/lib/logstash/inputs/base.rb +2 -2
  24. data/lib/logstash/instrument/collector.rb +1 -1
  25. data/lib/logstash/instrument/metric_store.rb +11 -1
  26. data/lib/logstash/instrument/periodic_poller/base.rb +2 -0
  27. data/lib/logstash/instrument/periodic_poller/jvm.rb +47 -2
  28. data/lib/logstash/logging/json.rb +21 -0
  29. data/lib/logstash/output_delegator.rb +2 -2
  30. data/lib/logstash/patches/clamp.rb +69 -0
  31. data/lib/logstash/pipeline.rb +36 -69
  32. data/lib/logstash/plugin.rb +1 -1
  33. data/lib/logstash/runner.rb +171 -146
  34. data/lib/logstash/settings.rb +267 -0
  35. data/lib/logstash/util/decorators.rb +6 -6
  36. data/lib/logstash/util/java_version.rb +1 -10
  37. data/lib/logstash/util/thread_dump.rb +55 -0
  38. data/lib/logstash/util/worker_threads_default_printer.rb +2 -2
  39. data/lib/logstash/version.rb +1 -1
  40. data/lib/logstash/webserver.rb +15 -49
  41. data/locales/en.yml +22 -25
  42. data/logstash-core.gemspec +3 -3
  43. data/spec/api/lib/api/node_spec.rb +2 -2
  44. data/spec/api/lib/api/node_stats_spec.rb +32 -57
  45. data/spec/api/lib/api/plugins_spec.rb +3 -3
  46. data/spec/api/lib/api/root_spec.rb +2 -2
  47. data/spec/api/lib/api/support/resource_dsl_methods.rb +47 -0
  48. data/spec/api/lib/commands/stats.rb +47 -0
  49. data/spec/api/spec_helper.rb +21 -21
  50. data/spec/conditionals_spec.rb +113 -113
  51. data/spec/logstash/agent_spec.rb +85 -68
  52. data/spec/logstash/config/config_ast_spec.rb +4 -2
  53. data/spec/logstash/config/mixin_spec.rb +33 -7
  54. data/spec/logstash/filters/base_spec.rb +16 -16
  55. data/spec/logstash/inputs/base_spec.rb +8 -8
  56. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +45 -0
  57. data/spec/logstash/output_delegator_spec.rb +2 -0
  58. data/spec/logstash/pipeline_reporter_spec.rb +5 -1
  59. data/spec/logstash/pipeline_spec.rb +75 -30
  60. data/spec/logstash/plugin_spec.rb +2 -2
  61. data/spec/logstash/runner_spec.rb +112 -25
  62. data/spec/logstash/setting_spec.rb +130 -0
  63. data/spec/logstash/settings_spec.rb +62 -0
  64. metadata +37 -43
  65. data/lib/logstash/api/init.ru +0 -31
  66. data/lib/logstash/api/lib/app.rb +0 -40
  67. data/lib/logstash/api/lib/app/command.rb +0 -29
  68. data/lib/logstash/api/lib/app/command_factory.rb +0 -29
  69. data/lib/logstash/api/lib/app/commands/stats/events_command.rb +0 -13
  70. data/lib/logstash/api/lib/app/commands/stats/hotthreads_command.rb +0 -120
  71. data/lib/logstash/api/lib/app/commands/stats/memory_command.rb +0 -25
  72. data/lib/logstash/api/lib/app/commands/system/basicinfo_command.rb +0 -15
  73. data/lib/logstash/api/lib/app/commands/system/plugins_command.rb +0 -28
  74. data/lib/logstash/api/lib/app/modules/node.rb +0 -25
  75. data/lib/logstash/api/lib/app/modules/node_stats.rb +0 -51
  76. data/lib/logstash/api/lib/app/modules/plugins.rb +0 -15
  77. data/lib/logstash/api/lib/app/modules/stats.rb +0 -21
  78. data/lib/logstash/api/lib/app/root.rb +0 -13
  79. data/lib/logstash/api/lib/app/service.rb +0 -61
  80. data/lib/logstash/api/lib/app/stats.rb +0 -56
  81. data/lib/logstash/util/defaults_printer.rb +0 -31
  82. data/spec/api/lib/api/stats_spec.rb +0 -19
  83. data/spec/api/lib/commands/events_spec.rb +0 -17
  84. data/spec/api/lib/commands/jvm_spec.rb +0 -45
  85. data/spec/logstash/util/defaults_printer_spec.rb +0 -50
  86. data/spec/logstash/util/worker_threads_default_printer_spec.rb +0 -45
@@ -0,0 +1,267 @@
1
+ # encoding: utf-8
2
+
3
+ module LogStash
4
+ class Settings
5
+
6
+ def initialize
7
+ @settings = {}
8
+ end
9
+
10
+ def register(setting)
11
+ if @settings.key?(setting.name)
12
+ raise ArgumentError.new("Setting \"#{setting.name}\" has already been registered as #{setting.inspect}")
13
+ else
14
+ @settings[setting.name] = setting
15
+ end
16
+ end
17
+
18
+ def get_setting(setting_name)
19
+ setting = @settings[setting_name]
20
+ raise ArgumentError.new("Setting \"#{setting_name}\" hasn't been registered") if setting.nil?
21
+ setting
22
+ end
23
+
24
+ def get_subset(setting_regexp)
25
+ regexp = setting_regexp.is_a?(Regexp) ? setting_regexp : Regexp.new(setting_regexp)
26
+ settings = self.class.new
27
+ @settings.each do |setting_name, setting|
28
+ next unless setting_name.match(regexp)
29
+ settings.register(setting.clone)
30
+ end
31
+ settings
32
+ end
33
+
34
+ def set?(setting_name)
35
+ get_setting(setting_name).set?
36
+ end
37
+
38
+ def clone
39
+ get_subset(".*")
40
+ end
41
+
42
+ def get_default(setting_name)
43
+ get_setting(setting_name).default
44
+ end
45
+
46
+ def get_value(setting_name)
47
+ get_setting(setting_name).value
48
+ end
49
+ alias_method :get, :get_value
50
+
51
+ def set_value(setting_name, value)
52
+ get_setting(setting_name).set(value)
53
+ end
54
+ alias_method :set, :set_value
55
+
56
+ def to_hash
57
+ hash = {}
58
+ @settings.each do |name, setting|
59
+ hash[name] = setting.value
60
+ end
61
+ hash
62
+ end
63
+
64
+ def merge(hash)
65
+ hash.each {|key, value| set_value(key, value) }
66
+ self
67
+ end
68
+
69
+ def format_settings
70
+ output = []
71
+ output << "-------- Logstash Settings (* means modified) ---------"
72
+ @settings.each do |setting_name, setting|
73
+ value = setting.value
74
+ default_value = setting.default
75
+ if default_value == value # print setting and its default value
76
+ output << "#{setting_name}: #{value.inspect}" unless value.nil?
77
+ elsif default_value.nil? # print setting and warn it has been set
78
+ output << "*#{setting_name}: #{value.inspect}"
79
+ elsif value.nil? # default setting not set by user
80
+ output << "#{setting_name}: #{default_value.inspect}"
81
+ else # print setting, warn it has been set, and show default value
82
+ output << "*#{setting_name}: #{value.inspect} (default: #{default_value.inspect})"
83
+ end
84
+ end
85
+ output << "--------------- Logstash Settings -------------------"
86
+ output
87
+ end
88
+
89
+ def reset
90
+ @settings.values.each(&:reset)
91
+ end
92
+
93
+ def from_yaml(yaml_path)
94
+ settings = read_yaml(::File.join(yaml_path, "logstash.yml"))
95
+ self.merge(flatten_hash(settings))
96
+ end
97
+
98
+ private
99
+ def read_yaml(path)
100
+ YAML.safe_load(IO.read(path)) || {}
101
+ end
102
+
103
+ def flatten_hash(h,f="",g={})
104
+ return g.update({ f => h }) unless h.is_a? Hash
105
+ if f.empty?
106
+ h.each { |k,r| flatten_hash(r,k,g) }
107
+ else
108
+ h.each { |k,r| flatten_hash(r,"#{f}.#{k}",g) }
109
+ end
110
+ g
111
+ end
112
+ end
113
+
114
+ class Setting
115
+ attr_reader :name, :default
116
+
117
+ def initialize(name, klass, default=nil, strict=true, &validator_proc)
118
+ @name = name
119
+ unless klass.is_a?(Class)
120
+ raise ArgumentError.new("Setting \"#{@name}\" must be initialized with a class (received #{klass})")
121
+ end
122
+ @klass = klass
123
+ @validator_proc = validator_proc
124
+ @value = nil
125
+ @value_is_set = false
126
+
127
+ validate(default) if strict
128
+ @default = default
129
+ end
130
+
131
+ def value
132
+ @value_is_set ? @value : default
133
+ end
134
+
135
+ def set?
136
+ @value_is_set
137
+ end
138
+
139
+ def set(value)
140
+ validate(value)
141
+ @value = value
142
+ @value_is_set = true
143
+ @value
144
+ end
145
+
146
+ def reset
147
+ @value = nil
148
+ @value_is_set = false
149
+ end
150
+
151
+ def to_hash
152
+ {
153
+ "name" => @name,
154
+ "klass" => @klass,
155
+ "value" => @value,
156
+ "value_is_set" => @value_is_set,
157
+ "default" => @default,
158
+ # Proc#== will only return true if it's the same obj
159
+ # so no there's no point in comparing it
160
+ # also thereś no use case atm to return the proc
161
+ # so let's not expose it
162
+ #"validator_proc" => @validator_proc
163
+ }
164
+ end
165
+
166
+ def ==(other)
167
+ self.to_hash == other.to_hash
168
+ end
169
+
170
+ private
171
+ def validate(value)
172
+ if !value.is_a?(@klass)
173
+ raise ArgumentError.new("Setting \"#{@name}\" must be a #{@klass}. Received: #{value} (#{value.class})")
174
+ elsif @validator_proc && !@validator_proc.call(value)
175
+ raise ArgumentError.new("Failed to validate setting \"#{@name}\" with value: #{value}")
176
+ end
177
+ end
178
+
179
+ ### Specific settings #####
180
+
181
+ class Boolean < Setting
182
+ def initialize(name, default, strict=true, &validator_proc)
183
+ @name = name
184
+ @klass = Object
185
+ @value = nil
186
+ @value_is_set = false
187
+ @validator_proc = validator_proc
188
+ coerced_default = coerce(default)
189
+ validate(coerced_default)
190
+ @default = coerced_default
191
+ end
192
+
193
+ def coerce(value)
194
+ case value
195
+ when TrueClass, "true"
196
+ true
197
+ when FalseClass, "false"
198
+ false
199
+ else
200
+ raise ArgumentError.new("could not coerce #{value} into a boolean")
201
+ end
202
+ end
203
+
204
+ def set(value)
205
+ coerced_value = coerce(value)
206
+ validate(coerced_value)
207
+ @value = coerce(coerced_value)
208
+ @value_is_set = true
209
+ @value
210
+ end
211
+ end
212
+
213
+ class String < Setting
214
+ def initialize(name, default=nil, strict=true)
215
+ super(name, ::String, default, strict)
216
+ end
217
+ end
218
+
219
+ class Numeric < Setting
220
+ def initialize(name, default=nil, strict=true)
221
+ super(name, ::Numeric, default, strict)
222
+ end
223
+ end
224
+
225
+ class Port < Setting
226
+ def initialize(name, default=nil, strict=true)
227
+ super(name, ::Numeric, default, strict) {|value| value >= 1 && value <= 65535 }
228
+ end
229
+ end
230
+
231
+ class Validator < Setting
232
+ def initialize(name, default=nil, strict=true, validator_class=nil)
233
+ @validator_class = validator_class
234
+ super(name, ::Object, default, strict)
235
+ end
236
+
237
+ def validate(value)
238
+ @validator_class.validate(value)
239
+ end
240
+ end
241
+
242
+ class String < Setting
243
+ def initialize(name, default=nil, strict=true, possible_strings=[])
244
+ super(name, ::String, default, strict)
245
+ end
246
+
247
+ def validate(value)
248
+ super(value) && possible_strings.include?(value)
249
+ end
250
+ end
251
+
252
+ class ExistingFilePath < Setting
253
+ def initialize(name, default=nil, strict=true)
254
+ super(name, ::String, default, strict) do |file_path|
255
+ if !::File.exists?(file_path)
256
+ raise ::ArgumentError.new("File \"#{file_path}\" must exist but was not found.")
257
+ else
258
+ true
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ end
265
+
266
+ SETTINGS = Settings.new
267
+ end
@@ -7,7 +7,7 @@ module LogStash::Util
7
7
  # Decorators provides common manipulation on the event data.
8
8
  module Decorators
9
9
  extend self
10
-
10
+
11
11
  @logger = Cabin::Channel.get(LogStash)
12
12
 
13
13
  # fields is a hash of field => value
@@ -22,11 +22,11 @@ module LogStash::Util
22
22
  # note below that the array field needs to be updated then reassigned to the event.
23
23
  # this is important because a construct like event[field] << v will not work
24
24
  # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
25
- a = Array(event[field])
25
+ a = Array(event.get(field))
26
26
  a << v
27
- event[field] = a
27
+ event.set(field, a)
28
28
  else
29
- event[field] = v
29
+ event.set(field, v)
30
30
  end
31
31
  @logger.debug? and @logger.debug("#{pluginname}: adding value to field", :field => field, :value => value)
32
32
  end
@@ -41,9 +41,9 @@ module LogStash::Util
41
41
  # note below that the tags array field needs to be updated then reassigned to the event.
42
42
  # this is important because a construct like event["tags"] << tag will not work
43
43
  # in the current Java event implementation. see https://github.com/elastic/logstash/issues/4140
44
- tags = event["tags"] || []
44
+ tags = event.get("tags") || []
45
45
  tags << tag
46
- event["tags"] = tags
46
+ event.set("tags", tags)
47
47
  end
48
48
  end
49
49
 
@@ -5,16 +5,7 @@ module LogStash::Util::JavaVersion
5
5
  def self.logger
6
6
  @logger ||= Cabin::Channel.get(LogStash)
7
7
  end
8
-
9
- # Print a warning if we're on a bad version of java
10
- def self.warn_on_bad_java_version
11
- if self.bad_java_version?(self.version)
12
- msg = "!!! Please upgrade your java version, the current version '#{self.version}' is not supported. We recommend a minimum version of Java 8"
13
- STDERR.puts(msg)
14
- logger.warn(msg)
15
- end
16
- end
17
-
8
+
18
9
  # Return the current java version string. Returns nil if this is a non-java platform (e.g. MRI).
19
10
  def self.version
20
11
  return nil unless LogStash::Environment.jruby?
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ module LogStash
3
+ module Util
4
+ class ThreadDump
5
+ SKIPPED_THREADS = [ "Finalizer", "Reference Handler", "Signal Dispatcher" ].freeze
6
+ THREADS_COUNT_DEFAULT = 3.freeze
7
+ IGNORE_IDLE_THREADS_DEFAULT = true.freeze
8
+
9
+ attr_reader :top_count, :ignore, :dump
10
+
11
+ def initialize(options={})
12
+ @options = options
13
+ @dump = options.fetch(:dump, JRMonitor.threads.generate({}))
14
+ @top_count = options.fetch(:threads, THREADS_COUNT_DEFAULT)
15
+ @ignore = options.fetch(:ignore_idle_threads, IGNORE_IDLE_THREADS_DEFAULT)
16
+ end
17
+
18
+ def each(&block)
19
+ i=0
20
+ dump.each_pair do |thread_name, _hash|
21
+ break if i >= top_count
22
+ if ignore
23
+ next if idle_thread?(thread_name, _hash)
24
+ end
25
+ block.call(thread_name, _hash)
26
+ i += 1
27
+ end
28
+ end
29
+
30
+ def idle_thread?(thread_name, data)
31
+ idle = false
32
+ if SKIPPED_THREADS.include?(thread_name)
33
+ # these are likely JVM dependent
34
+ idle = true
35
+ elsif thread_name.match(/Ruby-\d+-JIT-\d+/)
36
+ # This are internal JRuby JIT threads,
37
+ # see java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor for details.
38
+ idle = true
39
+ elsif thread_name.match(/pool-\d+-thread-\d+/)
40
+ # This are threads used by the internal JRuby implementation to dispatch
41
+ # calls and tasks, see prg.jruby.internal.runtime.methods.DynamicMethod.call
42
+ idle = true
43
+ else
44
+ data["thread.stacktrace"].each do |trace|
45
+ if trace.start_with?("java.util.concurrent.ThreadPoolExecutor.getTask")
46
+ idle = true
47
+ break
48
+ end
49
+ end
50
+ end
51
+ idle
52
+ end
53
+ end
54
+ end
55
+ end
@@ -6,8 +6,8 @@ require "logstash/util"
6
6
  module LogStash module Util class WorkerThreadsDefaultPrinter
7
7
 
8
8
  def initialize(settings)
9
- @setting = settings.fetch(:pipeline_workers, 0)
10
- @default = settings.fetch(:default_pipeline_workers, 0)
9
+ @setting = settings.fetch('pipeline.workers', 0)
10
+ @default = settings.fetch('default-pipeline-workers', 0)
11
11
  end
12
12
 
13
13
  def visit(collector)
@@ -11,4 +11,4 @@
11
11
  # eventually this file should be in the root logstash lib fir and dependencies in logstash-core should be
12
12
  # fixed.
13
13
 
14
- LOGSTASH_VERSION = "5.0.0-alpha2.snapshot2"
14
+ LOGSTASH_VERSION = "5.0.0-alpha3"
@@ -1,16 +1,15 @@
1
1
  # encoding: utf-8
2
2
  require "puma"
3
- require "puma/single"
4
- require "puma/binder"
5
- require "puma/configuration"
6
- require "puma/commonlogger"
3
+ require "puma/server"
4
+ require "sinatra"
5
+ require "rack"
6
+ require "logstash/api/rack_app"
7
7
 
8
8
  module LogStash
9
9
  class WebServer
10
-
11
10
  extend Forwardable
12
11
 
13
- attr_reader :logger, :status, :config, :options, :cli_options, :runner, :binder, :events
12
+ attr_reader :logger, :status, :config, :options, :cli_options, :runner, :binder, :events, :http_host, :http_port
14
13
 
15
14
  def_delegator :@runner, :stats
16
15
 
@@ -19,8 +18,8 @@ module LogStash
19
18
 
20
19
  def initialize(logger, options={})
21
20
  @logger = logger
22
- http_host = options[:http_host] || DEFAULT_HOST
23
- http_port = options[:http_port] || DEFAULT_PORT
21
+ @http_host = options[:http_host] || DEFAULT_HOST
22
+ @http_port = options[:http_port] || DEFAULT_PORT
24
23
  @options = {}
25
24
  @cli_options = options.merge({ :rackup => ::File.join(::File.dirname(__FILE__), "api", "init.ru"),
26
25
  :binds => ["tcp://#{http_host}:#{http_port}"],
@@ -31,24 +30,17 @@ module LogStash
31
30
  :queue_requests => false
32
31
  })
33
32
  @status = nil
34
-
35
- parse_options
36
-
37
- @runner = nil
38
- @events = ::Puma::Events.strings
39
- @binder = ::Puma::Binder.new(@events)
40
- @binder.import_from_env
41
-
42
- set_environment
43
33
  end
44
34
 
45
35
  def run
46
36
  log "=== puma start: #{Time.now} ==="
47
37
 
48
- @runner = Puma::Single.new(self)
49
- @status = :run
50
- @runner.run
51
- stop(:graceful => true)
38
+ stop # Just in case
39
+
40
+ @server = ::Puma::Server.new(LogStash::Api::RackApp.app)
41
+ @server.add_tcp_listener(http_host, http_port)
42
+
43
+ @server.run.join
52
44
  end
53
45
 
54
46
  def log(str)
@@ -58,7 +50,7 @@ module LogStash
58
50
  def error(str)
59
51
  logger.error(str)
60
52
  end
61
-
53
+
62
54
  # Empty method, this method is required because of the puma usage we make through
63
55
  # the Single interface, https://github.com/puma/puma/blob/master/lib/puma/single.rb#L82
64
56
  # for more details. This can always be implemented when we want to keep track of this
@@ -66,33 +58,7 @@ module LogStash
66
58
  def write_state; end
67
59
 
68
60
  def stop(options={})
69
- graceful = options.fetch(:graceful, true)
70
-
71
- if graceful
72
- @runner.stop_blocked
73
- else
74
- @runner.stop
75
- end rescue nil
76
-
77
- @status = :stop
78
- log "=== puma shutdown: #{Time.now} ==="
79
- end
80
-
81
- private
82
-
83
- def env
84
- @options[:debug] ? "development" : "production"
85
- end
86
-
87
- def set_environment
88
- @options[:environment] = env
89
- ENV['RACK_ENV'] = env
90
- end
91
-
92
- def parse_options
93
- @config = ::Puma::Configuration.new(cli_options)
94
- @config.load
95
- @options = @config.options
61
+ @server.stop(true) if @server
96
62
  end
97
63
  end
98
64
  end