logstash-integration-elastic_enterprise_search 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -1
- data/DEVELOPER.md +2 -1
- data/README.md +0 -1
- data/lib/logstash/outputs/elastic_app_search.rb +32 -0
- data/lib/logstash/outputs/elastic_workplace_search.rb +106 -0
- data/logstash-integration-elastic_enterprise_search.gemspec +3 -2
- data/spec/integration/outputs/{index_spec.rb → elastic_app_search_spec.rb} +0 -0
- data/spec/integration/outputs/elastic_workplace_search_spec.rb +83 -0
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d1202fb961af64675edfe8d9deb5a5496a6883a4ba4f73de08b8c53229a78d8
|
4
|
+
data.tar.gz: a69156a70dd56f29ad1ba16330b31e81725f03679f5ec7ed2b4bf0e6d3220ad0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19e16ac5f649cb599b67394558a998393adf9d84331af212d7567f614b290832669aab601378ad7ca48472f3ab6bce1167e1edfa53bdcb378ae9435413fa8964
|
7
|
+
data.tar.gz: 5ce52eb632f0897c9af62e53a02db844142b8864908da08dd6937328a635ded2c4cb11e18d0f9a1861a2f8c9aa04acb0c29d93386647e81b612ac03ec9c151b8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
-
## 2.
|
1
|
+
## 2.1.0
|
2
|
+
- Addition of Workplace Search Output plugin [#4](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/4)
|
3
|
+
- [DOC] Updates output-elastic_app_search documentation to add an integration attribute and include the integration plugin header [#5](https://github.com/logstash-plugins/logstash-integration-elastic_enterprise_search/pull/5)
|
4
|
+
|
2
5
|
|
6
|
+
## 2.0.0
|
3
7
|
- Initial release of the Elastic EnterpriseSearch Integration Plugin, which carries the
|
4
8
|
previous AppSearch Output plugin codebase;
|
5
9
|
independent changelogs for previous versions can be found:
|
data/DEVELOPER.md
CHANGED
data/README.md
CHANGED
@@ -97,4 +97,3 @@ Programming is not a required skill. Whatever you've seen about open source and
|
|
97
97
|
It is more important to the community that you are able to contribute.
|
98
98
|
|
99
99
|
For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
|
100
|
-
>>>>>>> 418bfff... Rought output plugin creation
|
@@ -5,12 +5,44 @@ require "elastic-app-search"
|
|
5
5
|
class LogStash::Outputs::ElasticAppSearch < LogStash::Outputs::Base
|
6
6
|
config_name "elastic_app_search"
|
7
7
|
|
8
|
+
# The name of the search engine you created in App Search, an information
|
9
|
+
# repository that includes the indexed document records.
|
10
|
+
# The `engine` field supports
|
11
|
+
# {logstash-ref}/event-dependent-configuration.html#sprintf[sprintf format] to
|
12
|
+
# allow the engine name to be derived from a field value from each event, for
|
13
|
+
# example `engine-%{engine_name}`.
|
14
|
+
#
|
15
|
+
# Invalid engine names cause ingestion to stop until the field value can be resolved into a valid engine name.
|
16
|
+
# This situation can happen if the interpolated field value resolves to a value without a matching engine,
|
17
|
+
# or, if the field is missing from the event and cannot be resolved at all.
|
8
18
|
config :engine, :validate => :string, :required => true
|
19
|
+
|
20
|
+
# The hostname of the App Search API that is associated with your App Search account.
|
21
|
+
# Set this when using the https://www.elastic.co/cloud/app-search-service
|
9
22
|
config :host, :validate => :string
|
23
|
+
|
24
|
+
# The value of the API endpoint in the form of a URL. Note: The value of the of the `path` setting will be will be appended to this URL.
|
25
|
+
# Set this when using the https://www.elastic.co/downloads/app-search
|
10
26
|
config :url, :validate => :string
|
27
|
+
|
28
|
+
# The private API Key with write permissions. Visit the https://app.swiftype.com/as/credentials
|
29
|
+
# in the App Search dashboard to find the key associated with your account.
|
11
30
|
config :api_key, :validate => :password, :required => true
|
31
|
+
|
32
|
+
# Where to move the value from the `@timestamp` field.
|
33
|
+
#
|
34
|
+
# All Logstash events contain a `@timestamp` field.
|
35
|
+
# App Search doesn't support fields starting with `@timestamp`, and
|
36
|
+
# by default, the `@timestamp` field will be deleted.
|
37
|
+
#
|
38
|
+
# To keep the timestamp field, set this value to the name of the field where you want `@timestamp` copied.
|
12
39
|
config :timestamp_destination, :validate => :string
|
40
|
+
|
41
|
+
# The id for app search documents. This can be an interpolated value
|
42
|
+
# like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
|
13
43
|
config :document_id, :validate => :string
|
44
|
+
|
45
|
+
# The path that is appended to the `url` parameter when connecting to a https://www.elastic.co/downloads/app-search
|
14
46
|
config :path, :validate => :string, :default => "/api/as/v1/"
|
15
47
|
|
16
48
|
ENGINE_WITH_SPRINTF_REGEX = /^.*%\{.+\}.*$/
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/outputs/base"
|
3
|
+
require "elastic-workplace-search"
|
4
|
+
|
5
|
+
class LogStash::Outputs::ElasticWorkplaceSearch < LogStash::Outputs::Base
|
6
|
+
config_name "elastic_workplace_search"
|
7
|
+
|
8
|
+
# The value of the API endpoint in the form of a URL.
|
9
|
+
config :url, :validate => :string, :required => true
|
10
|
+
|
11
|
+
# The ID of the source you created in Workplace Search.
|
12
|
+
# The `source` field supports
|
13
|
+
# {logstash-ref}/event-dependent-configuration.html#sprintf[sprintf format] to
|
14
|
+
# allow the source ID to be derived from a field value from each event, for
|
15
|
+
# example `%{source_id}`.
|
16
|
+
#
|
17
|
+
# Invalid source IDs cause ingestion to stop until the field value can be resolved into a valid source ID.
|
18
|
+
# This situation can happen if the interpolated field value resolves to a value without a matching source,
|
19
|
+
# or, if the field is missing from the event and cannot be resolved at all.
|
20
|
+
config :source, :validate => :string, :required => true
|
21
|
+
|
22
|
+
# The source access token. Visit the source overview page in the Workplace Search dashboard
|
23
|
+
# to find the token associated with your source.
|
24
|
+
config :access_token, :validate => :password, :required => true
|
25
|
+
|
26
|
+
# Where to move the value from the `@timestamp` field.
|
27
|
+
#
|
28
|
+
# All Logstash events contain a `@timestamp` field.
|
29
|
+
# Workplace Search doesn't support fields starting with `@timestamp`, and
|
30
|
+
# by default, the `@timestamp` field will be deleted.
|
31
|
+
#
|
32
|
+
# To keep the timestamp field, set this value to the name of the field where you want `@timestamp` copied.
|
33
|
+
config :timestamp_destination, :validate => :string
|
34
|
+
|
35
|
+
# The id for workplace search documents. This can be an interpolated value
|
36
|
+
# like `myapp-%{sequence_id}`. Reusing ids will cause documents to be rewritten.
|
37
|
+
config :document_id, :validate => :string
|
38
|
+
|
39
|
+
public
|
40
|
+
def register
|
41
|
+
Elastic::WorkplaceSearch.endpoint = "#{@url.chomp('/')}/api/ws/v1/"
|
42
|
+
@client = Elastic::WorkplaceSearch::Client.new(:access_token => @access_token.value)
|
43
|
+
check_connection!
|
44
|
+
rescue Elastic::WorkplaceSearch::InvalidCredentials
|
45
|
+
raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. Error: 401. Please check your credentials")
|
46
|
+
rescue Elastic::WorkplaceSearch::NonExistentRecord
|
47
|
+
raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. Error: 404. Please check if url '#{@url}' is correct and you've created a source with ID '#{@source}'")
|
48
|
+
rescue => e
|
49
|
+
raise ::LogStash::ConfigurationError.new("Failed to connect to Workplace Search. #{e.message}")
|
50
|
+
end
|
51
|
+
|
52
|
+
public
|
53
|
+
def multi_receive(events)
|
54
|
+
# because Workplace Search has a limit of 100 documents per bulk
|
55
|
+
events.each_slice(100) do |events|
|
56
|
+
batch = format_batch(events)
|
57
|
+
if @logger.trace?
|
58
|
+
@logger.trace("Sending bulk to Workplace Search", :size => batch.size, :data => batch.inspect)
|
59
|
+
end
|
60
|
+
index(batch)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def format_batch(events)
|
66
|
+
events.map do |event|
|
67
|
+
doc = event.to_hash
|
68
|
+
# we need to remove default fields that start with "@"
|
69
|
+
# since Elastic Workplace Search doesn't accept them
|
70
|
+
if @timestamp_destination
|
71
|
+
doc[@timestamp_destination] = doc.delete("@timestamp")
|
72
|
+
else # delete it
|
73
|
+
doc.delete("@timestamp")
|
74
|
+
end
|
75
|
+
if @document_id
|
76
|
+
doc["id"] = event.sprintf(@document_id)
|
77
|
+
end
|
78
|
+
doc.delete("@version")
|
79
|
+
doc
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def index(documents)
|
84
|
+
response = @client.index_documents(@source, documents)
|
85
|
+
report(documents, response)
|
86
|
+
rescue => e
|
87
|
+
@logger.error("Failed to execute index operation. Retrying..", :exception => e.class, :reason => e.message)
|
88
|
+
sleep(1)
|
89
|
+
retry
|
90
|
+
end
|
91
|
+
|
92
|
+
def report(documents, response)
|
93
|
+
documents.each_with_index do |document, i|
|
94
|
+
errors = response["results"][i]["errors"]
|
95
|
+
if errors.empty?
|
96
|
+
@logger.trace? && @logger.trace("Document was indexed with no errors", :document => document)
|
97
|
+
else
|
98
|
+
@logger.warn("Document failed to index. Dropping..", :document => document, :errors => errors.to_a)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def check_connection!
|
104
|
+
@client.list_all_permissions(@source)
|
105
|
+
end
|
106
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-integration-elastic_enterprise_search'
|
3
|
-
s.version = '2.
|
3
|
+
s.version = '2.1.0'
|
4
4
|
s.licenses = ['Apache-2.0']
|
5
5
|
s.summary = "Integration with Elastic Enterprise Search - output plugins"
|
6
6
|
s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline "+
|
@@ -20,12 +20,13 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.metadata = {
|
21
21
|
"logstash_plugin" => "true",
|
22
22
|
"logstash_group" => "integration",
|
23
|
-
"integration_plugins" => "logstash-output-elastic_app_search"
|
23
|
+
"integration_plugins" => "logstash-output-elastic_app_search, logstash-output-elastic_workplace_search"
|
24
24
|
}
|
25
25
|
|
26
26
|
# Gem dependencies
|
27
27
|
s.add_runtime_dependency "logstash-core-plugin-api", "~> 2.0"
|
28
28
|
s.add_runtime_dependency "logstash-codec-plain"
|
29
29
|
s.add_runtime_dependency "elastic-app-search", '~>7.8.0'
|
30
|
+
s.add_runtime_dependency "elastic-workplace-search", '~>0.4.1'
|
30
31
|
s.add_development_dependency "logstash-devutils"
|
31
32
|
end
|
File without changes
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/outputs/elastic_workplace_search"
|
4
|
+
require "logstash/codecs/plain"
|
5
|
+
require "logstash/event"
|
6
|
+
require "json"
|
7
|
+
require "base64"
|
8
|
+
|
9
|
+
describe "indexing against running Workplace Search", :integration => true do
|
10
|
+
|
11
|
+
let(:url) { ENV['APPSEARCH_URL'] }
|
12
|
+
let(:auth) { Base64.strict_encode64("#{ENV['APPSEARCH_USERNAME']}:#{ENV['AS_PASSWORD']}") }
|
13
|
+
let(:source) do
|
14
|
+
response = Faraday.post(
|
15
|
+
"#{url}/ws/org/sources/form_create",
|
16
|
+
JSON.dump("service_type" => "custom", "name" => "whatever"),
|
17
|
+
"Content-Type" => "application/json",
|
18
|
+
"Accept" => "application/json",
|
19
|
+
"Authorization" => "Basic #{auth}"
|
20
|
+
)
|
21
|
+
JSON.load(response.body)
|
22
|
+
end
|
23
|
+
let(:source_id) { source.fetch("id") }
|
24
|
+
|
25
|
+
let(:config) do
|
26
|
+
{
|
27
|
+
"url" => url,
|
28
|
+
"source" => source_id,
|
29
|
+
"access_token" => source.fetch("accessToken")
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
subject(:workplace_search_output) { LogStash::Outputs::ElasticWorkplaceSearch.new(config) }
|
34
|
+
|
35
|
+
before(:each) { workplace_search_output.register }
|
36
|
+
|
37
|
+
describe "single event" do
|
38
|
+
let(:event) { LogStash::Event.new("message" => "an event to index") }
|
39
|
+
|
40
|
+
it "should be indexed" do
|
41
|
+
workplace_search_output.multi_receive([event])
|
42
|
+
|
43
|
+
results = Stud.try(20.times, RSpec::Expectations::ExpectationNotMetError) do
|
44
|
+
attempt_response = execute_search_call
|
45
|
+
expect(attempt_response.status).to eq(200)
|
46
|
+
parsed_resp = JSON.parse(attempt_response.body)
|
47
|
+
expect(parsed_resp.dig("meta", "page", "total_pages")).to eq(1)
|
48
|
+
parsed_resp["results"]
|
49
|
+
end
|
50
|
+
expect(results.first.fetch("message")).to eq "an event to index"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "multiple events" do
|
55
|
+
let(:events) { generate_events(200) } #2 times the slice size used to batch
|
56
|
+
|
57
|
+
it "all should be indexed" do
|
58
|
+
workplace_search_output.multi_receive(events)
|
59
|
+
results = Stud.try(20.times, RSpec::Expectations::ExpectationNotMetError) do
|
60
|
+
attempt_response = execute_search_call
|
61
|
+
expect(attempt_response.status).to eq(200)
|
62
|
+
parsed_resp = JSON.parse(attempt_response.body)
|
63
|
+
expect(parsed_resp.dig("meta", "page", "total_results")).to eq(200)
|
64
|
+
parsed_resp["results"]
|
65
|
+
end
|
66
|
+
expect(results.first.fetch("message")).to start_with("an event to index")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def execute_search_call
|
72
|
+
Faraday.post(
|
73
|
+
"#{url}/ws/org/sources/#{source_id}/documents",
|
74
|
+
nil,
|
75
|
+
"Accept" => "application/json",
|
76
|
+
"Authorization" => "Basic #{auth}"
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_events(num_events)
|
81
|
+
(1..num_events).map { |i| LogStash::Event.new("message" => "an event to index #{i}")}
|
82
|
+
end
|
83
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-integration-elastic_enterprise_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 7.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.4.1
|
61
|
+
name: elastic-workplace-search
|
62
|
+
prerelease: false
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.4.1
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
57
71
|
requirements:
|
@@ -82,8 +96,10 @@ files:
|
|
82
96
|
- NOTICE.TXT
|
83
97
|
- README.md
|
84
98
|
- lib/logstash/outputs/elastic_app_search.rb
|
99
|
+
- lib/logstash/outputs/elastic_workplace_search.rb
|
85
100
|
- logstash-integration-elastic_enterprise_search.gemspec
|
86
|
-
- spec/integration/outputs/
|
101
|
+
- spec/integration/outputs/elastic_app_search_spec.rb
|
102
|
+
- spec/integration/outputs/elastic_workplace_search_spec.rb
|
87
103
|
- spec/unit/outputs/appsearch_spec.rb
|
88
104
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
89
105
|
licenses:
|
@@ -91,7 +107,7 @@ licenses:
|
|
91
107
|
metadata:
|
92
108
|
logstash_plugin: 'true'
|
93
109
|
logstash_group: integration
|
94
|
-
integration_plugins: logstash-output-elastic_app_search
|
110
|
+
integration_plugins: logstash-output-elastic_app_search, logstash-output-elastic_workplace_search
|
95
111
|
post_install_message:
|
96
112
|
rdoc_options: []
|
97
113
|
require_paths:
|
@@ -114,5 +130,6 @@ signing_key:
|
|
114
130
|
specification_version: 4
|
115
131
|
summary: Integration with Elastic Enterprise Search - output plugins
|
116
132
|
test_files:
|
117
|
-
- spec/integration/outputs/
|
133
|
+
- spec/integration/outputs/elastic_app_search_spec.rb
|
134
|
+
- spec/integration/outputs/elastic_workplace_search_spec.rb
|
118
135
|
- spec/unit/outputs/appsearch_spec.rb
|