logstash-core 2.2.4.snapshot1

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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-core.rb +1 -0
  3. data/lib/logstash-core/logstash-core.rb +3 -0
  4. data/lib/logstash-core/version.rb +8 -0
  5. data/lib/logstash/agent.rb +391 -0
  6. data/lib/logstash/codecs/base.rb +50 -0
  7. data/lib/logstash/config/config_ast.rb +550 -0
  8. data/lib/logstash/config/cpu_core_strategy.rb +32 -0
  9. data/lib/logstash/config/defaults.rb +12 -0
  10. data/lib/logstash/config/file.rb +39 -0
  11. data/lib/logstash/config/grammar.rb +3503 -0
  12. data/lib/logstash/config/mixin.rb +518 -0
  13. data/lib/logstash/config/registry.rb +13 -0
  14. data/lib/logstash/environment.rb +98 -0
  15. data/lib/logstash/errors.rb +12 -0
  16. data/lib/logstash/filters/base.rb +205 -0
  17. data/lib/logstash/inputs/base.rb +116 -0
  18. data/lib/logstash/inputs/threadable.rb +18 -0
  19. data/lib/logstash/java_integration.rb +116 -0
  20. data/lib/logstash/json.rb +61 -0
  21. data/lib/logstash/logging.rb +91 -0
  22. data/lib/logstash/namespace.rb +13 -0
  23. data/lib/logstash/output_delegator.rb +172 -0
  24. data/lib/logstash/outputs/base.rb +91 -0
  25. data/lib/logstash/patches.rb +5 -0
  26. data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
  27. data/lib/logstash/patches/cabin.rb +35 -0
  28. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  29. data/lib/logstash/patches/rubygems.rb +38 -0
  30. data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
  31. data/lib/logstash/pipeline.rb +499 -0
  32. data/lib/logstash/pipeline_reporter.rb +114 -0
  33. data/lib/logstash/plugin.rb +120 -0
  34. data/lib/logstash/program.rb +14 -0
  35. data/lib/logstash/runner.rb +124 -0
  36. data/lib/logstash/shutdown_watcher.rb +100 -0
  37. data/lib/logstash/util.rb +203 -0
  38. data/lib/logstash/util/buftok.rb +139 -0
  39. data/lib/logstash/util/charset.rb +35 -0
  40. data/lib/logstash/util/decorators.rb +52 -0
  41. data/lib/logstash/util/defaults_printer.rb +31 -0
  42. data/lib/logstash/util/filetools.rb +186 -0
  43. data/lib/logstash/util/java_version.rb +66 -0
  44. data/lib/logstash/util/password.rb +25 -0
  45. data/lib/logstash/util/plugin_version.rb +56 -0
  46. data/lib/logstash/util/prctl.rb +10 -0
  47. data/lib/logstash/util/retryable.rb +40 -0
  48. data/lib/logstash/util/socket_peer.rb +7 -0
  49. data/lib/logstash/util/unicode_trimmer.rb +81 -0
  50. data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
  51. data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
  52. data/lib/logstash/version.rb +14 -0
  53. data/locales/en.yml +204 -0
  54. data/logstash-core.gemspec +58 -0
  55. data/spec/conditionals_spec.rb +429 -0
  56. data/spec/logstash/agent_spec.rb +85 -0
  57. data/spec/logstash/config/config_ast_spec.rb +146 -0
  58. data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
  59. data/spec/logstash/config/defaults_spec.rb +10 -0
  60. data/spec/logstash/config/mixin_spec.rb +158 -0
  61. data/spec/logstash/environment_spec.rb +56 -0
  62. data/spec/logstash/filters/base_spec.rb +251 -0
  63. data/spec/logstash/inputs/base_spec.rb +74 -0
  64. data/spec/logstash/java_integration_spec.rb +304 -0
  65. data/spec/logstash/json_spec.rb +96 -0
  66. data/spec/logstash/output_delegator_spec.rb +144 -0
  67. data/spec/logstash/outputs/base_spec.rb +40 -0
  68. data/spec/logstash/patches_spec.rb +90 -0
  69. data/spec/logstash/pipeline_reporter_spec.rb +85 -0
  70. data/spec/logstash/pipeline_spec.rb +455 -0
  71. data/spec/logstash/plugin_spec.rb +169 -0
  72. data/spec/logstash/runner_spec.rb +68 -0
  73. data/spec/logstash/shutdown_watcher_spec.rb +113 -0
  74. data/spec/logstash/util/buftok_spec.rb +31 -0
  75. data/spec/logstash/util/charset_spec.rb +74 -0
  76. data/spec/logstash/util/defaults_printer_spec.rb +50 -0
  77. data/spec/logstash/util/java_version_spec.rb +79 -0
  78. data/spec/logstash/util/plugin_version_spec.rb +64 -0
  79. data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
  80. data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
  81. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
  82. data/spec/logstash/util_spec.rb +35 -0
  83. metadata +364 -0
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ require "logstash/namespace"
3
+ require "logstash/util"
4
+
5
+ # This class exists to format the settings for default worker threads
6
+ module LogStash module Util class WorkerThreadsDefaultPrinter
7
+
8
+ def initialize(settings)
9
+ @setting = settings.fetch(:pipeline_workers, 0)
10
+ @default = settings.fetch(:default_pipeline_workers, 0)
11
+ end
12
+
13
+ def visit(collector)
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 pipeline workers: #{@setting}")
21
+ end
22
+
23
+ def visit_default(collector)
24
+ return if @default == 0
25
+ collector.push "Default pipeline workers: #{@default}"
26
+ end
27
+
28
+ end end end
29
+
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module LogStash; module Util
4
+ class WrappedSynchronousQueue
5
+ java_import java.util.concurrent.SynchronousQueue
6
+ java_import java.util.concurrent.TimeUnit
7
+
8
+ def initialize()
9
+ @queue = java.util.concurrent.SynchronousQueue.new()
10
+ end
11
+
12
+ # Push an object to the queue if the queue is full
13
+ # it will block until the object can be added to the queue.
14
+ #
15
+ # @param [Object] Object to add to the queue
16
+ def push(obj)
17
+ @queue.put(obj)
18
+ end
19
+ alias_method(:<<, :push)
20
+
21
+ # Offer an object to the queue, wait for the specified amout of time.
22
+ # If adding to the queue was successfull it wil return true, false otherwise.
23
+ #
24
+ # @param [Object] Object to add to the queue
25
+ # @param [Integer] Time in milliseconds to wait before giving up
26
+ # @return [Boolean] True if adding was successfull if not it return false
27
+ def offer(obj, timeout_ms)
28
+ @queue.offer(obj, timeout_ms, TimeUnit::MILLISECONDS)
29
+ end
30
+
31
+ # Blocking
32
+ def take
33
+ @queue.take()
34
+ end
35
+
36
+ # Block for X millis
37
+ def poll(millis)
38
+ @queue.poll(millis, TimeUnit::MILLISECONDS)
39
+ end
40
+ end
41
+ end end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ # The version of the logstash package (not the logstash-core gem version).
4
+ #
5
+ # Note to authors: this should not include dashes because 'gem' barfs if
6
+ # you include a dash in the version string.
7
+
8
+ # TODO: (colin) the logstash-core gem uses it's own version number in logstash-core/lib/logstash-core/version.rb
9
+ # there are some dependencies in logstash-core on the LOGSTASH_VERSION constant this is why
10
+ # the logstash version is currently defined here in logstash-core/lib/logstash/version.rb but
11
+ # eventually this file should be in the root logstash lib fir and dependencies in logstash-core should be
12
+ # fixed.
13
+
14
+ LOGSTASH_VERSION = "2.2.4.snapshot1"
@@ -0,0 +1,204 @@
1
+ # YAML notes
2
+ # |- means 'scalar block' useful for formatted text
3
+ # > means 'scalar block' but it chomps all newlines. Useful
4
+ # for unformatted text.
5
+ en:
6
+ oops: |-
7
+ An unexpected error occurred!
8
+ logstash:
9
+ environment:
10
+ jruby-required: >-
11
+ JRuby is required
12
+ missing-jars: >-
13
+ Could not find jar files under %{pattern}
14
+ pipeline:
15
+ worker-error: |-
16
+ A plugin had an unrecoverable error. Will restart this plugin.
17
+ Plugin: %{plugin}
18
+ Error: %{error}
19
+ worker-error-debug: |-
20
+ A plugin had an unrecoverable error. Will restart this plugin.
21
+ Plugin: %{plugin}
22
+ Error: %{error}
23
+ Exception: %{exception}
24
+ Stack: %{stacktrace}
25
+ plugin-loading-error: >-
26
+ Couldn't find any %{type} plugin named '%{name}'. Are you
27
+ sure this is correct? Trying to load the %{name} %{type} plugin
28
+ resulted in this error: %{error}
29
+ plugin-type-loading-error: >-
30
+ Could not find any plugin type named '%{type}'. Check for typos.
31
+ Valid plugin types are 'input' 'filter' and 'output'
32
+ output-worker-unsupported: >-
33
+ %{plugin} output plugin: setting 'workers => %{worker_count}' is not
34
+ supported by this plugin. I will continue working as if you had not set
35
+ this setting.
36
+ output-worker-unsupported-with-message: >-
37
+ %{plugin} output plugin: setting 'workers => %{worker_count}' is not
38
+ supported by this plugin. I will continue working as if you had not set
39
+ this setting. Reason: %{message}
40
+ plugin:
41
+ deprecated_milestone: >-
42
+ %{plugin} plugin is using the 'milestone' method to declare the version
43
+ of the plugin this method is deprecated in favor of declaring the
44
+ version inside the gemspec.
45
+ no_version: >-
46
+ %{name} plugin doesn't have a version. This plugin isn't well
47
+ supported by the community and likely has no maintainer.
48
+ version:
49
+ 0-9-x:
50
+ Using version 0.9.x %{type} plugin '%{name}'. This plugin should work but
51
+ would benefit from use by folks like you. Please let us know if you
52
+ find bugs or have suggestions on how to improve this plugin.
53
+ 0-1-x: >-
54
+ Using version 0.1.x %{type} plugin '%{name}'. This plugin isn't well
55
+ supported by the community and likely has no maintainer.
56
+ agent:
57
+ sighup: >-
58
+ SIGHUP received.
59
+ missing-configuration: >-
60
+ No configuration file was specified. Perhaps you forgot to provide
61
+ the '-f yourlogstash.conf' flag?
62
+ error: >-
63
+ Error: %{error}
64
+ sigint: >-
65
+ SIGINT received. Shutting down the pipeline.
66
+ sigterm: >-
67
+ SIGTERM received. Shutting down the pipeline.
68
+ slow_shutdown: |-
69
+ Received shutdown signal, but pipeline is still waiting for in-flight events
70
+ to be processed. Sending another ^C will force quit Logstash, but this may cause
71
+ data loss.
72
+ forced_sigint: >-
73
+ SIGINT received. Terminating immediately..
74
+ configtest-flag-information: |-
75
+ You may be interested in the '--configtest' flag which you can
76
+ use to validate logstash's configuration before you choose
77
+ to restart a running system.
78
+ configuration:
79
+ obsolete: >-
80
+ The setting `%{name}` in plugin `%{plugin}` is obsolete and is no
81
+ longer available. %{extra} If you have any questions about this, you
82
+ are invited to visit https://discuss.elastic.co/c/logstash and ask.
83
+ file-not-found: |-
84
+ No config files found: %{path}
85
+ Can you make sure this path is a logstash config file?
86
+ scheme-not-supported: |-
87
+ URI scheme not supported: %{path}
88
+ Either pass a local file path or "file|http://" URI
89
+ fetch-failed: |-
90
+ Unable to fetch config from: %{path}
91
+ Reason: %{message}
92
+ setting_missing: |-
93
+ Missing a required setting for the %{plugin} %{type} plugin:
94
+
95
+ %{type} {
96
+ %{plugin} {
97
+ %{setting} => # SETTING MISSING
98
+ ...
99
+ }
100
+ }
101
+ setting_invalid: |-
102
+ Invalid setting for %{plugin} %{type} plugin:
103
+
104
+ %{type} {
105
+ %{plugin} {
106
+ # This setting must be a %{value_type}
107
+ # %{note}
108
+ %{setting} => %{value}
109
+ ...
110
+ }
111
+ }
112
+ invalid_plugin_settings: >-
113
+ Something is wrong with your configuration.
114
+ invalid_plugin_settings_duplicate_keys: |-
115
+ Duplicate keys found in your configuration: [%{keys}]
116
+ At line: %{line}, column %{column} (byte %{byte})
117
+ after %{after}
118
+ invalid_plugin_register: >-
119
+ Cannot register %{plugin} %{type} plugin.
120
+ The error reported is:
121
+ %{error}
122
+ plugin_path_missing: >-
123
+ You specified a plugin path that does not exist: %{path}
124
+ no_plugins_found: |-
125
+ Could not find any plugins in "%{path}"
126
+ I tried to find files matching the following, but found none:
127
+ %{plugin_glob}
128
+ log_file_failed: |-
129
+ Failed to open %{path} for writing: %{error}
130
+
131
+ This is often a permissions issue, or the wrong
132
+ path was specified?
133
+ flag:
134
+ # Note: Wrap these at 55 chars so they display nicely when clamp emits
135
+ # them in an 80-character terminal
136
+ config: |+
137
+ Load the logstash config from a specific file
138
+ or directory. If a directory is given, all
139
+ files in that directory will be concatenated
140
+ in lexicographical order and then parsed as a
141
+ single config file. You can also specify
142
+ wildcards (globs) and any matched files will
143
+ be loaded in the order described above.
144
+ config-string: |+
145
+ Use the given string as the configuration
146
+ data. Same syntax as the config file. If no
147
+ input is specified, then the following is
148
+ used as the default input:
149
+ "%{default_input}"
150
+ and if no output is specified, then the
151
+ following is used as the default output:
152
+ "%{default_output}"
153
+ If you wish to use both defaults, please use
154
+ the empty string for the '-e' flag.
155
+ configtest: |+
156
+ Check configuration for valid syntax and then exit.
157
+ pipeline-workers: |+
158
+ Sets the number of pipeline workers to run.
159
+ filterworkers: |+
160
+ DEPRECATED. Now an alias for --pipeline-workers and -w
161
+ pipeline-batch-size: |+
162
+ Size of batches the pipeline is to work in.
163
+ pipeline-batch-delay: |+
164
+ When creating pipeline batches, how long to wait while polling
165
+ for the next event.
166
+ log: |+
167
+ Write logstash internal logs to the given
168
+ file. Without this flag, logstash will emit
169
+ logs to standard output.
170
+ verbosity: |+
171
+ Increase verbosity of logstash internal logs.
172
+ Specifying once will show 'informational'
173
+ logs. Specifying twice will show 'debug'
174
+ logs. This flag is deprecated. You should use
175
+ --verbose or --debug instead.
176
+ version: |+
177
+ Emit the version of logstash and its friends,
178
+ then exit.
179
+ pluginpath: |+
180
+ A path of where to find plugins. This flag
181
+ can be given multiple times to include
182
+ multiple paths. Plugins are expected to be
183
+ in a specific directory hierarchy:
184
+ 'PATH/logstash/TYPE/NAME.rb' where TYPE is
185
+ 'inputs' 'filters', 'outputs' or 'codecs'
186
+ and NAME is the name of the plugin.
187
+ quiet: |+
188
+ Quieter logstash logging. This causes only
189
+ errors to be emitted.
190
+ verbose: |+
191
+ More verbose logging. This causes 'info'
192
+ level logs to be emitted.
193
+ debug: |+
194
+ Most verbose logging. This causes 'debug'
195
+ level logs to be emitted.
196
+ debug-config: |+
197
+ Print the compiled config ruby code out as a debug log (you must also have --debug enabled).
198
+ WARNING: This will include any 'password' options passed to plugin configs as plaintext, and may result
199
+ in plaintext passwords appearing in your logs!
200
+ unsafe_shutdown: |+
201
+ Force logstash to exit during shutdown even
202
+ if there are still inflight events in memory.
203
+ By default, logstash will refuse to quit until all
204
+ received events have been pushed to the outputs.
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'logstash-core/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Elastic"]
8
+ gem.email = ["info@elastic.co"]
9
+ gem.description = %q{The core components of logstash, the scalable log and event management tool}
10
+ gem.summary = %q{logstash-core - The core components of logstash}
11
+ gem.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
12
+ gem.license = "Apache License (2.0)"
13
+
14
+ gem.files = Dir.glob(["logstash-core.gemspec", "lib/**/*.rb", "spec/**/*.rb", "locales/*"])
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "logstash-core"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = LOGSTASH_CORE_VERSION
19
+
20
+ gem.add_runtime_dependency "logstash-core-event", "~> 2.2.4.snapshot1"
21
+
22
+ gem.add_runtime_dependency "cabin", "~> 0.7.0" #(Apache 2.0 license)
23
+ gem.add_runtime_dependency "pry", "~> 0.10.1" #(Ruby license)
24
+ gem.add_runtime_dependency "stud", "~> 0.0.19" #(Apache 2.0 license)
25
+ gem.add_runtime_dependency "clamp", "~> 0.6.5" #(MIT license) for command line args/flags
26
+ gem.add_runtime_dependency "filesize", "0.0.4" #(MIT license) for :bytes config validator
27
+ gem.add_runtime_dependency "gems", "~> 0.8.3" #(MIT license)
28
+ gem.add_runtime_dependency "concurrent-ruby", "0.9.2"
29
+ gem.add_runtime_dependency "jruby-openssl", "0.9.13" # Required to support TLSv1.2
30
+
31
+ # TODO(sissel): Treetop 1.5.x doesn't seem to work well, but I haven't
32
+ # investigated what the cause might be. -Jordan
33
+ gem.add_runtime_dependency "treetop", "< 1.5.0" #(MIT license)
34
+
35
+ # upgrade i18n only post 0.6.11, see https://github.com/svenfuchs/i18n/issues/270
36
+ gem.add_runtime_dependency "i18n", "= 0.6.9" #(MIT license)
37
+
38
+ # filetools and rakelib
39
+ gem.add_runtime_dependency "minitar", "~> 0.5.4"
40
+ gem.add_runtime_dependency "rubyzip", "~> 1.1.7"
41
+ gem.add_runtime_dependency "thread_safe", "~> 0.3.5" #(Apache 2.0 license)
42
+
43
+ if RUBY_PLATFORM == 'java'
44
+ gem.platform = RUBY_PLATFORM
45
+ gem.add_runtime_dependency "jrjackson", "~> 0.3.7" #(Apache 2.0 license)
46
+ else
47
+ gem.add_runtime_dependency "oj" #(MIT-style license)
48
+ end
49
+
50
+ if RUBY_ENGINE == "rbx"
51
+ # rubinius puts the ruby stdlib into gems.
52
+ gem.add_runtime_dependency "rubysl"
53
+
54
+ # Include racc to make the xml tests pass.
55
+ # https://github.com/rubinius/rubinius/issues/2632#issuecomment-26954565
56
+ gem.add_runtime_dependency "racc"
57
+ end
58
+ end
@@ -0,0 +1,429 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ module ConditionalFanciness
5
+ def description
6
+ return self.metadata[:description]
7
+ end
8
+
9
+ def conditional(expression, &block)
10
+ describe(expression) do
11
+ config <<-CONFIG
12
+ filter {
13
+ if #{expression} {
14
+ mutate { add_tag => "success" }
15
+ } else {
16
+ mutate { add_tag => "failure" }
17
+ }
18
+ }
19
+ CONFIG
20
+ instance_eval(&block)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "conditionals in output" do
26
+ extend ConditionalFanciness
27
+
28
+ describe "simple" do
29
+ config <<-CONFIG
30
+ input {
31
+ generator {
32
+ message => '{"foo":{"bar"},"baz": "quux"}'
33
+ count => 1
34
+ }
35
+ }
36
+ output {
37
+ if [foo] == "bar" {
38
+ stdout { }
39
+ }
40
+ }
41
+ CONFIG
42
+
43
+ agent do
44
+ #LOGSTASH-2288, should not fail raising an exception
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "conditionals in filter" do
50
+ extend ConditionalFanciness
51
+
52
+ describe "simple" do
53
+ config <<-CONFIG
54
+ filter {
55
+ mutate { add_field => { "always" => "awesome" } }
56
+ if [foo] == "bar" {
57
+ mutate { add_field => { "hello" => "world" } }
58
+ } else if [bar] == "baz" {
59
+ mutate { add_field => { "fancy" => "pants" } }
60
+ } else {
61
+ mutate { add_field => { "free" => "hugs" } }
62
+ }
63
+ }
64
+ CONFIG
65
+
66
+ sample({"foo" => "bar"}) do
67
+ expect(subject["always"]).to eq("awesome")
68
+ expect(subject["hello"]).to eq("world")
69
+ expect(subject["fancy"]).to be_nil
70
+ expect(subject["free"]).to be_nil
71
+ end
72
+
73
+ sample({"notfoo" => "bar"}) do
74
+ expect(subject["always"]).to eq("awesome")
75
+ expect(subject["hello"]).to be_nil
76
+ expect(subject["fancy"]).to be_nil
77
+ expect(subject["free"]).to eq("hugs")
78
+ end
79
+
80
+ sample({"bar" => "baz"}) do
81
+ expect(subject["always"]).to eq("awesome")
82
+ expect(subject["hello"]).to be_nil
83
+ expect(subject["fancy"]).to eq("pants")
84
+ expect(subject["free"]).to be_nil
85
+ end
86
+ end
87
+
88
+ describe "nested" do
89
+ config <<-CONFIG
90
+ filter {
91
+ if [nest] == 123 {
92
+ mutate { add_field => { "always" => "awesome" } }
93
+ if [foo] == "bar" {
94
+ mutate { add_field => { "hello" => "world" } }
95
+ } else if [bar] == "baz" {
96
+ mutate { add_field => { "fancy" => "pants" } }
97
+ } else {
98
+ mutate { add_field => { "free" => "hugs" } }
99
+ }
100
+ }
101
+ }
102
+ CONFIG
103
+
104
+ sample("foo" => "bar", "nest" => 124) do
105
+ expect(subject["always"]).to be_nil
106
+ expect(subject["hello"]).to be_nil
107
+ expect(subject["fancy"]).to be_nil
108
+ expect(subject["free"]).to be_nil
109
+ end
110
+
111
+ sample("foo" => "bar", "nest" => 123) do
112
+ expect(subject["always"]).to eq("awesome")
113
+ expect(subject["hello"]).to eq("world")
114
+ expect(subject["fancy"]).to be_nil
115
+ expect(subject["free"]).to be_nil
116
+ end
117
+
118
+ sample("notfoo" => "bar", "nest" => 123) do
119
+ expect(subject["always"]).to eq("awesome")
120
+ expect(subject["hello"]).to be_nil
121
+ expect(subject["fancy"]).to be_nil
122
+ expect(subject["free"]).to eq("hugs")
123
+ end
124
+
125
+ sample("bar" => "baz", "nest" => 123) do
126
+ expect(subject["always"]).to eq("awesome")
127
+ expect(subject["hello"]).to be_nil
128
+ expect(subject["fancy"]).to eq("pants")
129
+ expect(subject["free"]).to be_nil
130
+ end
131
+ end
132
+
133
+ describe "comparing two fields" do
134
+ config <<-CONFIG
135
+ filter {
136
+ if [foo] == [bar] {
137
+ mutate { add_tag => woot }
138
+ }
139
+ }
140
+ CONFIG
141
+
142
+ sample("foo" => 123, "bar" => 123) do
143
+ expect(subject["tags"] ).to include("woot")
144
+ end
145
+ end
146
+
147
+ describe "the 'in' operator" do
148
+ config <<-CONFIG
149
+ filter {
150
+ if [foo] in [foobar] {
151
+ mutate { add_tag => "field in field" }
152
+ }
153
+ if [foo] in "foo" {
154
+ mutate { add_tag => "field in string" }
155
+ }
156
+ if "hello" in [greeting] {
157
+ mutate { add_tag => "string in field" }
158
+ }
159
+ if [foo] in ["hello", "world", "foo"] {
160
+ mutate { add_tag => "field in list" }
161
+ }
162
+ if [missing] in [alsomissing] {
163
+ mutate { add_tag => "shouldnotexist" }
164
+ }
165
+ if !("foo" in ["hello", "world"]) {
166
+ mutate { add_tag => "shouldexist" }
167
+ }
168
+ }
169
+ CONFIG
170
+
171
+ sample("foo" => "foo", "foobar" => "foobar", "greeting" => "hello world") do
172
+ expect(subject["tags"]).to include("field in field")
173
+ expect(subject["tags"]).to include("field in string")
174
+ expect(subject["tags"]).to include("string in field")
175
+ expect(subject["tags"]).to include("field in list")
176
+ expect(subject["tags"]).not_to include("shouldnotexist")
177
+ expect(subject["tags"]).to include("shouldexist")
178
+ end
179
+ end
180
+
181
+ describe "the 'not in' operator" do
182
+ config <<-CONFIG
183
+ filter {
184
+ if "foo" not in "baz" { mutate { add_tag => "baz" } }
185
+ if "foo" not in "foo" { mutate { add_tag => "foo" } }
186
+ if !("foo" not in "foo") { mutate { add_tag => "notfoo" } }
187
+ if "foo" not in [somelist] { mutate { add_tag => "notsomelist" } }
188
+ if "one" not in [somelist] { mutate { add_tag => "somelist" } }
189
+ if "foo" not in [alsomissing] { mutate { add_tag => "no string in missing field" } }
190
+ }
191
+ CONFIG
192
+
193
+ sample("foo" => "foo", "somelist" => [ "one", "two" ], "foobar" => "foobar", "greeting" => "hello world", "tags" => [ "fancypantsy" ]) do
194
+ # verify the original exists
195
+ expect(subject["tags"]).to include("fancypantsy")
196
+
197
+ expect(subject["tags"]).to include("baz")
198
+ expect(subject["tags"]).not_to include("foo")
199
+ expect(subject["tags"]).to include("notfoo")
200
+ expect(subject["tags"]).to include("notsomelist")
201
+ expect(subject["tags"]).not_to include("somelist")
202
+ expect(subject["tags"]).to include("no string in missing field")
203
+ end
204
+ end
205
+
206
+ describe "operators" do
207
+ conditional "[message] == 'sample'" do
208
+ sample("sample") { expect(subject["tags"] ).to include("success") }
209
+ sample("different") { expect(subject["tags"] ).to include("failure") }
210
+ end
211
+
212
+ conditional "[message] != 'sample'" do
213
+ sample("sample") { expect(subject["tags"] ).to include("failure") }
214
+ sample("different") { expect(subject["tags"] ).to include("success") }
215
+ end
216
+
217
+ conditional "[message] < 'sample'" do
218
+ sample("apple") { expect(subject["tags"] ).to include("success") }
219
+ sample("zebra") { expect(subject["tags"] ).to include("failure") }
220
+ end
221
+
222
+ conditional "[message] > 'sample'" do
223
+ sample("zebra") { expect(subject["tags"] ).to include("success") }
224
+ sample("apple") { expect(subject["tags"] ).to include("failure") }
225
+ end
226
+
227
+ conditional "[message] <= 'sample'" do
228
+ sample("apple") { expect(subject["tags"] ).to include("success") }
229
+ sample("zebra") { expect(subject["tags"] ).to include("failure") }
230
+ sample("sample") { expect(subject["tags"] ).to include("success") }
231
+ end
232
+
233
+ conditional "[message] >= 'sample'" do
234
+ sample("zebra") { expect(subject["tags"] ).to include("success") }
235
+ sample("sample") { expect(subject["tags"] ).to include("success") }
236
+ sample("apple") { expect(subject["tags"] ).to include("failure") }
237
+ end
238
+
239
+ conditional "[message] =~ /sample/" do
240
+ sample("apple") { expect(subject["tags"] ).to include("failure") }
241
+ sample("sample") { expect(subject["tags"] ).to include("success") }
242
+ sample("some sample") { expect(subject["tags"] ).to include("success") }
243
+ end
244
+
245
+ conditional "[message] !~ /sample/" do
246
+ sample("apple") { expect(subject["tags"]).to include("success") }
247
+ sample("sample") { expect(subject["tags"]).to include("failure") }
248
+ sample("some sample") { expect(subject["tags"]).to include("failure") }
249
+ end
250
+
251
+ end
252
+
253
+ describe "negated expressions" do
254
+ conditional "!([message] == 'sample')" do
255
+ sample("sample") { expect(subject["tags"]).not_to include("success") }
256
+ sample("different") { expect(subject["tags"]).not_to include("failure") }
257
+ end
258
+
259
+ conditional "!([message] != 'sample')" do
260
+ sample("sample") { expect(subject["tags"]).not_to include("failure") }
261
+ sample("different") { expect(subject["tags"]).not_to include("success") }
262
+ end
263
+
264
+ conditional "!([message] < 'sample')" do
265
+ sample("apple") { expect(subject["tags"]).not_to include("success") }
266
+ sample("zebra") { expect(subject["tags"]).not_to include("failure") }
267
+ end
268
+
269
+ conditional "!([message] > 'sample')" do
270
+ sample("zebra") { expect(subject["tags"]).not_to include("success") }
271
+ sample("apple") { expect(subject["tags"]).not_to include("failure") }
272
+ end
273
+
274
+ conditional "!([message] <= 'sample')" do
275
+ sample("apple") { expect(subject["tags"]).not_to include("success") }
276
+ sample("zebra") { expect(subject["tags"]).not_to include("failure") }
277
+ sample("sample") { expect(subject["tags"]).not_to include("success") }
278
+ end
279
+
280
+ conditional "!([message] >= 'sample')" do
281
+ sample("zebra") { expect(subject["tags"]).not_to include("success") }
282
+ sample("sample") { expect(subject["tags"]).not_to include("success") }
283
+ sample("apple") { expect(subject["tags"]).not_to include("failure") }
284
+ end
285
+
286
+ conditional "!([message] =~ /sample/)" do
287
+ sample("apple") { expect(subject["tags"]).not_to include("failure") }
288
+ sample("sample") { expect(subject["tags"]).not_to include("success") }
289
+ sample("some sample") { expect(subject["tags"]).not_to include("success") }
290
+ end
291
+
292
+ conditional "!([message] !~ /sample/)" do
293
+ sample("apple") { expect(subject["tags"]).not_to include("success") }
294
+ sample("sample") { expect(subject["tags"]).not_to include("failure") }
295
+ sample("some sample") { expect(subject["tags"]).not_to include("failure") }
296
+ end
297
+
298
+ end
299
+
300
+ describe "value as an expression" do
301
+ # testing that a field has a value should be true.
302
+ conditional "[message]" do
303
+ sample("apple") { expect(subject["tags"]).to include("success") }
304
+ sample("sample") { expect(subject["tags"]).to include("success") }
305
+ sample("some sample") { expect(subject["tags"]).to include("success") }
306
+ end
307
+
308
+ # testing that a missing field has a value should be false.
309
+ conditional "[missing]" do
310
+ sample("apple") { expect(subject["tags"]).to include("failure") }
311
+ sample("sample") { expect(subject["tags"]).to include("failure") }
312
+ sample("some sample") { expect(subject["tags"]).to include("failure") }
313
+ end
314
+ end
315
+
316
+ describe "logic operators" do
317
+ describe "and" do
318
+ conditional "[message] and [message]" do
319
+ sample("whatever") { expect(subject["tags"]).to include("success") }
320
+ end
321
+ conditional "[message] and ![message]" do
322
+ sample("whatever") { expect(subject["tags"]).to include("failure") }
323
+ end
324
+ conditional "![message] and [message]" do
325
+ sample("whatever") { expect(subject["tags"]).to include("failure") }
326
+ end
327
+ conditional "![message] and ![message]" do
328
+ sample("whatever") { expect(subject["tags"]).to include("failure") }
329
+ end
330
+ end
331
+
332
+ describe "or" do
333
+ conditional "[message] or [message]" do
334
+ sample("whatever") { expect(subject["tags"]).to include("success") }
335
+ end
336
+ conditional "[message] or ![message]" do
337
+ sample("whatever") { expect(subject["tags"]).to include("success") }
338
+ end
339
+ conditional "![message] or [message]" do
340
+ sample("whatever") { expect(subject["tags"]).to include("success") }
341
+ end
342
+ conditional "![message] or ![message]" do
343
+ sample("whatever") { expect(subject["tags"]).to include("failure") }
344
+ end
345
+ end
346
+ end
347
+
348
+ describe "field references" do
349
+ conditional "[field with space]" do
350
+ sample("field with space" => "hurray") do
351
+ expect(subject["tags"]).to include("success")
352
+ end
353
+ end
354
+
355
+ conditional "[field with space] == 'hurray'" do
356
+ sample("field with space" => "hurray") do
357
+ expect(subject["tags"]).to include("success")
358
+ end
359
+ end
360
+
361
+ conditional "[nested field][reference with][some spaces] == 'hurray'" do
362
+ sample({"nested field" => { "reference with" => { "some spaces" => "hurray" } } }) do
363
+ expect(subject["tags"]).to include("success")
364
+ end
365
+ end
366
+ end
367
+
368
+ describe "new events from root" do
369
+ config <<-CONFIG
370
+ filter {
371
+ if [type] == "original" {
372
+ clone {
373
+ clones => ["clone"]
374
+ }
375
+ }
376
+ if [type] == "original" {
377
+ mutate { add_field => { "cond1" => "true" } }
378
+ } else {
379
+ mutate { add_field => { "cond2" => "true" } }
380
+ }
381
+ }
382
+ CONFIG
383
+
384
+ sample({"type" => "original"}) do
385
+ expect(subject).to be_an(Array)
386
+ expect(subject.length).to eq(2)
387
+
388
+ expect(subject[0]["type"]).to eq("original")
389
+ expect(subject[0]["cond1"]).to eq("true")
390
+ expect(subject[0]["cond2"]).to eq(nil)
391
+
392
+ expect(subject[1]["type"]).to eq("clone")
393
+ # expect(subject[1]["cond1"]).to eq(nil)
394
+ # expect(subject[1]["cond2"]).to eq("true")
395
+ end
396
+ end
397
+
398
+ describe "multiple new events from root" do
399
+ config <<-CONFIG
400
+ filter {
401
+ if [type] == "original" {
402
+ clone {
403
+ clones => ["clone1", "clone2"]
404
+ }
405
+ }
406
+ if [type] == "clone1" {
407
+ mutate { add_field => { "cond1" => "true" } }
408
+ } else if [type] == "clone2" {
409
+ mutate { add_field => { "cond2" => "true" } }
410
+ }
411
+ }
412
+ CONFIG
413
+
414
+ sample({"type" => "original"}) do
415
+ # puts subject.inspect
416
+ expect(subject[0]["cond1"]).to eq(nil)
417
+ expect(subject[0]["cond2"]).to eq(nil)
418
+
419
+ expect(subject[1]["type"]).to eq("clone1")
420
+ expect(subject[1]["cond1"]).to eq("true")
421
+ expect(subject[1]["cond2"]).to eq(nil)
422
+
423
+ expect(subject[2]["type"]).to eq("clone2")
424
+ expect(subject[2]["cond1"]).to eq(nil)
425
+ expect(subject[2]["cond2"]).to eq("true")
426
+ end
427
+ end
428
+
429
+ end