logstash-core 5.6.16-java → 6.0.0.alpha1-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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/gemspec_jars.rb +4 -7
  3. data/lib/logstash-core/logstash-core.jar +0 -0
  4. data/lib/logstash-core/version.rb +4 -8
  5. data/lib/logstash-core_jars.rb +12 -26
  6. data/lib/logstash/agent.rb +261 -246
  7. data/lib/logstash/api/commands/default_metadata.rb +1 -1
  8. data/lib/logstash/api/commands/hot_threads_reporter.rb +5 -11
  9. data/lib/logstash/api/commands/node.rb +3 -2
  10. data/lib/logstash/api/commands/stats.rb +3 -2
  11. data/lib/logstash/bootstrap_check/bad_java.rb +16 -0
  12. data/lib/logstash/bootstrap_check/bad_ruby.rb +12 -0
  13. data/lib/logstash/bootstrap_check/default_config.rb +17 -0
  14. data/lib/logstash/compiler.rb +38 -0
  15. data/lib/logstash/compiler/lscl.rb +566 -0
  16. data/lib/logstash/compiler/lscl/lscl_grammar.rb +3503 -0
  17. data/lib/logstash/compiler/treetop_monkeypatches.rb +92 -0
  18. data/lib/logstash/config/config_ast.rb +4 -82
  19. data/lib/logstash/config/mixin.rb +73 -41
  20. data/lib/logstash/config/pipeline_config.rb +48 -0
  21. data/lib/logstash/config/source/base.rb +16 -0
  22. data/lib/logstash/config/source/local.rb +215 -0
  23. data/lib/logstash/config/source_loader.rb +125 -0
  24. data/lib/logstash/converge_result.rb +103 -0
  25. data/lib/logstash/environment.rb +6 -19
  26. data/lib/logstash/errors.rb +2 -0
  27. data/lib/logstash/execution_context.rb +4 -7
  28. data/lib/logstash/filter_delegator.rb +6 -9
  29. data/lib/logstash/inputs/base.rb +0 -2
  30. data/lib/logstash/instrument/collector.rb +5 -7
  31. data/lib/logstash/instrument/metric_store.rb +12 -12
  32. data/lib/logstash/instrument/metric_type/mean.rb +0 -5
  33. data/lib/logstash/instrument/namespaced_metric.rb +0 -4
  34. data/lib/logstash/instrument/namespaced_null_metric.rb +0 -4
  35. data/lib/logstash/instrument/null_metric.rb +0 -10
  36. data/lib/logstash/instrument/periodic_poller/cgroup.rb +85 -168
  37. data/lib/logstash/instrument/periodic_poller/jvm.rb +5 -5
  38. data/lib/logstash/instrument/periodic_poller/pq.rb +3 -7
  39. data/lib/logstash/instrument/periodic_pollers.rb +1 -3
  40. data/lib/logstash/instrument/wrapped_write_client.rb +24 -33
  41. data/lib/logstash/logging/logger.rb +15 -47
  42. data/lib/logstash/namespace.rb +0 -1
  43. data/lib/logstash/output_delegator.rb +5 -7
  44. data/lib/logstash/outputs/base.rb +0 -2
  45. data/lib/logstash/pipeline.rb +159 -87
  46. data/lib/logstash/pipeline_action.rb +13 -0
  47. data/lib/logstash/pipeline_action/base.rb +29 -0
  48. data/lib/logstash/pipeline_action/create.rb +47 -0
  49. data/lib/logstash/pipeline_action/reload.rb +48 -0
  50. data/lib/logstash/pipeline_action/stop.rb +23 -0
  51. data/lib/logstash/plugin.rb +0 -1
  52. data/lib/logstash/plugins/hooks_registry.rb +6 -0
  53. data/lib/logstash/plugins/registry.rb +0 -1
  54. data/lib/logstash/program.rb +14 -0
  55. data/lib/logstash/queue_factory.rb +5 -1
  56. data/lib/logstash/runner.rb +58 -80
  57. data/lib/logstash/settings.rb +3 -27
  58. data/lib/logstash/state_resolver.rb +41 -0
  59. data/lib/logstash/util/java_version.rb +6 -0
  60. data/lib/logstash/util/safe_uri.rb +12 -148
  61. data/lib/logstash/util/thread_dump.rb +4 -7
  62. data/lib/logstash/util/wrapped_acked_queue.rb +36 -39
  63. data/lib/logstash/util/wrapped_synchronous_queue.rb +29 -39
  64. data/lib/logstash/version.rb +10 -8
  65. data/locales/en.yml +3 -54
  66. data/logstash-core.gemspec +8 -35
  67. data/spec/{logstash/api/modules → api/lib/api}/logging_spec.rb +10 -1
  68. data/spec/{logstash/api/modules → api/lib/api}/node_plugins_spec.rb +2 -1
  69. data/spec/{logstash/api/modules → api/lib/api}/node_spec.rb +3 -3
  70. data/spec/{logstash/api/modules → api/lib/api}/node_stats_spec.rb +3 -7
  71. data/spec/{logstash/api/modules → api/lib/api}/plugins_spec.rb +3 -4
  72. data/spec/{logstash/api/modules → api/lib/api}/root_spec.rb +2 -2
  73. data/spec/api/lib/api/support/resource_dsl_methods.rb +87 -0
  74. data/spec/{logstash/api/commands/stats_spec.rb → api/lib/commands/stats.rb} +2 -7
  75. data/spec/{logstash/api → api/lib}/errors_spec.rb +1 -1
  76. data/spec/{logstash/api → api/lib}/rack_app_spec.rb +0 -0
  77. data/spec/api/spec_helper.rb +106 -0
  78. data/spec/logstash/agent/converge_spec.rb +286 -0
  79. data/spec/logstash/agent/metrics_spec.rb +244 -0
  80. data/spec/logstash/agent_spec.rb +213 -225
  81. data/spec/logstash/compiler/compiler_spec.rb +584 -0
  82. data/spec/logstash/config/config_ast_spec.rb +8 -47
  83. data/spec/logstash/config/mixin_spec.rb +2 -42
  84. data/spec/logstash/config/pipeline_config_spec.rb +75 -0
  85. data/spec/logstash/config/source/local_spec.rb +395 -0
  86. data/spec/logstash/config/source_loader_spec.rb +122 -0
  87. data/spec/logstash/converge_result_spec.rb +179 -0
  88. data/spec/logstash/event_spec.rb +0 -66
  89. data/spec/logstash/execution_context_spec.rb +8 -12
  90. data/spec/logstash/filter_delegator_spec.rb +12 -24
  91. data/spec/logstash/inputs/base_spec.rb +7 -5
  92. data/spec/logstash/instrument/periodic_poller/cgroup_spec.rb +92 -225
  93. data/spec/logstash/instrument/periodic_poller/jvm_spec.rb +1 -1
  94. data/spec/logstash/instrument/periodic_poller/os_spec.rb +32 -29
  95. data/spec/logstash/instrument/wrapped_write_client_spec.rb +33 -33
  96. data/spec/logstash/legacy_ruby_event_spec.rb +13 -4
  97. data/spec/logstash/output_delegator_spec.rb +11 -20
  98. data/spec/logstash/outputs/base_spec.rb +7 -5
  99. data/spec/logstash/pipeline_action/create_spec.rb +83 -0
  100. data/spec/logstash/pipeline_action/reload_spec.rb +83 -0
  101. data/spec/logstash/pipeline_action/stop_spec.rb +37 -0
  102. data/spec/logstash/pipeline_pq_file_spec.rb +1 -1
  103. data/spec/logstash/pipeline_spec.rb +81 -137
  104. data/spec/logstash/plugin_spec.rb +2 -1
  105. data/spec/logstash/plugins/hooks_registry_spec.rb +6 -0
  106. data/spec/logstash/queue_factory_spec.rb +13 -1
  107. data/spec/logstash/runner_spec.rb +29 -140
  108. data/spec/logstash/settings/writable_directory_spec.rb +10 -13
  109. data/spec/logstash/settings_spec.rb +0 -91
  110. data/spec/logstash/state_resolver_spec.rb +156 -0
  111. data/spec/logstash/timestamp_spec.rb +2 -6
  112. data/spec/logstash/util/java_version_spec.rb +22 -0
  113. data/spec/logstash/util/safe_uri_spec.rb +0 -56
  114. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +22 -0
  115. data/spec/support/helpers.rb +9 -11
  116. data/spec/support/matchers.rb +96 -6
  117. data/spec/support/mocks_classes.rb +80 -0
  118. data/spec/support/shared_contexts.rb +2 -27
  119. metadata +100 -149
  120. data/lib/logstash/config/loader.rb +0 -107
  121. data/lib/logstash/config/modules_common.rb +0 -103
  122. data/lib/logstash/config/source/modules.rb +0 -55
  123. data/lib/logstash/config/string_escape.rb +0 -27
  124. data/lib/logstash/dependency_report.rb +0 -131
  125. data/lib/logstash/dependency_report_runner.rb +0 -17
  126. data/lib/logstash/elasticsearch_client.rb +0 -142
  127. data/lib/logstash/instrument/global_metrics.rb +0 -13
  128. data/lib/logstash/instrument/periodic_poller/dlq.rb +0 -24
  129. data/lib/logstash/modules/cli_parser.rb +0 -74
  130. data/lib/logstash/modules/elasticsearch_config.rb +0 -22
  131. data/lib/logstash/modules/elasticsearch_importer.rb +0 -37
  132. data/lib/logstash/modules/elasticsearch_resource.rb +0 -10
  133. data/lib/logstash/modules/file_reader.rb +0 -36
  134. data/lib/logstash/modules/kibana_base.rb +0 -24
  135. data/lib/logstash/modules/kibana_client.rb +0 -124
  136. data/lib/logstash/modules/kibana_config.rb +0 -105
  137. data/lib/logstash/modules/kibana_dashboards.rb +0 -36
  138. data/lib/logstash/modules/kibana_importer.rb +0 -17
  139. data/lib/logstash/modules/kibana_resource.rb +0 -10
  140. data/lib/logstash/modules/kibana_settings.rb +0 -40
  141. data/lib/logstash/modules/logstash_config.rb +0 -120
  142. data/lib/logstash/modules/resource_base.rb +0 -38
  143. data/lib/logstash/modules/scaffold.rb +0 -52
  144. data/lib/logstash/modules/settings_merger.rb +0 -23
  145. data/lib/logstash/modules/util.rb +0 -17
  146. data/lib/logstash/util/dead_letter_queue_manager.rb +0 -61
  147. data/lib/logstash/util/environment_variables.rb +0 -43
  148. data/spec/logstash/config/loader_spec.rb +0 -38
  149. data/spec/logstash/config/string_escape_spec.rb +0 -24
  150. data/spec/logstash/instrument/periodic_poller/dlq_spec.rb +0 -17
  151. data/spec/logstash/modules/logstash_config_spec.rb +0 -56
  152. data/spec/logstash/modules/scaffold_spec.rb +0 -234
  153. data/spec/logstash/pipeline_dlq_commit_spec.rb +0 -109
  154. data/spec/logstash/settings/splittable_string_array_spec.rb +0 -51
  155. data/spec/logstash/util/wrapped_acked_queue_spec.rb +0 -49
  156. data/versions-gem-copy.yml +0 -12
@@ -0,0 +1,92 @@
1
+ class Treetop::Runtime::SyntaxNode
2
+ def get_meta(key)
3
+ @ast_metadata ||= {}
4
+ return @ast_metadata[key] if @ast_metadata[key]
5
+ return self.parent.get_meta(key) if self.parent
6
+ nil
7
+ end
8
+
9
+ def set_meta(key, value)
10
+ @ast_metadata ||= {}
11
+ @ast_metadata[key] = value
12
+ end
13
+ def compile
14
+ return "" if elements.nil?
15
+ return elements.collect(&:compile).reject(&:empty?).join("")
16
+ end
17
+
18
+ # Traverse the syntax tree recursively.
19
+ # The order should respect the order of the configuration file as it is read
20
+ # and written by humans (and the order in which it is parsed).
21
+ def recurse(e, depth=0, &block)
22
+ r = block.call(e, depth)
23
+ e.elements.each { |e| recurse(e, depth + 1, &block) } if r && e.elements
24
+ nil
25
+ end
26
+
27
+ def recursive_inject(results=[], &block)
28
+ if !elements.nil?
29
+ elements.each do |element|
30
+ if block.call(element)
31
+ results << element
32
+ else
33
+ element.recursive_inject(results, &block)
34
+ end
35
+ end
36
+ end
37
+ return results
38
+ end
39
+
40
+ # When Treetop parses the configuration file
41
+ # it will generate a tree, the generated tree will contain
42
+ # a few `Empty` nodes to represent the actual space/tab or newline in the file.
43
+ # Some of theses node will point to our concrete class.
44
+ # To fetch a specific types of object we need to follow each branch
45
+ # and ignore the empty nodes.
46
+ def recursive_select(*klasses)
47
+ return recursive_inject { |e| klasses.any? {|k| e.is_a?(k)} }
48
+ end
49
+
50
+ def recursive_inject_parent(results=[], &block)
51
+ if !parent.nil?
52
+ if block.call(parent)
53
+ results << parent
54
+ else
55
+ parent.recursive_inject_parent(results, &block)
56
+ end
57
+ end
58
+ return results
59
+ end
60
+
61
+ def recursive_select_parent(results=[], klass)
62
+ return recursive_inject_parent(results) { |e| e.is_a?(klass) }
63
+ end
64
+
65
+ # Monkeypatch Treetop::Runtime::SyntaxNode's inspect method to skip
66
+ # any Whitespace or SyntaxNodes with no children.
67
+ def _inspect(indent="")
68
+ em = extension_modules
69
+ interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
70
+ im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
71
+ tv = text_value
72
+ tv = "...#{tv[-20..-1]}" if tv.size > 20
73
+
74
+ indent +
75
+ self.class.to_s.sub(/.*:/,'') +
76
+ em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
77
+ " offset=#{interval.first}" +
78
+ ", #{tv.inspect}" +
79
+ im +
80
+ (elements && elements.size > 0 ?
81
+ ":" +
82
+ (elements.select { |e| !e.is_a?(LogStash::Config::AST::Whitespace) && e.elements && e.elements.size > 0 }||[]).map{|e|
83
+ begin
84
+ "\n"+e.inspect(indent+" ")
85
+ rescue # Defend against inspect not taking a parameter
86
+ "\n"+indent+" "+e.inspect
87
+ end
88
+ }.join("") :
89
+ ""
90
+ )
91
+ end
92
+ end
@@ -1,78 +1,10 @@
1
1
  # encoding: utf-8
2
2
  require 'logstash/errors'
3
- require "logstash/config/string_escape"
4
3
  require "treetop"
5
4
 
6
- class Treetop::Runtime::SyntaxNode
7
-
8
- def compile
9
- return "" if elements.nil?
10
- return elements.collect(&:compile).reject(&:empty?).join("")
11
- end
12
-
13
- def get_meta(key)
14
- @ast_metadata ||= {}
15
- return @ast_metadata[key] if @ast_metadata[key]
16
- return self.parent.get_meta(key) if self.parent
17
- nil
18
- end
19
-
20
- def set_meta(key, value)
21
- @ast_metadata ||= {}
22
- @ast_metadata[key] = value
23
- end
24
-
25
- # Traverse the syntax tree recursively.
26
- # The order should respect the order of the configuration file as it is read
27
- # and written by humans (and the order in which it is parsed).
28
- def recurse(e, depth=0, &block)
29
- r = block.call(e, depth)
30
- e.elements.each { |e| recurse(e, depth + 1, &block) } if r && e.elements
31
- nil
32
- end
33
-
34
- def recursive_inject(results=[], &block)
35
- if !elements.nil?
36
- elements.each do |element|
37
- if block.call(element)
38
- results << element
39
- else
40
- element.recursive_inject(results, &block)
41
- end
42
- end
43
- end
44
- return results
45
- end
46
-
47
- # When Treetop parses the configuration file
48
- # it will generate a tree, the generated tree will contain
49
- # a few `Empty` nodes to represent the actual space/tab or newline in the file.
50
- # Some of theses node will point to our concrete class.
51
- # To fetch a specific types of object we need to follow each branch
52
- # and ignore the empty nodes.
53
- def recursive_select(klass)
54
- return recursive_inject { |e| e.is_a?(klass) }
55
- end
56
-
57
- def recursive_inject_parent(results=[], &block)
58
- if !parent.nil?
59
- if block.call(parent)
60
- results << parent
61
- else
62
- parent.recursive_inject_parent(results, &block)
63
- end
64
- end
65
- return results
66
- end
67
-
68
- def recursive_select_parent(results=[], klass)
69
- return recursive_inject_parent(results) { |e| e.is_a?(klass) }
70
- end
71
- end
72
-
5
+ require "logstash/compiler/treetop_monkeypatches"
73
6
 
74
7
  module LogStash; module Config; module AST
75
- PROCESS_ESCAPE_SEQUENCES = :process_escape_sequences
76
8
 
77
9
  def self.deferred_conditionals=(val)
78
10
  @deferred_conditionals = val
@@ -105,11 +37,6 @@ module LogStash; module Config; module AST
105
37
  end
106
38
 
107
39
  class Config < Node
108
- def process_escape_sequences=(val)
109
- set_meta(PROCESS_ESCAPE_SEQUENCES, val)
110
- end
111
-
112
-
113
40
  def compile
114
41
  LogStash::Config::AST.deferred_conditionals = []
115
42
  LogStash::Config::AST.deferred_conditionals_index = 0
@@ -141,9 +68,8 @@ module LogStash; module Config; module AST
141
68
  # of the output/filter function
142
69
  definitions << "define_singleton_method :#{type}_func do |event|"
143
70
  definitions << " targeted_outputs = []" if type == "output"
144
- definitions << " events = event" if type == "filter"
145
- definitions << " @logger.debug? && @logger.debug(\"#{type} received\", \"event\" => event.to_hash)" if type == "output"
146
- definitions << " @logger.debug? && events.each { |e| @logger.debug(\"#{type} received\", \"event\" => e.to_hash)}" if type == "filter"
71
+ definitions << " events = [event]" if type == "filter"
72
+ definitions << " @logger.debug? && @logger.debug(\"#{type} received\", \"event\" => event.to_hash)"
147
73
 
148
74
  sections.select { |s| s.plugin_type.text_value == type }.each do |s|
149
75
  definitions << s.compile.split("\n", -1).map { |e| " #{e}" }
@@ -353,11 +279,7 @@ module LogStash; module Config; module AST
353
279
  end
354
280
  class String < Value
355
281
  def compile
356
- if get_meta(PROCESS_ESCAPE_SEQUENCES)
357
- Unicode.wrap(LogStash::Config::StringEscape.process_escapes(text_value[1...-1]))
358
- else
359
- Unicode.wrap(text_value[1...-1])
360
- end
282
+ return Unicode.wrap(text_value[1...-1])
361
283
  end
362
284
  end
363
285
  class RegExp < Value
@@ -33,21 +33,37 @@ LogStash::Environment.load_locale!
33
33
  # }
34
34
  #
35
35
  module LogStash::Config::Mixin
36
-
37
- include LogStash::Util::EnvironmentVariables
38
-
39
36
  attr_accessor :config
40
37
  attr_accessor :original_params
41
38
 
42
39
  PLUGIN_VERSION_1_0_0 = LogStash::Util::PluginVersion.new(1, 0, 0)
43
40
  PLUGIN_VERSION_0_9_0 = LogStash::Util::PluginVersion.new(0, 9, 0)
44
-
41
+
42
+ ENV_PLACEHOLDER_REGEX = /\$\{(?<name>\w+)(\:(?<default>[^}]*))?\}/
43
+
45
44
  # This method is called when someone does 'include LogStash::Config'
46
45
  def self.included(base)
47
46
  # Add the DSL methods to the 'base' given.
48
47
  base.extend(LogStash::Config::Mixin::DSL)
49
48
  end
50
-
49
+
50
+ # Recursive method to replace environment variable references in parameters
51
+ def deep_replace(value)
52
+ if (value.is_a?(Hash))
53
+ value.each do |valueHashKey, valueHashValue|
54
+ value[valueHashKey.to_s] = deep_replace(valueHashValue)
55
+ end
56
+ else
57
+ if (value.is_a?(Array))
58
+ value.each_index do | valueArrayIndex|
59
+ value[valueArrayIndex] = deep_replace(value[valueArrayIndex])
60
+ end
61
+ else
62
+ return replace_env_placeholders(value)
63
+ end
64
+ end
65
+ end
66
+
51
67
  def config_init(params)
52
68
  # Validation will modify the values inside params if necessary.
53
69
  # For example: converting a string to a number, etc.
@@ -60,6 +76,30 @@ module LogStash::Config::Mixin
60
76
  # store the plugin type, turns LogStash::Inputs::Base into 'input'
61
77
  @plugin_type = self.class.ancestors.find { |a| a.name =~ /::Base$/ }.config_name
62
78
 
79
+ # warn about deprecated variable use
80
+ params.each do |name, value|
81
+ opts = self.class.get_config[name]
82
+ if opts && opts[:deprecated]
83
+ extra = opts[:deprecated].is_a?(String) ? opts[:deprecated] : ""
84
+ extra.gsub!("%PLUGIN%", self.class.config_name)
85
+ self.logger.warn("You are using a deprecated config setting " +
86
+ "#{name.inspect} set in #{self.class.config_name}. " +
87
+ "Deprecated settings will continue to work, " +
88
+ "but are scheduled for removal from logstash " +
89
+ "in the future. #{extra} If you have any questions " +
90
+ "about this, please visit the #logstash channel " +
91
+ "on freenode irc.", :name => name, :plugin => self)
92
+
93
+ end
94
+ if opts && opts[:obsolete]
95
+ extra = opts[:obsolete].is_a?(String) ? opts[:obsolete] : ""
96
+ extra.gsub!("%PLUGIN%", self.class.config_name)
97
+ raise LogStash::ConfigurationError,
98
+ I18n.t("logstash.runner.configuration.obsolete", :name => name,
99
+ :plugin => self.class.config_name, :extra => extra)
100
+ end
101
+ end
102
+
63
103
  # Set defaults from 'config :foo, :default => somevalue'
64
104
  self.class.get_config.each do |name, opts|
65
105
  next if params.include?(name.to_s)
@@ -85,46 +125,17 @@ module LogStash::Config::Mixin
85
125
  params[name.to_s] = deep_replace(value)
86
126
  end
87
127
 
128
+
88
129
  if !self.class.validate(params)
89
130
  raise LogStash::ConfigurationError,
90
131
  I18n.t("logstash.runner.configuration.invalid_plugin_settings")
91
132
  end
92
133
 
93
- # now that we know the parameters are valid, we can obfuscate the original copy
94
- # of the parameters before storing them as an instance variable
95
- self.class.secure_params!(original_params)
96
- @original_params = original_params
97
-
98
- # warn about deprecated variable use
99
- original_params.each do |name, value|
100
- opts = self.class.get_config[name]
101
- if opts && opts[:deprecated]
102
- extra = opts[:deprecated].is_a?(String) ? opts[:deprecated] : ""
103
- extra.gsub!("%PLUGIN%", self.class.config_name)
104
- self.logger.warn("You are using a deprecated config setting " +
105
- "#{name.inspect} set in #{self.class.config_name}. " +
106
- "Deprecated settings will continue to work, " +
107
- "but are scheduled for removal from logstash " +
108
- "in the future. #{extra} If you have any questions " +
109
- "about this, please visit the #logstash channel " +
110
- "on freenode irc.", :name => name, :plugin => self)
111
-
112
- end
113
-
114
- if opts && opts[:obsolete]
115
- extra = opts[:obsolete].is_a?(String) ? opts[:obsolete] : ""
116
- extra.gsub!("%PLUGIN%", self.class.config_name)
117
- raise LogStash::ConfigurationError,
118
- I18n.t("logstash.runner.configuration.obsolete", :name => name,
119
- :plugin => self.class.config_name, :extra => extra)
120
- end
121
- end
122
-
123
134
  # We remove any config options marked as obsolete,
124
135
  # no code should be associated to them and their values should not bleed
125
136
  # to the plugin context.
126
137
  #
127
- # This need to be done after fetching the options from the parents class
138
+ # This need to be done after fetching the options from the parents classed
128
139
  params.reject! do |name, value|
129
140
  opts = self.class.get_config[name]
130
141
  opts.include?(:obsolete)
@@ -139,13 +150,36 @@ module LogStash::Config::Mixin
139
150
  instance_variable_set("@#{key}", value)
140
151
  end
141
152
 
153
+ # now that we know the parameters are valid, we can obfuscate the original copy
154
+ # of the parameters before storing them as an instance variable
155
+ self.class.secure_params!(original_params)
156
+ @original_params = original_params
157
+
142
158
  @config = params
143
159
  end # def config_init
144
160
 
145
- module DSL
146
-
147
- include LogStash::Util::EnvironmentVariables
161
+ # Replace all environment variable references in 'value' param by environment variable value and return updated value
162
+ # Process following patterns : $VAR, ${VAR}, ${VAR:defaultValue}
163
+ def replace_env_placeholders(value)
164
+ return value unless value.is_a?(String)
165
+
166
+ value.gsub(ENV_PLACEHOLDER_REGEX) do |placeholder|
167
+ # Note: Ruby docs claim[1] Regexp.last_match is thread-local and scoped to
168
+ # the call, so this should be thread-safe.
169
+ #
170
+ # [1] http://ruby-doc.org/core-2.1.1/Regexp.html#method-c-last_match
171
+ name = Regexp.last_match(:name)
172
+ default = Regexp.last_match(:default)
173
+
174
+ replacement = ENV.fetch(name, default)
175
+ if replacement.nil?
176
+ raise LogStash::ConfigurationError, "Cannot evaluate `#{placeholder}`. Environment variable `#{name}` is not set and there is no default value given."
177
+ end
178
+ replacement
179
+ end
180
+ end # def replace_env_placeholders
148
181
 
182
+ module DSL
149
183
  attr_accessor :flags
150
184
 
151
185
  # If name is given, set the name and return it.
@@ -391,8 +425,6 @@ module LogStash::Config::Mixin
391
425
  # (see LogStash::Inputs::File for example)
392
426
  result = nil
393
427
 
394
- value = deep_replace(value)
395
-
396
428
  if validator.nil?
397
429
  return true, value
398
430
  elsif validator.is_a?(Array)
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+ require "digest"
3
+
4
+ module LogStash module Config
5
+ class PipelineConfig
6
+ include LogStash::Util::Loggable
7
+
8
+ attr_reader :source, :pipeline_id, :config_parts, :settings, :read_at
9
+
10
+ def initialize(source, pipeline_id, config_parts, settings)
11
+ @source = source
12
+ @pipeline_id = pipeline_id
13
+ # We can't use Array() since config_parts may be a java object!
14
+ config_parts_array = config_parts.is_a?(Array) ? config_parts : [config_parts]
15
+ @config_parts = config_parts_array.sort_by { |config_part| [config_part.protocol.to_s, config_part.id] }
16
+ @settings = settings
17
+ @read_at = Time.now
18
+ end
19
+
20
+ def config_hash
21
+ @config_hash ||= Digest::SHA1.hexdigest(config_string)
22
+ end
23
+
24
+ def config_string
25
+ @config_string = config_parts.collect(&:text).join("\n")
26
+ end
27
+
28
+ def system?
29
+ @settings.get("pipeline.system")
30
+ end
31
+
32
+ def ==(other)
33
+ config_hash == other.config_hash && pipeline_id == other.pipeline_id
34
+ end
35
+
36
+ def display_debug_information
37
+ logger.debug("-------- Logstash Config ---------")
38
+ logger.debug("Config from source", :source => source, :pipeline_id => pipeline_id)
39
+
40
+ config_parts.each do |config_part|
41
+ logger.debug("Config string", :protocol => config_part.protocol, :id => config_part.id)
42
+ logger.debug("\n\n#{config_part.text}")
43
+ end
44
+ logger.debug("Merged config")
45
+ logger.debug("\n\n#{config_string}")
46
+ end
47
+ end
48
+ end end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ module LogStash module Config module Source
3
+ class Base
4
+ def initialize(settings)
5
+ @settings = settings
6
+ end
7
+
8
+ def pipeline_configs
9
+ raise NotImplementedError, "`#pipeline_configs` must be implemented!"
10
+ end
11
+
12
+ def match?
13
+ raise NotImplementedError, "`match?` must be implemented!"
14
+ end
15
+ end
16
+ end end end
@@ -0,0 +1,215 @@
1
+ # encoding: utf-8
2
+ require "logstash/config/source/base"
3
+ require "logstash/config/pipeline_config"
4
+ require "logstash/util/loggable"
5
+ require "logstash/errors"
6
+ require "uri"
7
+
8
+ module LogStash module Config module Source
9
+ # A locally defined configuration source
10
+ #
11
+ # Which can aggregate the following config options:
12
+ # - settings.config_string: "input { stdin {} }"
13
+ # - settings.config_path: /tmp/logstash/*.conf
14
+ # - settings.config_path: http://localhost/myconfig.conf
15
+ #
16
+ # All theses option will create a unique pipeline, generated parts will be
17
+ # sorted alphabetically. Se `PipelineConfig` class for the sorting algorithm.
18
+ #
19
+ class Local < Base
20
+ class ConfigStringLoader
21
+ def self.read(config_string)
22
+ [org.logstash.common.SourceWithMetadata.new("string", "config_string", config_string)]
23
+ end
24
+ end
25
+
26
+ class ConfigPathLoader
27
+ include LogStash::Util::Loggable
28
+
29
+ TEMPORARY_FILE_RE = /~$/
30
+ LOCAL_FILE_URI = /^file:\/\//i
31
+
32
+ def initialize(path)
33
+ @path = normalize_path(path)
34
+ end
35
+
36
+ def read
37
+ config_parts = []
38
+ encoding_issue_files = []
39
+
40
+ get_files.each do |file|
41
+ next unless ::File.file?(file) # skip directory
42
+
43
+ logger.debug("Reading config file", :config_file => file)
44
+
45
+ if temporary_file?(file)
46
+ logger.warn("NOT reading config file because it is a temp file", :config_file => file)
47
+ next
48
+ end
49
+
50
+ config_string = ::File.read(file)
51
+
52
+ if valid_encoding?(config_string)
53
+ part = org.logstash.common.SourceWithMetadata.new("file", file, config_string)
54
+ config_parts << part
55
+ else
56
+ encoding_issue_files << file
57
+ end
58
+ end
59
+
60
+ if encoding_issue_files.any?
61
+ raise LogStash::ConfigLoadingError, "The following config files contains non-ascii characters but are not UTF-8 encoded #{encoding_issue_files}"
62
+ end
63
+
64
+ if config_parts.empty?
65
+ logger.info("No config files found in path", :path => path)
66
+ end
67
+
68
+ config_parts
69
+ end
70
+
71
+ def self.read(path)
72
+ ConfigPathLoader.new(path).read
73
+ end
74
+
75
+ private
76
+ def normalize_path(path)
77
+ path.gsub!(LOCAL_FILE_URI, "")
78
+ ::File.expand_path(path)
79
+ end
80
+
81
+ def get_files
82
+ Dir.glob(path).sort
83
+ end
84
+
85
+ def path
86
+ if ::File.directory?(@path)
87
+ ::File.join(@path, "*")
88
+ else
89
+ @path
90
+ end
91
+ end
92
+
93
+ def valid_encoding?(content)
94
+ content.ascii_only? && content.valid_encoding?
95
+ end
96
+
97
+ def temporary_file?(filepath)
98
+ filepath.match(TEMPORARY_FILE_RE)
99
+ end
100
+ end
101
+
102
+ class ConfigRemoteLoader
103
+ def self.read(uri)
104
+ uri = URI.parse(uri)
105
+
106
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == "https") do |http|
107
+ request = Net::HTTP::Get.new(uri.path)
108
+ response = http.request(request)
109
+
110
+ # since we have fetching config we wont follow any redirection.
111
+ case response.code.to_i
112
+ when 200
113
+ [org.logstash.common.SourceWithMetadata.new(uri.scheme, uri.to_s, response.body)]
114
+ when 302
115
+ raise LogStash::ConfigLoadingError, I18n.t("logstash.runner.configuration.fetch-failed", :path => uri.to_s, :message => "We don't follow redirection for remote configuration")
116
+ when 404
117
+ raise LogStash::ConfigLoadingError, I18n.t("logstash.runner.configuration.fetch-failed", :path => uri.to_s, :message => "File not found")
118
+ when 403
119
+ raise LogStash::ConfigLoadingError, I18n.t("logstash.runner.configuration.fetch-failed", :path => uri.to_s, :message => "Permission denied")
120
+ when 500
121
+ raise LogStash::ConfigLoadingError, I18n.t("logstash.runner.configuration.fetch-failed", :path => uri.to_s, :message => "500 error on remote host")
122
+ else
123
+ raise LogStash::ConfigLoadingError, I18n.t("logstash.runner.configuration.fetch-failed", :path => uri.to_s, :message => "code: #{response.code}, message: #{response.class.to_s}")
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ PIPELINE_ID = LogStash::SETTINGS.get("pipeline.id").to_sym
130
+ HTTP_RE = /^http(s)?/
131
+ INPUT_BLOCK_RE = /input *{/
132
+ OUTPUT_BLOCK_RE = /output *{/
133
+
134
+ def pipeline_configs
135
+ config_parts = []
136
+
137
+ config_parts.concat(ConfigStringLoader.read(config_string)) if config_string?
138
+ if local_config?
139
+ local_config_parts = ConfigPathLoader.read(config_path)
140
+ config_parts.concat(local_config_parts)
141
+ else
142
+ local_config_parts = []
143
+ end
144
+
145
+ config_parts.concat(ConfigRemoteLoader.read(config_path)) if remote_config?
146
+
147
+ return if config_parts.empty?
148
+ return if config_string? && config_string.strip.empty? && local_config? && local_config_parts.empty?
149
+
150
+ add_missing_default_inputs_or_outputs(config_parts)
151
+
152
+ [PipelineConfig.new(self.class, PIPELINE_ID, config_parts, @settings)]
153
+ end
154
+
155
+ def match?
156
+ config_string? || config_path?
157
+ end
158
+
159
+ private
160
+ # Make sure we have an input and at least 1 output
161
+ # if its not the case we will add stdin and stdout
162
+ # this is for backward compatibility reason
163
+ def add_missing_default_inputs_or_outputs(config_parts)
164
+ if !config_parts.any? { |part| INPUT_BLOCK_RE.match(part.text) }
165
+ config_parts << org.logstash.common.SourceWithMetadata.new(self.class.name, "default input", LogStash::Config::Defaults.input)
166
+ end
167
+
168
+ # include a default stdout output if no outputs given
169
+ if !config_parts.any? { |part| OUTPUT_BLOCK_RE.match(part.text) }
170
+ config_parts << org.logstash.common.SourceWithMetadata.new(self.class.name, "default output", LogStash::Config::Defaults.output)
171
+ end
172
+ end
173
+
174
+ def config_string
175
+ @settings.get("config.string")
176
+ end
177
+
178
+ def config_string?
179
+ !config_string.nil?
180
+ end
181
+
182
+ def config_path
183
+ @settings.get("path.config")
184
+ end
185
+
186
+ def config_path?
187
+ !config_path.nil? && !config_path.empty?
188
+ end
189
+
190
+ def local_config?
191
+ return false unless config_path?
192
+
193
+ begin
194
+ uri = URI.parse(config_path)
195
+ uri.scheme == "file" || uri.scheme.nil?
196
+ rescue URI::InvalidURIError
197
+ # fallback for windows.
198
+ # if the parsing of the file failed we assume we can reach it locally.
199
+ # some relative path on windows arent parsed correctly (.\logstash.conf)
200
+ true
201
+ end
202
+ end
203
+
204
+ def remote_config?
205
+ return false unless config_path?
206
+
207
+ begin
208
+ uri = URI.parse(config_path)
209
+ uri.scheme =~ HTTP_RE
210
+ rescue URI::InvalidURIError
211
+ false
212
+ end
213
+ end
214
+ end
215
+ end end end