logstash-core 5.6.16-java → 6.0.0.alpha1-java

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -12,7 +12,7 @@ module LogStash
12
12
  end
13
13
 
14
14
  def host
15
- @@host ||= Socket.gethostname
15
+ Socket.gethostname
16
16
  end
17
17
 
18
18
  def version
@@ -1,5 +1,4 @@
1
1
  # encoding: utf-8
2
- java_import 'org.logstash.instrument.reports.ThreadsReport'
3
2
 
4
3
  class HotThreadsReport
5
4
  STRING_SEPARATOR_LENGTH = 80.freeze
@@ -8,7 +7,8 @@ class HotThreadsReport
8
7
  def initialize(cmd, options)
9
8
  @cmd = cmd
10
9
  filter = { :stacktrace_size => options.fetch(:stacktrace_size, HOT_THREADS_STACK_TRACES_SIZE_DEFAULT) }
11
- @thread_dump = ::LogStash::Util::ThreadDump.new(options.merge(:dump => ThreadsReport.generate(filter)))
10
+ jr_dump = JRMonitor.threads.generate(filter)
11
+ @thread_dump = ::LogStash::Util::ThreadDump.new(options.merge(:dump => jr_dump))
12
12
  end
13
13
 
14
14
  def to_s
@@ -17,12 +17,7 @@ class HotThreadsReport
17
17
  report << '=' * STRING_SEPARATOR_LENGTH
18
18
  report << "\n"
19
19
  hash[:threads].each do |thread|
20
- line_str = I18n.t("logstash.web_api.hot_threads.thread_title",
21
- :percent_of_cpu_time => thread[:percent_of_cpu_time],
22
- :thread_state => thread[:state],
23
- :thread_name => thread[:name],
24
- :thread_id => thread[:thread_id])
25
- thread_report = "#{line_str} \n"
20
+ thread_report = "#{I18n.t("logstash.web_api.hot_threads.thread_title", :percent_of_cpu_time => thread[:percent_of_cpu_time], :thread_state => thread[:state], :thread_name => thread[:name])} \n"
26
21
  thread_report << "#{thread[:path]}\n" if thread[:path]
27
22
  thread[:traces].each do |trace|
28
23
  thread_report << "\t#{trace}\n"
@@ -36,10 +31,9 @@ class HotThreadsReport
36
31
 
37
32
  def to_hash
38
33
  hash = { :time => Time.now.iso8601, :busiest_threads => @thread_dump.top_count, :threads => [] }
39
- @thread_dump.each do |_hash|
34
+ @thread_dump.each do |thread_name, _hash|
40
35
  thread_name, thread_path = _hash["thread.name"].split(": ")
41
36
  thread = { :name => thread_name,
42
- :thread_id => _hash["thread.id"],
43
37
  :percent_of_cpu_time => cpu_time_as_percent(_hash),
44
38
  :state => _hash["thread.state"]
45
39
  }
@@ -48,7 +42,7 @@ class HotThreadsReport
48
42
  _hash["thread.stacktrace"].each do |trace|
49
43
  traces << trace
50
44
  end
51
- thread[:traces] = traces
45
+ thread[:traces] = traces unless traces.empty?
52
46
  hash[:threads] << thread
53
47
  end
54
48
  { :hot_threads => hash }
@@ -20,8 +20,8 @@ module LogStash
20
20
  def pipeline(pipeline_id = LogStash::SETTINGS.get("pipeline.id").to_sym)
21
21
  stats = extract_metrics(
22
22
  [:stats, :pipelines, pipeline_id, :config],
23
- :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval, :dead_letter_queue_enabled, :dead_letter_queue_path
24
- ).reject{|_, v|v.nil?}
23
+ :workers, :batch_size, :batch_delay, :config_reload_automatic, :config_reload_interval
24
+ )
25
25
  stats.merge(:id => pipeline_id)
26
26
  end
27
27
 
@@ -40,6 +40,7 @@ module LogStash
40
40
  {
41
41
  :pid => ManagementFactory.getRuntimeMXBean().getName().split("@").first.to_i,
42
42
  :version => java.lang.System.getProperty("java.version"),
43
+ :vm_name => java.lang.System.getProperty("java.vm.name"),
43
44
  :vm_version => java.lang.System.getProperty("java.version"),
44
45
  :vm_vendor => java.lang.System.getProperty("java.vendor"),
45
46
  :vm_name => java.lang.System.getProperty("java.vm.name"),
@@ -54,6 +54,7 @@ module LogStash
54
54
  def memory
55
55
  memory = service.get_shallow(:jvm, :memory)
56
56
  {
57
+ :heap_used_in_bytes => memory[:heap][:used_in_bytes],
57
58
  :heap_used_percent => memory[:heap][:used_percent],
58
59
  :heap_committed_in_bytes => memory[:heap][:committed_in_bytes],
59
60
  :heap_max_in_bytes => memory[:heap][:max_in_bytes],
@@ -107,8 +108,8 @@ module LogStash
107
108
  },
108
109
  :reloads => stats[:reloads],
109
110
  :queue => stats[:queue]
110
- }.merge(stats[:dlq] ? {:dead_letter_queue => stats[:dlq]} : {})
111
- end
111
+ }
112
+ end
112
113
  end # module PluginsStats
113
114
  end
114
115
  end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require "logstash/util"
3
+ require "logstash/util/java_version"
4
+ require "logstash/errors"
5
+
6
+ module LogStash module BootstrapCheck
7
+ class BadJava
8
+ def self.check(settings)
9
+ # Exit on bad java versions
10
+ LogStash::Util::JavaVersion.validate_java_version!
11
+ rescue => e
12
+ # Just rewrap the original exception
13
+ raise LogStash::BootstrapCheckError, e.message
14
+ end
15
+ end
16
+ end end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ require "logstash/errors"
3
+
4
+ module LogStash module BootstrapCheck
5
+ class BadRuby
6
+ def self.check(settings)
7
+ if RUBY_VERSION < "1.9.2"
8
+ raise LogStash::BootstrapCheckError, "Ruby 1.9.2 or later is required. (You are running: " + RUBY_VERSION + ")"
9
+ end
10
+ end
11
+ end
12
+ end end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ require "logstash/errors"
3
+
4
+ module LogStash module BootstrapCheck
5
+ class DefaultConfig
6
+ def self.check(settings)
7
+ if settings.get("config.string").nil? && settings.get("path.config").nil?
8
+ raise LogStash::BootstrapCheckError, I18n.t("logstash.runner.missing-configuration")
9
+ end
10
+
11
+ if settings.get("config.reload.automatic") && settings.get("path.config").nil?
12
+ # there's nothing to reload
13
+ raise LogStash::BootstrapCheckError, I18n.t("logstash.runner.reload-without-config-path")
14
+ end
15
+ end
16
+ end
17
+ end end
@@ -0,0 +1,38 @@
1
+ require 'logstash/util/loggable'
2
+ require 'logstash/compiler/lscl/lscl_grammar'
3
+
4
+ java_import org.logstash.config.ir.Pipeline
5
+ java_import org.logstash.config.ir.graph.Graph;
6
+ java_import org.logstash.config.ir.graph.PluginVertex;
7
+
8
+ module LogStash; class Compiler
9
+ include ::LogStash::Util::Loggable
10
+
11
+ def self.compile_pipeline(config_str, source_file=nil)
12
+ graph_sections = self.compile_graph(config_str, source_file)
13
+ pipeline = org.logstash.config.ir.Pipeline.new(
14
+ graph_sections[:input],
15
+ graph_sections[:filter],
16
+ graph_sections[:output]
17
+ )
18
+ end
19
+
20
+ def self.compile_ast(config_str, source_file=nil)
21
+ grammar = LogStashCompilerLSCLGrammarParser.new
22
+ config = grammar.parse(config_str)
23
+
24
+ if config.nil?
25
+ raise ConfigurationError, grammar.failure_reason
26
+ end
27
+
28
+ config
29
+ end
30
+
31
+ def self.compile_imperative(config_str, source_file=nil)
32
+ compile_ast(config_str, source_file).compile(source_file)
33
+ end
34
+
35
+ def self.compile_graph(config_str, source_file=nil)
36
+ Hash[compile_imperative(config_str, source_file).map {|section,icompiled| [section, icompiled.toGraph]}]
37
+ end
38
+ end; end
@@ -0,0 +1,566 @@
1
+ # encoding: utf-8
2
+ require 'logstash/errors'
3
+ require "treetop"
4
+ require "logstash/compiler/treetop_monkeypatches"
5
+ java_import org.logstash.config.ir.DSL
6
+ java_import org.logstash.common.SourceWithMetadata
7
+
8
+ module LogStashCompilerLSCLGrammar; module LogStash; module Compiler; module LSCL; module AST
9
+ # Helpers for parsing LSCL files
10
+ module Helpers
11
+ def source_meta
12
+ line, column = line_and_column
13
+ org.logstash.common.SourceWithMetadata.new(source_file, line, column, self.text_value)
14
+ end
15
+
16
+ def source_file=(value)
17
+ set_meta(:source_file, value)
18
+ end
19
+
20
+ def source_file
21
+ get_meta(:source_file)
22
+ end
23
+
24
+ def compose(*statements)
25
+ compose_for(section_type.to_sym).call(source_meta, *statements)
26
+ end
27
+
28
+ def compose_for(section_sym)
29
+ if section_sym == :filter
30
+ jdsl.method(:iComposeSequence)
31
+ else
32
+ jdsl.method(:iComposeParallel)
33
+ end
34
+ end
35
+
36
+ def line_and_column
37
+ start = self.interval.first
38
+ [self.input.line_of(start), self.input.column_of(start)]
39
+ end
40
+
41
+ def empty_source_meta()
42
+ org.logstash.common.SourceWithMetadata.new()
43
+ end
44
+
45
+ def jdsl
46
+ org.logstash.config.ir.DSL
47
+ end
48
+
49
+ def self.jdsl
50
+ org.logstash.config.ir.DSL
51
+ end
52
+
53
+ AND_METHOD = jdsl.method(:eAnd)
54
+ OR_METHOD = jdsl.method(:eOr)
55
+ end
56
+
57
+ class Node < Treetop::Runtime::SyntaxNode
58
+ include Helpers
59
+
60
+ def section_type
61
+ if recursive_select_parent(Plugin).any?
62
+ return "codec"
63
+ else
64
+ section = recursive_select_parent(PluginSection)
65
+ return section.first.plugin_type.text_value
66
+ end
67
+ end
68
+ end
69
+
70
+ class Config < Node
71
+ include Helpers
72
+
73
+ def compile(source_file=nil)
74
+ # There is no way to move vars across nodes in treetop :(
75
+ self.source_file = source_file
76
+
77
+ sections = recursive_select(PluginSection)
78
+
79
+ section_map = {
80
+ :input => [],
81
+ :filter => [],
82
+ :output => []
83
+ }
84
+
85
+ sections.each do |section|
86
+ section_name = section.plugin_type.text_value.to_sym
87
+ section_expr = section.expr
88
+ raise "Unknown section name #{section_name}!" if ![:input, :output, :filter].include?(section_name)
89
+ ::Array[section_expr].each do |se|
90
+ section_map[section_name].concat se
91
+ end
92
+ end
93
+
94
+ section_map.keys.each do |key|
95
+ section_map[key] = compose_for(key).call(empty_source_meta, *section_map[key])
96
+ end
97
+
98
+ section_map
99
+ end
100
+ end
101
+
102
+ class Comment < Node; end
103
+ class Whitespace < Node; end
104
+
105
+ class PluginSection < Node
106
+ def expr
107
+ recursive_select(Branch, Plugin).map(&:expr)
108
+ end
109
+ end
110
+
111
+ class Plugins < Node; end
112
+ class Plugin < Node
113
+ def expr
114
+ jdsl.iPlugin(source_meta, plugin_type_enum, self.plugin_name, self.expr_attributes)
115
+ end
116
+
117
+ def plugin_type_enum
118
+ case section_type
119
+ when "input"
120
+ Java::OrgLogstashConfigIr::PluginDefinition::Type::INPUT
121
+ when "codec"
122
+ Java::OrgLogstashConfigIr::PluginDefinition::Type::CODEC
123
+ when "filter"
124
+ Java::OrgLogstashConfigIr::PluginDefinition::Type::FILTER
125
+ when "output"
126
+ Java::OrgLogstashConfigIr::PluginDefinition::Type::OUTPUT
127
+ end
128
+ end
129
+
130
+ def plugin_name
131
+ return name.text_value
132
+ end
133
+
134
+ def expr_attributes
135
+ # Turn attributes into a hash map
136
+ self.attributes.recursive_select(Attribute).map(&:expr).map {|k,v|
137
+ if v.java_kind_of?(Java::OrgLogstashConfigIrExpression::ValueExpression)
138
+ [k, v.get]
139
+ else
140
+ [k,v]
141
+ end
142
+ }.reduce({}) do |hash,kv|
143
+ k,v = kv
144
+ hash[k] = v
145
+ hash
146
+ end
147
+
148
+ end
149
+ end
150
+
151
+ class Name < Node
152
+ def expr
153
+ return text_value
154
+ end
155
+ end
156
+
157
+ class Attribute < Node
158
+ def expr
159
+ [name.text_value, value.expr]
160
+ end
161
+ end
162
+
163
+ class RValue < Node; end
164
+ class Value < RValue; end
165
+
166
+ class Bareword < Value
167
+ def expr
168
+ jdsl.eValue(source_meta, text_value)
169
+ end
170
+ end
171
+
172
+ class String < Value
173
+ def expr
174
+ jdsl.e_value(source_meta, text_value[1...-1])
175
+ end
176
+ end
177
+
178
+ class RegExp < Value
179
+ def expr
180
+ # Strip the slashes off
181
+ jdsl.eRegex(text_value[1..-2])
182
+ end
183
+ end
184
+
185
+ class Number < Value
186
+ def expr
187
+ jdsl.eValue(source_meta, text_value.include?(".") ?
188
+ text_value.to_f :
189
+ text_value.to_i)
190
+ end
191
+ end
192
+
193
+ class Array < Value
194
+ def expr
195
+ jdsl.eValue(source_meta, recursive_select(Value).map(&:expr).map(&:get))
196
+ end
197
+ end
198
+
199
+ class Hash < Value
200
+ def validate!
201
+ duplicate_values = find_duplicate_keys
202
+
203
+ if duplicate_values.size > 0
204
+ raise ConfigurationError.new(
205
+ I18n.t("logstash.runner.configuration.invalid_plugin_settings_duplicate_keys",
206
+ :keys => duplicate_values.join(', '),
207
+ :line => input.line_of(interval.first),
208
+ :column => input.column_of(interval.first),
209
+ :byte => interval.first + 1,
210
+ :after => input[0..interval.first]
211
+ )
212
+ )
213
+ end
214
+ end
215
+
216
+ def find_duplicate_keys
217
+ values = recursive_select(HashEntry).collect { |hash_entry| hash_entry.name.text_value }
218
+ values.find_all { |v| values.count(v) > 1 }.uniq
219
+ end
220
+
221
+ def expr
222
+ validate!
223
+ ::Hash[recursive_select(HashEntry).map(&:expr)]
224
+ end
225
+ end
226
+
227
+ class HashEntries < Node; end
228
+
229
+ class HashEntry < Node
230
+ def expr
231
+ return [name.expr.get, value.expr.get()]
232
+ end
233
+ end
234
+
235
+ class Branch < Node
236
+ def expr
237
+ # Build this stuff as s-expressions for convenience at first
238
+ # This will turn if/elsif/else blocks into nested if/else trees
239
+
240
+ exprs = []
241
+ else_stack = [] # For turning if / elsif / else into nested ifs
242
+
243
+ self.recursive_select(Plugin, If, Elsif, Else).each do |node|
244
+ if node.is_a?(If)
245
+ exprs << :if
246
+ exprs << expr_cond(node)
247
+ exprs << expr_body(node)
248
+ elsif node.is_a?(Elsif)
249
+ condition = expr_cond(node)
250
+ body = expr_body(node)
251
+ else_stack << [:if, condition, body]
252
+ elsif node.is_a?(Else)
253
+ body = expr_body(node)
254
+ if else_stack.size >= 1
255
+ else_stack.last << body
256
+ else
257
+ exprs << body
258
+ end
259
+ end
260
+ end
261
+
262
+ else_stack.reverse.each_cons(2) do |cons|
263
+ later,earlier = cons
264
+ earlier << later
265
+ end
266
+ exprs << else_stack.first
267
+
268
+ # Then convert to the imperative java IR
269
+ javaify_sexpr(exprs)
270
+ end
271
+
272
+ def javaify_sexpr(sexpr)
273
+ return nil if sexpr.nil?
274
+
275
+ head, tail = sexpr.first
276
+ tail = sexpr[1..-1]
277
+
278
+ if head == :if
279
+ condition, t_branch, f_branch = tail
280
+
281
+ java_t_branch = t_branch && javaify_sexpr(t_branch)
282
+ java_f_branch = f_branch && javaify_sexpr(f_branch)
283
+
284
+ if java_t_branch || java_f_branch
285
+ jdsl.iIf(condition, java_t_branch || jdsl.noop, java_f_branch || jdsl.noop)
286
+ else
287
+ jdsl.noop()
288
+ end
289
+ elsif head == :compose
290
+ tail && tail.size > 0 ? compose(*tail) : jdsl.noop
291
+ else
292
+ raise "Unknown expression #{sexpr}!"
293
+ end
294
+ end
295
+
296
+ def expr_cond(node)
297
+ node.elements.find {|e| e.is_a?(Condition)}.expr
298
+ end
299
+
300
+ def expr_body(node)
301
+ [:compose, *node.recursive_select(Plugin, Branch).map(&:expr)]
302
+ end
303
+ end
304
+
305
+ # Branch covers all these
306
+ class BranchEntry < Node; end
307
+ class If < BranchEntry; end
308
+ class Elsif < BranchEntry; end
309
+ class Else < BranchEntry; end
310
+
311
+ class Condition < Node
312
+ include Helpers
313
+
314
+ def expr
315
+ first_element = elements.first
316
+ rest_elements = elements.size > 1 ? elements[1].recursive_select(BooleanOperator, Expression, SelectorElement) : []
317
+
318
+ all_elements = [first_element, *rest_elements]
319
+
320
+ if all_elements.size == 1
321
+ elem = all_elements.first
322
+ if elem.is_a?(Selector)
323
+ eventValue = elem.recursive_select(SelectorElement).first.expr
324
+ jdsl.eTruthy(source_meta, eventValue)
325
+ elsif elem.is_a?(RegexpExpression)
326
+ elem.expr
327
+ else
328
+ join_conditions(all_elements)
329
+ end
330
+ else
331
+ join_conditions(all_elements)
332
+ end
333
+ end
334
+
335
+ def precedence(op)
336
+ # Believe this is right for logstash?
337
+ case op
338
+ when AND_METHOD
339
+ 2
340
+ when OR_METHOD
341
+ 1
342
+ else
343
+ raise ArgumentError, "Unexpected operator #{op}"
344
+ end
345
+ end
346
+
347
+ # Converts an sexpr of :and or :or to the java imperative IR
348
+ def jconvert(sexpr)
349
+ raise "jconvert cannot handle nils!" if sexpr.nil?
350
+
351
+ if sexpr.java_kind_of?(Java::OrgLogstashConfigIrExpression::Expression)
352
+ return sexpr
353
+ end
354
+
355
+ op, left, right = sexpr
356
+
357
+ left_c = jconvert(left)
358
+ right_c = jconvert(right)
359
+
360
+ case op
361
+ when :and
362
+ return jdsl.eAnd(left, right);
363
+ when :or
364
+ return jdsl.eOr(left, right);
365
+ else
366
+ raise "Unknown op #{jop}"
367
+ end
368
+ end
369
+
370
+ def join_conditions(all_elements)
371
+ # Use Dijkstra's shunting yard algorithm
372
+ out = []
373
+ operators = []
374
+
375
+ all_elements.each do |e|
376
+ e_exp = e.expr
377
+
378
+ if e.is_a?(BooleanOperator)
379
+ if operators.last && precedence(operators.last) > precedence(e_exp)
380
+ out << operators.pop
381
+ end
382
+ operators << e_exp
383
+ else
384
+ out << e_exp
385
+ end
386
+ end
387
+ operators.reverse.each {|o| out << o}
388
+
389
+ stack = []
390
+ expr = []
391
+ out.each do |e|
392
+ if e.is_a?(Symbol)
393
+ rval, lval = stack.pop, stack.pop
394
+ stack << jconvert([e, lval, rval])
395
+ elsif e.nil?
396
+ raise "Nil expr encountered! This should not happen!"
397
+ else
398
+ stack << e
399
+ end
400
+ end
401
+
402
+ stack_to_expr(stack)
403
+ end
404
+
405
+ def stack_to_expr(stack)
406
+ raise "Got an empty stack! This should not happen!" if stack.empty?
407
+ stack = stack.reverse # We need to work the stack in reverse order
408
+
409
+ working_stack = []
410
+ while elem = stack.pop
411
+ if elem.is_a?(::Method)
412
+ right, left = working_stack.pop, working_stack.pop
413
+ working_stack << elem.call(left, right)
414
+ else
415
+ working_stack << elem
416
+ end
417
+ end
418
+
419
+ raise "Invariant violated! Stack size > 1" if working_stack.size > 1
420
+
421
+ working_stack.first
422
+ end
423
+ end
424
+
425
+ module Expression
426
+ def expr
427
+ # If we have a more specific type (like a Negative expression) use that
428
+ if defined?(super)
429
+ return super
430
+ end
431
+
432
+ exprs = self.recursive_select(Condition, Selector).map(&:expr)
433
+
434
+ raise "Exprs should only have one part!" if exprs.size != 1
435
+ exprs.first
436
+ end
437
+ end
438
+
439
+ module NegativeExpression
440
+ include Helpers
441
+
442
+ def expr
443
+ exprs = self.recursive_select(Condition, Selector).map(&:expr)
444
+ raise "Negative exprs should only have one part!" if exprs.size != 1
445
+ jdsl.eNot(source_meta, exprs.first)
446
+ end
447
+ end
448
+
449
+ module ComparisonExpression
450
+ include Helpers
451
+
452
+ def expr
453
+ lval, comparison_method, rval = self.recursive_select(Selector, Expression, ComparisonOperator, Number, String).map(&:expr)
454
+ comparison_method.call(source_meta, lval, rval)
455
+ end
456
+ end
457
+
458
+ module InExpression
459
+ include Helpers
460
+
461
+ def expr
462
+ item, list = recursive_select(RValue)
463
+ jdsl.eIn(source_meta, item.expr, list.expr)
464
+ end
465
+ end
466
+
467
+ module NotInExpression
468
+ include Helpers
469
+
470
+ def expr
471
+ item, list = recursive_select(RValue)
472
+ jdsl.eNot(source_meta, jdsl.eIn(item.expr, list.expr))
473
+ end
474
+ end
475
+
476
+ # Not implemented because no one uses this
477
+ class MethodCall < Node; end
478
+
479
+ class RegexpExpression < Node
480
+ def expr
481
+ selector, operator_method, regexp = recursive_select(
482
+ Selector,
483
+ LogStash::Compiler::LSCL::AST::RegExpOperator,
484
+ LogStash::Compiler::LSCL::AST::RegExp,
485
+ LogStash::Compiler::LSCL::AST::String # Strings work as rvalues! :p
486
+ ).map(&:expr)
487
+
488
+ # Handle string rvalues, they just get turned into regexps
489
+ # Maybe we really shouldn't handle these anymore...
490
+ if regexp.class == org.logstash.config.ir.expression.ValueExpression
491
+ regexp = jdsl.eRegex(regexp.get)
492
+ end
493
+
494
+ raise "Expected a selector in #{text_value}!" unless selector
495
+ raise "Expected a regexp in #{text_value}!" unless regexp
496
+
497
+ operator_method.call(source_meta, selector, regexp);
498
+ end
499
+ end
500
+
501
+ module BranchOrPlugin; end
502
+
503
+ module ComparisonOperator
504
+ include Helpers
505
+
506
+ def expr
507
+ case self.text_value
508
+ when "=="
509
+ jdsl.method(:eEq)
510
+ when "!="
511
+ jdsl.method(:eNeq)
512
+ when ">"
513
+ jdsl.method(:eGt)
514
+ when "<"
515
+ jdsl.method(:eLt)
516
+ when ">="
517
+ jdsl.method(:eGte)
518
+ when "<="
519
+ jdsl.method(:eLte)
520
+ else
521
+ raise "Unknown operator #{self.text_value}"
522
+ end
523
+ end
524
+ end
525
+
526
+ module RegExpOperator
527
+ include Helpers
528
+
529
+ def expr
530
+ if self.text_value == '!~'
531
+ jdsl.method(:eRegexNeq)
532
+ elsif self.text_value == '=~'
533
+ jdsl.method(:eRegexEq)
534
+ else
535
+ raise "Unknown regex operator #{self.text_value}"
536
+ end
537
+ end
538
+ end
539
+
540
+ module BooleanOperator
541
+ include Helpers
542
+
543
+ def expr
544
+ case self.text_value
545
+ when "and"
546
+ AND_METHOD
547
+ when "or"
548
+ OR_METHOD
549
+ else
550
+ raise "Unknown operator #{self.text_value}"
551
+ end
552
+ end
553
+ end
554
+
555
+ class Selector < RValue
556
+ def expr
557
+ jdsl.eEventValue(source_meta, text_value)
558
+ end
559
+ end
560
+
561
+ class SelectorElement < Node;
562
+ def expr
563
+ jdsl.eEventValue(source_meta, text_value)
564
+ end
565
+ end
566
+ end; end; end; end; end;