logstash-output-opensearch 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![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
|