logstash-output-opensearch 1.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ADMINS.md +29 -0
  5. data/CODE_OF_CONDUCT.md +25 -0
  6. data/CONTRIBUTING.md +99 -0
  7. data/DEVELOPER_GUIDE.md +208 -0
  8. data/Gemfile +20 -0
  9. data/LICENSE +202 -0
  10. data/MAINTAINERS.md +71 -0
  11. data/NOTICE +2 -0
  12. data/README.md +37 -0
  13. data/RELEASING.md +36 -0
  14. data/SECURITY.md +3 -0
  15. data/lib/logstash/outputs/opensearch.rb +449 -0
  16. data/lib/logstash/outputs/opensearch/distribution_checker.rb +44 -0
  17. data/lib/logstash/outputs/opensearch/http_client.rb +465 -0
  18. data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +140 -0
  19. data/lib/logstash/outputs/opensearch/http_client/pool.rb +467 -0
  20. data/lib/logstash/outputs/opensearch/http_client_builder.rb +182 -0
  21. data/lib/logstash/outputs/opensearch/template_manager.rb +60 -0
  22. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x.json +44 -0
  23. data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x.json +44 -0
  24. data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +168 -0
  25. data/lib/logstash/plugin_mixins/opensearch/common.rb +294 -0
  26. data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +18 -0
  27. data/logstash-output-opensearch.gemspec +40 -0
  28. data/spec/fixtures/_nodes/nodes.json +74 -0
  29. data/spec/fixtures/htpasswd +2 -0
  30. data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
  31. data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
  32. data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
  33. data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
  34. data/spec/integration/outputs/compressed_indexing_spec.rb +76 -0
  35. data/spec/integration/outputs/create_spec.rb +76 -0
  36. data/spec/integration/outputs/delete_spec.rb +72 -0
  37. data/spec/integration/outputs/index_spec.rb +164 -0
  38. data/spec/integration/outputs/index_version_spec.rb +110 -0
  39. data/spec/integration/outputs/ingest_pipeline_spec.rb +82 -0
  40. data/spec/integration/outputs/metrics_spec.rb +75 -0
  41. data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +67 -0
  42. data/spec/integration/outputs/painless_update_spec.rb +147 -0
  43. data/spec/integration/outputs/parent_spec.rb +103 -0
  44. data/spec/integration/outputs/retry_spec.rb +182 -0
  45. data/spec/integration/outputs/routing_spec.rb +70 -0
  46. data/spec/integration/outputs/sniffer_spec.rb +70 -0
  47. data/spec/integration/outputs/templates_spec.rb +105 -0
  48. data/spec/integration/outputs/update_spec.rb +123 -0
  49. data/spec/opensearch_spec_helper.rb +141 -0
  50. data/spec/spec_helper.rb +19 -0
  51. data/spec/unit/http_client_builder_spec.rb +194 -0
  52. data/spec/unit/outputs/error_whitelist_spec.rb +62 -0
  53. data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +159 -0
  54. data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +306 -0
  55. data/spec/unit/outputs/opensearch/http_client_spec.rb +292 -0
  56. data/spec/unit/outputs/opensearch/template_manager_spec.rb +36 -0
  57. data/spec/unit/outputs/opensearch_proxy_spec.rb +112 -0
  58. data/spec/unit/outputs/opensearch_spec.rb +800 -0
  59. data/spec/unit/outputs/opensearch_ssl_spec.rb +179 -0
  60. metadata +289 -0
  61. metadata.gz.sig +0 -0
data/MAINTAINERS.md ADDED
@@ -0,0 +1,71 @@
1
+ - [Overview](#overview)
2
+ - [Current Maintainers](#current-maintainers)
3
+ - [Maintainer Responsibilities](#maintainer-responsibilities)
4
+ - [Uphold Code of Conduct](#uphold-code-of-conduct)
5
+ - [Prioritize Security](#prioritize-security)
6
+ - [Review Pull Requests](#review-pull-requests)
7
+ - [Triage Open Issues](#triage-open-issues)
8
+ - [Be Responsive](#be-responsive)
9
+ - [Maintain Overall Health of the Repo](#maintain-overall-health-of-the-repo)
10
+ - [Use Semver](#use-semver)
11
+ - [Release Frequently](#release-frequently)
12
+ - [Promote Other Maintainers](#promote-other-maintainers)
13
+
14
+ ## Overview
15
+
16
+ This document explains who the maintainers are (see below), what they do in this repo, and how they should be doing it. If you're interested in contributing, see [CONTRIBUTING](CONTRIBUTING.md).
17
+
18
+ ## Current Maintainers
19
+
20
+ | Maintainer | GitHub ID | Affiliation |
21
+ | ------------------------ | --------------------------------------- | ----------- |
22
+ | Jack Mazanec | [jmazanec15](https://github.com/jmazanec15) | Amazon |
23
+ | Vamshi Vijay Nakkirtha | [vamshin](https://github.com/vamshin) | Amazon |
24
+ | Vijayan Balasubramanian | [VijayanB](https://github.com/VijayanB) | Amazon |
25
+
26
+ ## Maintainer Responsibilities
27
+
28
+ Maintainers are active and visible members of the community, and have [maintain-level permissions on a repository](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization). Use those privileges to serve the community and evolve code as follows.
29
+
30
+ ### Uphold Code of Conduct
31
+
32
+ Model the behavior set forward by the [Code of Conduct](CODE_OF_CONDUCT.md) and raise any violations to other maintainers and admins.
33
+
34
+ ### Prioritize Security
35
+
36
+ Security is your number one priority. Maintainer's Github keys must be password protected securely and any reported security vulnerabilities are addressed before features or bugs.
37
+
38
+ Note that this repository is monitored and supported 24/7 by Amazon Security, see [Reporting a Vulnerability](SECURITY.md) for details.
39
+
40
+ ### Review Pull Requests
41
+
42
+ Review pull requests regularly, comment, suggest, reject, merge and close. Accept only high quality pull-requests. Provide code reviews and guidance on incomming pull requests. Don't let PRs be stale and do your best to be helpful to contributors.
43
+
44
+ ### Triage Open Issues
45
+
46
+ Manage labels, review issues regularly, and triage by labelling them.
47
+
48
+ All repositories in this organization have a standard set of labels, including `bug`, `documentation`, `duplicate`, `enhancement`, `good first issue`, `help wanted`, `blocker`, `invalid`, `question`, `wontfix`, and `untriaged`, along with release labels, such as `v1.0.0`, `v1.1.0` and `v2.0.0`, and `backport`.
49
+
50
+ Use labels to target an issue or a PR for a given release, add `help wanted` to good issues for new community members, and `blocker` for issues that scare you or need immediate attention. Request for more information from a submitter if an issue is not clear. Create new labels as needed by the project.
51
+
52
+ ### Be Responsive
53
+
54
+ Respond to enhancement requests, and forum posts. Allocate time to reviewing and commenting on issues and conversations as they come in.
55
+
56
+ ### Maintain Overall Health of the Repo
57
+
58
+ Keep the `main` branch at production quality at all times. Backport features as needed. Cut release branches and tags to enable future patches.
59
+
60
+ ### Use Semver
61
+
62
+ Use and enforce [semantic versioning](https://semver.org/) and do not let breaking changes be made outside of major releases.
63
+
64
+ ### Release Frequently
65
+
66
+ Make frequent project releases to the community.
67
+
68
+ ### Promote Other Maintainers
69
+
70
+ Assist, add, and remove [MAINTAINERS](MAINTAINERS.md). Exercise good judgement, and propose high quality contributors to become co-maintainers.
71
+
data/NOTICE ADDED
@@ -0,0 +1,2 @@
1
+ logstash-output-opensearch
2
+ Copyright 2021 logstash-output-opensearch Contributors
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ [![Build and Test logstash-output-opensearch plugin](https://github.com/opensearch-project/logstash-output-opensearch/actions/workflows/CI.yml/badge.svg)](https://github.com/opensearch-project/logstash-output-opensearch/actions/workflows/CI.yml)
2
+ ![PRs welcome!](https://img.shields.io/badge/PRs-welcome!-success)
3
+ # Logstash Plugin
4
+
5
+ - [Welcome!](#welcome)
6
+ - [Project Resources](#project-resources)
7
+ - [Code of Conduct](#code-of-conduct)
8
+ - [License](#license)
9
+ - [Copyright](#copyright)
10
+
11
+ ## Welcome!
12
+
13
+ **logstash-output-opensearch** is a community-driven, open source fork logstash-output-elasticsearch licensed under the [Apache v2.0 License](LICENSE.txt). For more information, see [opensearch.org](https://opensearch.org/).
14
+
15
+ ## Project Resources
16
+
17
+ * [Project Website](https://opensearch.org/)
18
+ * [Documentation](https://opensearch.org/)
19
+ * Need help? Try [Forums](https://discuss.opendistrocommunity.dev/)
20
+ * [Project Principles](https://opensearch.org/#principles)
21
+ * [Contributing to OpenSearch](CONTRIBUTING.md)
22
+ * [Maintainer Responsibilities](MAINTAINERS.md)
23
+ * [Release Management](RELEASING.md)
24
+ * [Admin Responsibilities](ADMINS.md)
25
+ * [Security](SECURITY.md)
26
+
27
+ ## Code of Conduct
28
+
29
+ This project has adopted the [Amazon Open Source Code of Conduct](CODE_OF_CONDUCT.md). For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq), or contact [opensource-codeofconduct@amazon.com](mailto:opensource-codeofconduct@amazon.com) with any additional questions or comments.
30
+
31
+ ## License
32
+
33
+ This project is licensed under the [Apache v2.0 License](LICENSE.txt).
34
+
35
+ ## Copyright
36
+
37
+ Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
data/RELEASING.md ADDED
@@ -0,0 +1,36 @@
1
+ - [Overview](#overview)
2
+ - [Branching](#branching)
3
+ - [Release Branching](#release-branching)
4
+ - [Feature Branches](#feature-branches)
5
+ - [Release Labels](#release-labels)
6
+ - [Releasing](#releasing)
7
+
8
+ ## Overview
9
+
10
+ This document explains the release strategy for artifacts in this organization.
11
+
12
+ ## Branching
13
+
14
+ ### Release Branching
15
+
16
+ Given the current major release of 1.0, projects in this organization maintain the following active branches.
17
+
18
+ * **main**: The next _major_ release. This is the branch where all merges take place and code moves fast.
19
+ * **1.x**: The next _minor_ release. Once a change is merged into `main`, decide whether to backport it to `1.x`.
20
+ * **1.0**: The _current_ release. In between minor releases, only hotfixes (e.g. security) are backported to `1.0`.
21
+
22
+ Label PRs with the next major version label (e.g. `2.0.0`) and merge changes into `main`. Label PRs that you believe need to be backported as `1.x` and `1.0`. Backport PRs by checking out the versioned branch, cherry-pick changes and open a PR against each target backport branch.
23
+
24
+ ### Feature Branches
25
+
26
+ Do not creating branches in the upstream repo, use your fork, for the exception of long lasting feature branches that require active collaboration from multiple developers. Name feature branches `feature/<thing>`. Once the work is merged to `main`, please make sure to delete the feature branch.
27
+
28
+ ## Release Labels
29
+
30
+ Repositories create consistent release labels, such as `v1.0.0`, `v1.1.0` and `v2.0.0`, as well as `backport`. Use release labels to target an issue or a PR for a given release. See [MAINTAINERS](MAINTAINERS.md#triage-open-issues) for more information on triaging issues.
31
+
32
+ ## Releasing
33
+
34
+ The release process is standard across repositories in this org and is run by a release manager volunteering from amongst [MAINTAINERS](MAINTAINERS.md).
35
+
36
+ TODO
data/SECURITY.md ADDED
@@ -0,0 +1,3 @@
1
+ ## Reporting a Vulnerability
2
+
3
+ If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. Please do **not** create a public GitHub issue.
@@ -0,0 +1,449 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ #
3
+ # The OpenSearch Contributors require contributions made to
4
+ # this file be licensed under the Apache-2.0 license or a
5
+ # compatible open source license.
6
+ #
7
+ # Modifications Copyright OpenSearch Contributors. See
8
+ # GitHub history for details.
9
+
10
+ # encoding: utf-8
11
+ require "logstash/namespace"
12
+ require "logstash/environment"
13
+ require "logstash/outputs/base"
14
+ require "logstash/json"
15
+ require "concurrent/atomic/atomic_boolean"
16
+ require "stud/interval"
17
+ require "socket" # for Socket.gethostname
18
+ require "thread" # for safe queueing
19
+ require "uri" # for escaping user input
20
+ require "forwardable"
21
+
22
+ # This plugin is the recommended method of storing logs in OpenSearch.
23
+ # If you plan on using the OpenSearch Dashboards web interface, you'll want to use this output.
24
+ #
25
+ # This output only speaks the HTTP protocol. HTTP is the preferred protocol for interacting with OpenSearch.
26
+ # We strongly encourage the use of HTTP over the node protocol for a number of reasons. HTTP is only marginally slower,
27
+ # yet far easier to administer and work with. When using the HTTP protocol one may upgrade OpenSearch versions without having
28
+ # to upgrade Logstash in lock-step.
29
+ #
30
+ # You can learn more about OpenSearch at <https://opensearch.org/>
31
+ #
32
+ # ==== Retry Policy
33
+ # This plugin uses the OpenSearch bulk API to optimize its imports into OpenSearch. These requests may experience
34
+ # either partial or total failures.
35
+ #
36
+ # The following errors are retried infinitely:
37
+ #
38
+ # - Network errors (inability to connect)
39
+ # - 429 (Too many requests) and
40
+ # - 503 (Service unavailable) errors
41
+ #
42
+ # NOTE: 409 exceptions are no longer retried. Please set a higher `retry_on_conflict` value if you experience 409 exceptions.
43
+ # It is more performant for OpenSearch to retry these exceptions than this plugin.
44
+ #
45
+ # ==== Batch Sizes ====
46
+ # This plugin attempts to send batches of events as a single request. However, if
47
+ # a request exceeds 20MB we will break it up until multiple batch requests. If a single document exceeds 20MB it will be sent as a single request.
48
+ #
49
+ # ==== DNS Caching
50
+ #
51
+ # This plugin uses the JVM to lookup DNS entries and is subject to the value of https://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html[networkaddress.cache.ttl],
52
+ # a global setting for the JVM.
53
+ #
54
+ # As an example, to set your DNS TTL to 1 second you would set
55
+ # the `LS_JAVA_OPTS` environment variable to `-Dnetworkaddress.cache.ttl=1`.
56
+ #
57
+ # Keep in mind that a connection with keepalive enabled will
58
+ # not reevaluate its DNS value while the keepalive is in effect.
59
+ #
60
+ # ==== HTTP Compression
61
+ #
62
+ # This plugin supports request and response compression. Response compression is enabled by default,
63
+ # the user doesn't have to set any configs in OpenSearch for it to send back compressed response.
64
+ #
65
+ # For requests compression, users have to enable `http_compression`
66
+ # setting in their Logstash config file.
67
+ #
68
+ class LogStash::Outputs::OpenSearch < LogStash::Outputs::Base
69
+ declare_threadsafe!
70
+
71
+ require "logstash/outputs/opensearch/distribution_checker"
72
+ require "logstash/outputs/opensearch/http_client"
73
+ require "logstash/outputs/opensearch/http_client_builder"
74
+ require "logstash/plugin_mixins/opensearch/api_configs"
75
+ require "logstash/plugin_mixins/opensearch/common"
76
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
77
+
78
+ # Protocol agnostic methods
79
+ include(LogStash::PluginMixins::OpenSearch::Common)
80
+
81
+ # ecs_compatibility option, provided by Logstash core or the support adapter.
82
+ include(LogStash::PluginMixins::ECSCompatibilitySupport)
83
+
84
+ # Generic/API config options that any document indexer output needs
85
+ include(LogStash::PluginMixins::OpenSearch::APIConfigs)
86
+
87
+ config_name "opensearch"
88
+
89
+ # The OpenSearch action to perform. Valid actions are:
90
+ #
91
+ # - index: indexes a document (an event from Logstash).
92
+ # - delete: deletes a document by id (An id is required for this action)
93
+ # - create: indexes a document, fails if a document by that id already exists in the index.
94
+ # - update: updates a document by id. Update has a special case where you can upsert -- update a
95
+ # document if not already present. See the `upsert` option.
96
+ # - A sprintf style string to change the action based on the content of the event. The value `%{[foo]}`
97
+ # would use the foo field for the action
98
+ #
99
+ # For more details on actions, check out the https://docs-beta.opensearch.org/opensearch/rest-api/bulk/[OpenSearch bulk API documentation]
100
+ config :action, :validate => :string, :default => "index"
101
+
102
+ # The index to write events to. This can be dynamic using the `%{foo}` syntax.
103
+ # The default value will partition your indices by day so you can more easily
104
+ # delete old data or only search specific date ranges.
105
+ # Indexes may not contain uppercase characters.
106
+ # For weekly indexes ISO 8601 format is recommended, eg. logstash-%{+xxxx.ww}.
107
+ # LS uses Joda to format the index pattern from event timestamp.
108
+ # Joda formats are defined http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html[here].
109
+ config :index, :validate => :string
110
+
111
+ config :document_type,
112
+ :validate => :string,
113
+ :deprecated => "Document types are removed entirely. You should avoid this feature"
114
+
115
+ # From Logstash 1.3 onwards, a template is applied to OpenSearch during
116
+ # Logstash's startup if one with the name `template_name` does not already exist.
117
+ # By default, the contents of this template is the default template for
118
+ # `logstash-%{+YYYY.MM.dd}` which always matches indices based on the pattern
119
+ # `logstash-*`. Should you require support for other index names, or would like
120
+ # to change the mappings in the template in general, a custom template can be
121
+ # specified by setting `template` to the path of a template file.
122
+ #
123
+ # Setting `manage_template` to false disables this feature. If you require more
124
+ # control over template creation, (e.g. creating indices dynamically based on
125
+ # field names) you should set `manage_template` to false and use the REST
126
+ # API to apply your templates manually.
127
+ config :manage_template, :validate => :boolean, :default => true
128
+
129
+ # This configuration option defines how the template is named inside OpenSearch.
130
+ # Note that if you have used the template management features and subsequently
131
+ # change this, you will need to prune the old template manually, e.g.
132
+ #
133
+ # `curl -XDELETE <http://localhost:9200/_template/OldTemplateName?pretty>`
134
+ #
135
+ # where `OldTemplateName` is whatever the former setting was.
136
+ config :template_name, :validate => :string
137
+
138
+ # You can set the path to your own template here, if you so desire.
139
+ # If not set, the included template will be used.
140
+ config :template, :validate => :path
141
+
142
+ # The template_overwrite option will always overwrite the indicated template
143
+ # in OpenSearch with either the one indicated by template or the included one.
144
+ # This option is set to false by default. If you always want to stay up to date
145
+ # with the template provided by Logstash, this option could be very useful to you.
146
+ # Likewise, if you have your own template file managed by puppet, for example, and
147
+ # you wanted to be able to update it regularly, this option could help there as well.
148
+ #
149
+ # Please note that if you are using your own customized version of the Logstash
150
+ # template (logstash), setting this to true will make Logstash to overwrite
151
+ # the "logstash" template (i.e. removing all customized settings)
152
+ config :template_overwrite, :validate => :boolean, :default => false
153
+
154
+ # The version to use for indexing. Use sprintf syntax like `%{my_version}` to use a field value here.
155
+ config :version, :validate => :string
156
+
157
+ # The version_type to use for indexing.
158
+ config :version_type, :validate => ["internal", 'external', "external_gt", "external_gte", "force"]
159
+
160
+ # A routing override to be applied to all processed events.
161
+ # This can be dynamic using the `%{foo}` syntax.
162
+ config :routing, :validate => :string
163
+
164
+ # For child documents, ID of the associated parent.
165
+ # This can be dynamic using the `%{foo}` syntax.
166
+ config :parent, :validate => :string, :default => nil
167
+
168
+ # For child documents, name of the join field
169
+ config :join_field, :validate => :string, :default => nil
170
+
171
+ # Set upsert content for update mode.s
172
+ # Create a new document with this parameter as json string if `document_id` doesn't exists
173
+ config :upsert, :validate => :string, :default => ""
174
+
175
+ # Enable `doc_as_upsert` for update mode.
176
+ # Create a new document with source if `document_id` doesn't exist in OpenSearch
177
+ config :doc_as_upsert, :validate => :boolean, :default => false
178
+
179
+ # Set script name for scripted update mode
180
+ config :script, :validate => :string, :default => ""
181
+
182
+ # Define the type of script referenced by "script" variable
183
+ # inline : "script" contains inline script
184
+ # indexed : "script" contains the name of script directly indexed in opensearch
185
+ # file : "script" contains the name of script stored in opensearch's config directory
186
+ config :script_type, :validate => ["inline", 'indexed', "file"], :default => ["inline"]
187
+
188
+ # Set the language of the used script. If not set, this defaults to painless
189
+ config :script_lang, :validate => :string, :default => "painless"
190
+
191
+ # Set variable name passed to script (scripted update)
192
+ config :script_var_name, :validate => :string, :default => "event"
193
+
194
+ # if enabled, script is in charge of creating non-existent document (scripted update)
195
+ config :scripted_upsert, :validate => :boolean, :default => false
196
+
197
+ # The number of times OpenSearch should internally retry an update/upserted document
198
+ config :retry_on_conflict, :validate => :number, :default => 1
199
+
200
+ # Set which ingest pipeline you wish to execute for an event. You can also use event dependent configuration
201
+ # here like `pipeline => "%{INGEST_PIPELINE}"`
202
+ config :pipeline, :validate => :string, :default => nil
203
+
204
+ attr_reader :client
205
+ attr_reader :default_index
206
+ attr_reader :default_template_name
207
+
208
+ def initialize(*params)
209
+ super
210
+ setup_ecs_compatibility_related_defaults
211
+ end
212
+
213
+ def register
214
+ @after_successful_connection_done = Concurrent::AtomicBoolean.new(false)
215
+ @stopping = Concurrent::AtomicBoolean.new(false)
216
+
217
+ check_action_validity
218
+
219
+ @logger.info("New OpenSearch output", :class => self.class.name, :hosts => @hosts.map(&:sanitized).map(&:to_s))
220
+
221
+ @client = build_client(DistributionChecker.new(@logger))
222
+
223
+ @after_successful_connection_thread = after_successful_connection do
224
+ begin
225
+ finish_register
226
+ true # thread.value
227
+ rescue => e
228
+ # we do not want to halt the thread with an exception as that has consequences for LS
229
+ e # thread.value
230
+ ensure
231
+ @after_successful_connection_done.make_true
232
+ end
233
+ end
234
+
235
+ # To support BWC, we check if DLQ exists in core (< 5.4). If it doesn't, we use nil to resort to previous behavior.
236
+ @dlq_writer = dlq_enabled? ? execution_context.dlq_writer : nil
237
+
238
+ @event_mapper = -> (e) { event_action_tuple(e) }
239
+ @event_target = -> (e) { e.sprintf(@index) }
240
+
241
+ @bulk_request_metrics = metric.namespace(:bulk_requests)
242
+ @document_level_metrics = metric.namespace(:documents)
243
+ end
244
+
245
+ # @override post-register when OpenSearch connection established
246
+ def finish_register
247
+ discover_cluster_uuid
248
+ install_template
249
+ super
250
+ end
251
+
252
+ # @override to handle proxy => '' as if none was set
253
+ def config_init(params)
254
+ proxy = params['proxy']
255
+ if proxy.is_a?(String)
256
+ # environment variables references aren't yet resolved
257
+ proxy = deep_replace(proxy)
258
+ if proxy.empty?
259
+ params.delete('proxy')
260
+ @proxy = ''
261
+ else
262
+ params['proxy'] = proxy # do not do resolving again
263
+ end
264
+ end
265
+ super(params)
266
+ end
267
+
268
+ # Receive an array of events and immediately attempt to index them (no buffering)
269
+ def multi_receive(events)
270
+ wait_for_successful_connection if @after_successful_connection_done
271
+ retrying_submit map_events(events)
272
+ end
273
+
274
+ def map_events(events)
275
+ events.map(&@event_mapper)
276
+ end
277
+
278
+ def wait_for_successful_connection
279
+ after_successful_connection_done = @after_successful_connection_done
280
+ return unless after_successful_connection_done
281
+ stoppable_sleep 1 until after_successful_connection_done.true?
282
+
283
+ status = @after_successful_connection_thread && @after_successful_connection_thread.value
284
+ if status.is_a?(Exception) # check if thread 'halted' with an error
285
+ # keep logging that something isn't right (from every #multi_receive)
286
+ @logger.error "OpenSearch setup did not complete normally, please review previously logged errors",
287
+ message: status.message, exception: status.class
288
+ else
289
+ @after_successful_connection_done = nil # do not execute __method__ again if all went well
290
+ end
291
+ end
292
+ private :wait_for_successful_connection
293
+
294
+ def close
295
+ @stopping.make_true if @stopping
296
+ stop_after_successful_connection_thread
297
+ @client.close if @client
298
+ end
299
+
300
+ private
301
+
302
+ def stop_after_successful_connection_thread
303
+ @after_successful_connection_thread.join unless @after_successful_connection_thread.nil?
304
+ end
305
+
306
+ # Convert the event into a 3-tuple of action, params and event hash
307
+ def event_action_tuple(event)
308
+ params = common_event_params(event)
309
+ params[:_type] = get_event_type(event) if use_event_type?(nil)
310
+
311
+ if @parent
312
+ if @join_field
313
+ join_value = event.get(@join_field)
314
+ parent_value = event.sprintf(@parent)
315
+ event.set(@join_field, { "name" => join_value, "parent" => parent_value })
316
+ params[routing_field_name] = event.sprintf(@parent)
317
+ else
318
+ params[:parent] = event.sprintf(@parent)
319
+ end
320
+ end
321
+
322
+ action = event.sprintf(@action || 'index')
323
+
324
+ if action == 'update'
325
+ params[:_upsert] = LogStash::Json.load(event.sprintf(@upsert)) if @upsert != ""
326
+ params[:_script] = event.sprintf(@script) if @script != ""
327
+ params[retry_on_conflict_action_name] = @retry_on_conflict
328
+ end
329
+
330
+ params[:version] = event.sprintf(@version) if @version
331
+ params[:version_type] = event.sprintf(@version_type) if @version_type
332
+
333
+ EventActionTuple.new(action, params, event)
334
+ end
335
+
336
+ class EventActionTuple < Array # TODO: acting as an array for compatibility
337
+
338
+ def initialize(action, params, event, event_data = nil)
339
+ super(3)
340
+ self[0] = action
341
+ self[1] = params
342
+ self[2] = event_data || event.to_hash
343
+ @event = event
344
+ end
345
+
346
+ attr_reader :event
347
+
348
+ end
349
+
350
+ # @return Hash (initial) parameters for given event
351
+ # @private shared event params factory between index and data_stream mode
352
+ def common_event_params(event)
353
+ params = {
354
+ :_id => @document_id ? event.sprintf(@document_id) : nil,
355
+ :_index => @event_target.call(event),
356
+ routing_field_name => @routing ? event.sprintf(@routing) : nil
357
+ }
358
+
359
+ if @pipeline
360
+ value = event.sprintf(@pipeline)
361
+ # convention: empty string equates to not using a pipeline
362
+ # this is useful when using a field reference in the pipeline setting, e.g.
363
+ # opensearch {
364
+ # pipeline => "%{[@metadata][pipeline]}"
365
+ # }
366
+ params[:pipeline] = value unless value.empty?
367
+ end
368
+
369
+ params
370
+ end
371
+
372
+ @@plugins = Gem::Specification.find_all{|spec| spec.name =~ /logstash-output-opensearch-/ }
373
+
374
+ @@plugins.each do |plugin|
375
+ name = plugin.name.split('-')[-1]
376
+ require "logstash/outputs/opensearch/#{name}"
377
+ end
378
+
379
+ def retry_on_conflict_action_name
380
+ :retry_on_conflict
381
+ end
382
+
383
+ def routing_field_name
384
+ :routing
385
+ end
386
+
387
+ DEFAULT_EVENT_TYPE_ES = "_doc".freeze
388
+
389
+ def get_event_type(event)
390
+ # Set the 'type' value for the index.
391
+ type = if @document_type
392
+ event.sprintf(@document_type)
393
+ else
394
+ DEFAULT_EVENT_TYPE_ES
395
+ end
396
+
397
+ type.to_s
398
+ end
399
+
400
+ ##
401
+ # WARNING: This method is overridden in a subclass in Logstash Core 7.7-7.8's monitoring,
402
+ # where a `client` argument is both required and ignored. In later versions of
403
+ # Logstash Core it is optional and ignored, but to make it optional here would
404
+ # allow us to accidentally break compatibility with Logstashes where it was required.
405
+ # @param noop_required_client [nil]: required `nil` for legacy reasons.
406
+ # @return [Boolean]
407
+ def use_event_type?(noop_required_client)
408
+ # only if the user defined it
409
+ @document_type
410
+ end
411
+
412
+ def install_template
413
+ TemplateManager.install_template(self)
414
+ rescue => e
415
+ @logger.error("Failed to install template", message: e.message, exception: e.class, backtrace: e.backtrace)
416
+ end
417
+
418
+ def setup_ecs_compatibility_related_defaults
419
+ case ecs_compatibility
420
+ when :disabled
421
+ @default_index = "logstash-%{+yyyy.MM.dd}"
422
+ @default_template_name = 'logstash'
423
+ when :v1
424
+ @default_index = "ecs-logstash-%{+yyyy.MM.dd}"
425
+ @default_template_name = 'ecs-logstash'
426
+ else
427
+ fail("unsupported ECS Compatibility `#{ecs_compatibility}`")
428
+ end
429
+ @index ||= default_index
430
+ @template_name ||= default_template_name
431
+ end
432
+
433
+ # To be overidden by the -java version
434
+ VALID_HTTP_ACTIONS = ["index", "delete", "create", "update"]
435
+ def valid_actions
436
+ VALID_HTTP_ACTIONS
437
+ end
438
+
439
+ def check_action_validity
440
+ return if @action.nil? # not set
441
+ raise LogStash::ConfigurationError, "No action specified!" if @action.empty?
442
+
443
+ # If we're using string interpolation, we're good!
444
+ return if @action =~ /%{.+}/
445
+ return if valid_actions.include?(@action)
446
+
447
+ raise LogStash::ConfigurationError, "Action '#{@action}' is invalid! Pick one of #{valid_actions} or use a sprintf style statement"
448
+ end
449
+ end