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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ADMINS.md +29 -0
- data/CODE_OF_CONDUCT.md +25 -0
- data/CONTRIBUTING.md +99 -0
- data/DEVELOPER_GUIDE.md +208 -0
- data/Gemfile +20 -0
- data/LICENSE +202 -0
- data/MAINTAINERS.md +71 -0
- data/NOTICE +2 -0
- data/README.md +37 -0
- data/RELEASING.md +36 -0
- data/SECURITY.md +3 -0
- data/lib/logstash/outputs/opensearch.rb +449 -0
- data/lib/logstash/outputs/opensearch/distribution_checker.rb +44 -0
- data/lib/logstash/outputs/opensearch/http_client.rb +465 -0
- data/lib/logstash/outputs/opensearch/http_client/manticore_adapter.rb +140 -0
- data/lib/logstash/outputs/opensearch/http_client/pool.rb +467 -0
- data/lib/logstash/outputs/opensearch/http_client_builder.rb +182 -0
- data/lib/logstash/outputs/opensearch/template_manager.rb +60 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/1x.json +44 -0
- data/lib/logstash/outputs/opensearch/templates/ecs-disabled/7x.json +44 -0
- data/lib/logstash/plugin_mixins/opensearch/api_configs.rb +168 -0
- data/lib/logstash/plugin_mixins/opensearch/common.rb +294 -0
- data/lib/logstash/plugin_mixins/opensearch/noop_distribution_checker.rb +18 -0
- data/logstash-output-opensearch.gemspec +40 -0
- data/spec/fixtures/_nodes/nodes.json +74 -0
- data/spec/fixtures/htpasswd +2 -0
- data/spec/fixtures/nginx_reverse_proxy.conf +22 -0
- data/spec/fixtures/scripts/painless/scripted_update.painless +2 -0
- data/spec/fixtures/scripts/painless/scripted_update_nested.painless +1 -0
- data/spec/fixtures/scripts/painless/scripted_upsert.painless +1 -0
- data/spec/integration/outputs/compressed_indexing_spec.rb +76 -0
- data/spec/integration/outputs/create_spec.rb +76 -0
- data/spec/integration/outputs/delete_spec.rb +72 -0
- data/spec/integration/outputs/index_spec.rb +164 -0
- data/spec/integration/outputs/index_version_spec.rb +110 -0
- data/spec/integration/outputs/ingest_pipeline_spec.rb +82 -0
- data/spec/integration/outputs/metrics_spec.rb +75 -0
- data/spec/integration/outputs/no_opensearch_on_startup_spec.rb +67 -0
- data/spec/integration/outputs/painless_update_spec.rb +147 -0
- data/spec/integration/outputs/parent_spec.rb +103 -0
- data/spec/integration/outputs/retry_spec.rb +182 -0
- data/spec/integration/outputs/routing_spec.rb +70 -0
- data/spec/integration/outputs/sniffer_spec.rb +70 -0
- data/spec/integration/outputs/templates_spec.rb +105 -0
- data/spec/integration/outputs/update_spec.rb +123 -0
- data/spec/opensearch_spec_helper.rb +141 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/unit/http_client_builder_spec.rb +194 -0
- data/spec/unit/outputs/error_whitelist_spec.rb +62 -0
- data/spec/unit/outputs/opensearch/http_client/manticore_adapter_spec.rb +159 -0
- data/spec/unit/outputs/opensearch/http_client/pool_spec.rb +306 -0
- data/spec/unit/outputs/opensearch/http_client_spec.rb +292 -0
- data/spec/unit/outputs/opensearch/template_manager_spec.rb +36 -0
- data/spec/unit/outputs/opensearch_proxy_spec.rb +112 -0
- data/spec/unit/outputs/opensearch_spec.rb +800 -0
- data/spec/unit/outputs/opensearch_ssl_spec.rb +179 -0
- metadata +289 -0
- 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
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
[](https://github.com/opensearch-project/logstash-output-opensearch/actions/workflows/CI.yml)
|
2
|
+

|
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
|