fluent-plugin-test 0.0.17
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
- data/LICENSE.txt +201 -0
- data/README.md +1622 -0
- data/lib/fluent/log-ext.rb +64 -0
- data/lib/fluent/plugin/filter_opensearch_genid.rb +103 -0
- data/lib/fluent/plugin/in_opensearch.rb +441 -0
- data/lib/fluent/plugin/oj_serializer.rb +48 -0
- data/lib/fluent/plugin/opensearch_constants.rb +39 -0
- data/lib/fluent/plugin/opensearch_error.rb +31 -0
- data/lib/fluent/plugin/opensearch_error_handler.rb +182 -0
- data/lib/fluent/plugin/opensearch_fallback_selector.rb +36 -0
- data/lib/fluent/plugin/opensearch_index_template.rb +155 -0
- data/lib/fluent/plugin/opensearch_simple_sniffer.rb +36 -0
- data/lib/fluent/plugin/opensearch_tls.rb +96 -0
- data/lib/fluent/plugin/out_opensearch.rb +1162 -0
- data/lib/fluent/plugin/out_opensearch_data_stream.rb +231 -0
- metadata +241 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
|
2
|
+
require_relative 'out_opensearch'
|
3
|
+
|
4
|
+
module Fluent::Plugin
|
5
|
+
class OpenSearchOutputDataStream < OpenSearchOutput
|
6
|
+
|
7
|
+
Fluent::Plugin.register_output('opensearch_data_stream', self)
|
8
|
+
|
9
|
+
helpers :event_emitter
|
10
|
+
|
11
|
+
config_param :data_stream_name, :string
|
12
|
+
config_param :data_stream_template_name, :string, :default => nil
|
13
|
+
# OpenSearch 1.0 or later always support new style of index template.
|
14
|
+
config_set_default :use_legacy_template, false
|
15
|
+
|
16
|
+
INVALID_START_CHRACTERS = ["-", "_", "+", "."]
|
17
|
+
INVALID_CHARACTERS = ["\\", "/", "*", "?", "\"", "<", ">", "|", " ", ",", "#", ":"]
|
18
|
+
|
19
|
+
def configure(conf)
|
20
|
+
super
|
21
|
+
|
22
|
+
@data_stream_template_name = "#{@data_stream_name}_template" if @data_stream_template_name.nil?
|
23
|
+
|
24
|
+
# ref. https://opensearch.org/docs/latest/opensearch/data-streams/
|
25
|
+
unless placeholder?(:data_stream_name_placeholder, @data_stream_name)
|
26
|
+
validate_data_stream_parameters
|
27
|
+
else
|
28
|
+
@use_placeholder = true
|
29
|
+
@data_stream_names = []
|
30
|
+
end
|
31
|
+
|
32
|
+
unless @use_placeholder
|
33
|
+
begin
|
34
|
+
@data_stream_names = [@data_stream_name]
|
35
|
+
retry_operate(@max_retry_putting_template,
|
36
|
+
@fail_on_putting_template_retry_exceed,
|
37
|
+
@catch_transport_exception_on_retry) do
|
38
|
+
create_index_template(@data_stream_name, @data_stream_template_name)
|
39
|
+
end
|
40
|
+
rescue => e
|
41
|
+
raise Fluent::ConfigError, "Failed to create data stream: <#{@data_stream_name}> #{e.message}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_data_stream_parameters
|
47
|
+
{"data_stream_name" => @data_stream_name,
|
48
|
+
"data_stream_template_name" => @data_stream_template_name}.each do |parameter, value|
|
49
|
+
unless valid_data_stream_parameters?(value)
|
50
|
+
unless start_with_valid_characters?(value)
|
51
|
+
if not_dots?(value)
|
52
|
+
raise Fluent::ConfigError, "'#{parameter}' must not start with #{INVALID_START_CHRACTERS.join(",")}: <#{value}>"
|
53
|
+
else
|
54
|
+
raise Fluent::ConfigError, "'#{parameter}' must not be . or ..: <#{value}>"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
unless valid_characters?(value)
|
58
|
+
raise Fluent::ConfigError, "'#{parameter}' must not contain invalid characters #{INVALID_CHARACTERS.join(",")}: <#{value}>"
|
59
|
+
end
|
60
|
+
unless lowercase_only?(value)
|
61
|
+
raise Fluent::ConfigError, "'#{parameter}' must be lowercase only: <#{value}>"
|
62
|
+
end
|
63
|
+
if value.bytes.size > 255
|
64
|
+
raise Fluent::ConfigError, "'#{parameter}' must not be longer than 255 bytes: <#{value}>"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_index_template(datastream_name, template_name, host = nil)
|
71
|
+
# Create index template from file
|
72
|
+
if !dry_run?
|
73
|
+
if @template_file
|
74
|
+
return if data_stream_exist?(datastream_name, host) or template_exists?(template_name, host)
|
75
|
+
template_installation_actual(template_name, @customize_template, @application_name, datastream_name, host)
|
76
|
+
else # Create default index template
|
77
|
+
return if data_stream_exist?(datastream_name, host) or template_exists?(template_name, host)
|
78
|
+
body = {
|
79
|
+
"index_patterns" => ["#{datastream_name}*"],
|
80
|
+
"data_stream" => {},
|
81
|
+
}
|
82
|
+
|
83
|
+
params = {
|
84
|
+
name: template_name,
|
85
|
+
body: body
|
86
|
+
}
|
87
|
+
retry_operate(@max_retry_putting_template,
|
88
|
+
@fail_on_putting_template_retry_exceed,
|
89
|
+
@catch_transport_exception_on_retry) do
|
90
|
+
client(host).indices.put_index_template(params)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def data_stream_exist?(datastream_name, host = nil)
|
97
|
+
params = {
|
98
|
+
name: datastream_name
|
99
|
+
}
|
100
|
+
begin
|
101
|
+
# TODO: Use X-Pack equivalent performing DataStream operation method on the following line
|
102
|
+
response = client(host).perform_request('GET', "/_data_stream/#{datastream_name}", {}, params)
|
103
|
+
return (not response.is_a?(OpenSearch::Transport::Transport::Errors::NotFound))
|
104
|
+
rescue OpenSearch::Transport::Transport::Errors::NotFound => e
|
105
|
+
log.info "Specified data stream does not exist. Will be created: <#{e}>"
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def template_exists?(name, host = nil)
|
111
|
+
if @use_legacy_template
|
112
|
+
client(host).indices.get_template(:name => name)
|
113
|
+
else
|
114
|
+
client(host).indices.get_index_template(:name => name)
|
115
|
+
end
|
116
|
+
return true
|
117
|
+
rescue OpenSearch::Transport::Transport::Errors::NotFound
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
|
121
|
+
def valid_data_stream_parameters?(data_stream_parameter)
|
122
|
+
lowercase_only?(data_stream_parameter) and
|
123
|
+
valid_characters?(data_stream_parameter) and
|
124
|
+
start_with_valid_characters?(data_stream_parameter) and
|
125
|
+
not_dots?(data_stream_parameter) and
|
126
|
+
data_stream_parameter.bytes.size <= 255
|
127
|
+
end
|
128
|
+
|
129
|
+
def lowercase_only?(data_stream_parameter)
|
130
|
+
data_stream_parameter.downcase == data_stream_parameter
|
131
|
+
end
|
132
|
+
|
133
|
+
def valid_characters?(data_stream_parameter)
|
134
|
+
not (INVALID_CHARACTERS.each.any? do |v| data_stream_parameter.include?(v) end)
|
135
|
+
end
|
136
|
+
|
137
|
+
def start_with_valid_characters?(data_stream_parameter)
|
138
|
+
not (INVALID_START_CHRACTERS.each.any? do |v| data_stream_parameter.start_with?(v) end)
|
139
|
+
end
|
140
|
+
|
141
|
+
def not_dots?(data_stream_parameter)
|
142
|
+
not (data_stream_parameter == "." or data_stream_parameter == "..")
|
143
|
+
end
|
144
|
+
|
145
|
+
def client_library_version
|
146
|
+
OpenSearch::VERSION
|
147
|
+
end
|
148
|
+
|
149
|
+
def multi_workers_ready?
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
def write(chunk)
|
154
|
+
data_stream_name = @data_stream_name
|
155
|
+
data_stream_template_name = @data_stream_template_name
|
156
|
+
host = nil
|
157
|
+
if @use_placeholder
|
158
|
+
host = if @hosts
|
159
|
+
extract_placeholders(@hosts, chunk)
|
160
|
+
else
|
161
|
+
extract_placeholders(@host, chunk)
|
162
|
+
end
|
163
|
+
data_stream_name = extract_placeholders(@data_stream_name, chunk).downcase
|
164
|
+
data_stream_template_name = extract_placeholders(@data_stream_template_name, chunk).downcase
|
165
|
+
begin
|
166
|
+
create_index_template(data_stream_name, data_stream_template_name, host)
|
167
|
+
rescue => e
|
168
|
+
raise Fluent::ConfigError, "Failed to create data stream: <#{data_stream_name}> #{e.message}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
bulk_message = ""
|
173
|
+
headers = {
|
174
|
+
CREATE_OP => {}
|
175
|
+
}
|
176
|
+
tag = chunk.metadata.tag
|
177
|
+
chunk.msgpack_each do |time, record|
|
178
|
+
next unless record.is_a? Hash
|
179
|
+
begin
|
180
|
+
if record.has_key?(TIMESTAMP_FIELD)
|
181
|
+
rts = record[TIMESTAMP_FIELD]
|
182
|
+
dt = parse_time(rts, time, tag)
|
183
|
+
elsif record.has_key?(@time_key)
|
184
|
+
rts = record[@time_key]
|
185
|
+
dt = parse_time(rts, time, tag)
|
186
|
+
else
|
187
|
+
dt = Time.at(time).to_datetime
|
188
|
+
end
|
189
|
+
record.merge!({"@timestamp" => dt.iso8601(@time_precision)})
|
190
|
+
if @include_tag_key
|
191
|
+
record[@tag_key] = tag
|
192
|
+
end
|
193
|
+
if @remove_keys
|
194
|
+
@remove_keys.each { |key| record.delete(key) }
|
195
|
+
end
|
196
|
+
bulk_message = append_record_to_messages(CREATE_OP, {}, headers, record, bulk_message)
|
197
|
+
rescue => e
|
198
|
+
emit_error_label_event do
|
199
|
+
router.emit_error_event(tag, time, record, e)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
return if bulk_message.to_s.empty?
|
205
|
+
|
206
|
+
params = {
|
207
|
+
index: data_stream_name,
|
208
|
+
body: bulk_message
|
209
|
+
}
|
210
|
+
begin
|
211
|
+
response = client(host).bulk(params)
|
212
|
+
if response['errors']
|
213
|
+
log.error "Could not bulk insert to Data Stream: #{data_stream_name} #{response}"
|
214
|
+
end
|
215
|
+
rescue => e
|
216
|
+
raise RecoverableRequestFailure, "could not push logs to OpenSearch cluster (#{data_stream_name}): #{e.message}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def append_record_to_messages(op, meta, header, record, msgs)
|
221
|
+
header[CREATE_OP] = meta
|
222
|
+
msgs << @dump_proc.call(header) << BODY_DELIMITER
|
223
|
+
msgs << @dump_proc.call(record) << BODY_DELIMITER
|
224
|
+
msgs
|
225
|
+
end
|
226
|
+
|
227
|
+
def retry_stream_retryable?
|
228
|
+
@buffer.storable?
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
metadata
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-test
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.17
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- imcotop
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-04-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fluentd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.14'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: opensearch-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: aws-sdk-core
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: excon
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faraday-excon
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faraday_middleware-aws-sigv4
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.0.1
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webrick
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.9'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.9'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: webmock
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.18.1
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 3.18.1
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: test-unit
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 3.3.0
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 3.3.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: minitest
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '5.8'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '5.8'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: flexmock
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '2.0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '2.0'
|
195
|
+
description: Example plugin for Fluent event collector
|
196
|
+
email:
|
197
|
+
- imcotop@icloud.com
|
198
|
+
executables: []
|
199
|
+
extensions: []
|
200
|
+
extra_rdoc_files: []
|
201
|
+
files:
|
202
|
+
- LICENSE.txt
|
203
|
+
- README.md
|
204
|
+
- lib/fluent/log-ext.rb
|
205
|
+
- lib/fluent/plugin/filter_opensearch_genid.rb
|
206
|
+
- lib/fluent/plugin/in_opensearch.rb
|
207
|
+
- lib/fluent/plugin/oj_serializer.rb
|
208
|
+
- lib/fluent/plugin/opensearch_constants.rb
|
209
|
+
- lib/fluent/plugin/opensearch_error.rb
|
210
|
+
- lib/fluent/plugin/opensearch_error_handler.rb
|
211
|
+
- lib/fluent/plugin/opensearch_fallback_selector.rb
|
212
|
+
- lib/fluent/plugin/opensearch_index_template.rb
|
213
|
+
- lib/fluent/plugin/opensearch_simple_sniffer.rb
|
214
|
+
- lib/fluent/plugin/opensearch_tls.rb
|
215
|
+
- lib/fluent/plugin/out_opensearch.rb
|
216
|
+
- lib/fluent/plugin/out_opensearch_data_stream.rb
|
217
|
+
homepage: https://github.com/fluent/fluent-plugin-opensearch
|
218
|
+
licenses:
|
219
|
+
- Apache-2.0
|
220
|
+
metadata:
|
221
|
+
changelog_uri: https://github.com/fluent/fluent-plugin-opensearch/blob/master/History.md
|
222
|
+
post_install_message:
|
223
|
+
rdoc_options: []
|
224
|
+
require_paths:
|
225
|
+
- lib
|
226
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: '2.3'
|
231
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - ">="
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: '0'
|
236
|
+
requirements: []
|
237
|
+
rubygems_version: 3.5.7
|
238
|
+
signing_key:
|
239
|
+
specification_version: 4
|
240
|
+
summary: Example plugin for Fluent event collector
|
241
|
+
test_files: []
|