fluent-plugin-elasticsearch 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +9 -1
- data/PULL_REQUEST_TEMPLATE.md +10 -0
- data/README.md +73 -2
- data/fluent-plugin-elasticsearch.gemspec +1 -1
- data/lib/fluent/plugin/out_elasticsearch.rb +49 -7
- data/lib/fluent/plugin/out_elasticsearch_dynamic.rb +16 -7
- data/test/plugin/test_out_elasticsearch.rb +161 -2
- data/test/plugin/test_out_elasticsearch_dynamic.rb +80 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90e3be14c80ad364758d6868ac2eeb3ff362d03c
|
4
|
+
data.tar.gz: 449226f062ac9c526d420e459fb25b731583d482
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0da741644cf316f00cb3aecf005933d465c076c4df8af080ec1a4d69bbd8d881de1298a5b734e1de2bf2e6cd36062579ae1e73a0e8684ec523dca3e7de89d84b
|
7
|
+
data.tar.gz: 1acd9c7b4e96059143dac1a4fc80eb8f170f74f934ee53304e112edaa01dadeccf4eb5fb44244ec4e16a55ef973a3534b60f61ea998249e892fecc675524886e
|
data/History.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
## Changelog
|
1
|
+
## Changelog [[tags]](https://github.com/uken/fluent-plugin-elasticsearch/tags)
|
2
2
|
|
3
3
|
### Future
|
4
4
|
|
5
|
+
### 1.5.0
|
6
|
+
- add `routing_key` (#158)
|
7
|
+
- add `time_key_exclude_timestamp` to exclude `@timestamp` (#161)
|
8
|
+
- convert index names to lowercase (#163)
|
9
|
+
- add `remove_keys` (#164)
|
10
|
+
- add `flatten_hashes` (#168)
|
11
|
+
- add `target_type_key` (#169)
|
12
|
+
|
5
13
|
### 1.4.0
|
6
14
|
- add `target_index_key` to specify target index (#153)
|
7
15
|
- add `time_key_format` for faster time format parsing (#154)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Pull Request Description HERE
|
2
|
+
|
3
|
+
(check all that apply)
|
4
|
+
- [ ] tests added
|
5
|
+
- [ ] tests passing
|
6
|
+
- [ ] README updated (if needed)
|
7
|
+
- [ ] README Table of Contents updated (if needed)
|
8
|
+
- [ ] History.md and `version` in gemspec are untouched
|
9
|
+
- [ ] backward compatible
|
10
|
+
- [ ] feature works in `elasticsearch_dynamic` (not required but recommended)
|
data/README.md
CHANGED
@@ -22,18 +22,24 @@ Note: For Amazon Elasticsearch Service please consider using [fluent-plugin-aws-
|
|
22
22
|
+ [logstash_dateformat](#logstash_dateformat)
|
23
23
|
+ [time_key_format](#time_key_format)
|
24
24
|
+ [time_key](#time_key)
|
25
|
+
+ [time_key_exclude_timestamp](#time_key_exclude_timestamp)
|
25
26
|
+ [utc_index](#utc_index)
|
26
27
|
+ [target_index_key](#target_index_key)
|
28
|
+
+ [target_type_key](#target_type_key)
|
27
29
|
+ [request_timeout](#request_timeout)
|
28
30
|
+ [reload_connections](#reload_connections)
|
29
31
|
+ [reload_on_failure](#reload_on_failure)
|
30
32
|
+ [resurrect_after](#resurrect_after)
|
31
33
|
+ [include_tag_key, tag_key](#include_tag_key-tag_key)
|
32
34
|
+ [id_key](#id_key)
|
35
|
+
+ [parent_key](#parent_key)
|
36
|
+
+ [routing_key](#routing_key)
|
37
|
+
+ [remove_keys](#remove_keys)
|
33
38
|
+ [write_operation](#write_operation)
|
34
39
|
+ [Client/host certificate options](#clienthost-certificate-options)
|
35
40
|
+ [Proxy Support](#proxy-support)
|
36
41
|
+ [Buffered output options](#buffered-output-options)
|
42
|
+
+ [Hash flattening](#hash-flattening)
|
37
43
|
+ [Not seeing a config you need?](#not-seeing-a-config-you-need)
|
38
44
|
+ [Dynamic configuration](#dynamic-configuration)
|
39
45
|
* [Contact](#contact)
|
@@ -117,7 +123,7 @@ logstash_dateformat %Y.%m. # defaults to "%Y.%m.%d"
|
|
117
123
|
|
118
124
|
### time_key_format
|
119
125
|
|
120
|
-
The format of the time stamp field (`@timestamp` or what you specify with [time_key]
|
126
|
+
The format of the time stamp field (`@timestamp` or what you specify with [time_key](#time_key)). This parameter only has an effect when [logstash_format](#logstash_format) is true as it only affects the name of the index we write to. Please see [Time#strftime](http://ruby-doc.org/core-1.9.3/Time.html#method-i-strftime) for information about the value of this format.
|
121
127
|
|
122
128
|
Setting this to a known format can vastly improve your log ingestion speed if all most of your logs are in the same format. If there is an error parsing this format the timestamp will default to the ingestion time. If you are on Ruby 2.0 or later you can get a further performance improvment by installing the "strptime" gem: `fluent-gem install strptime`.
|
123
129
|
|
@@ -161,6 +167,16 @@ The output will be
|
|
161
167
|
}
|
162
168
|
```
|
163
169
|
|
170
|
+
See `time_key_exclude_timestamp` to avoid adding `@timestamp`.
|
171
|
+
|
172
|
+
### time_key_exclude_timestamp
|
173
|
+
|
174
|
+
```
|
175
|
+
time_key_exclude_timestamp false
|
176
|
+
```
|
177
|
+
|
178
|
+
By default, setting `time_key` will copy the value to an additional field `@timestamp`. When setting `time_key_exclude_timestamp true`, no additional field will be added.
|
179
|
+
|
164
180
|
### utc_index
|
165
181
|
|
166
182
|
```
|
@@ -202,6 +218,10 @@ The output would be
|
|
202
218
|
|
203
219
|
and this record will be written to the specified index (`logstash-2014.12.19`) rather than `fallback`.
|
204
220
|
|
221
|
+
### target_type_key
|
222
|
+
|
223
|
+
Similar to `target_index_key` config, find the type name to write to in the record under this key. If key not found in record - fallback to `type_name` (default "fluentd").
|
224
|
+
|
205
225
|
### request_timeout
|
206
226
|
|
207
227
|
You can specify HTTP request timeout.
|
@@ -275,6 +295,38 @@ This following record `{"name":"Johnny","request_id":"87d89af7daffad6"}` will tr
|
|
275
295
|
{ "name": "Johnny", "request_id": "87d89af7daffad6" }
|
276
296
|
```
|
277
297
|
|
298
|
+
### parent_key
|
299
|
+
|
300
|
+
```
|
301
|
+
parent_key a_parent # use "a_parent" field value to set _parent in elasticsearch command
|
302
|
+
```
|
303
|
+
|
304
|
+
If your input is
|
305
|
+
```
|
306
|
+
{ "name": "Johnny", "a_parent": "my_parent" }
|
307
|
+
```
|
308
|
+
|
309
|
+
ElasticSearch command would be
|
310
|
+
|
311
|
+
```
|
312
|
+
{ "index" : { "_index" : "****", "_type" : "****", "_id" : "****", "_parent" : "my_parent" } }
|
313
|
+
{ "name": "Johnny", "a_parent": "my_parent" }
|
314
|
+
```
|
315
|
+
|
316
|
+
if `parent_key` is not configed or the `parent_key` is absent in input record, nothing will happen.
|
317
|
+
|
318
|
+
### routing_key
|
319
|
+
|
320
|
+
Similar to `parent_key` config, will add `_routing` into elasticsearch command if `routing_key` is set and the field does exist in input event.
|
321
|
+
|
322
|
+
### remove_keys
|
323
|
+
|
324
|
+
```
|
325
|
+
parent_key a_parent
|
326
|
+
routing_key a_routing
|
327
|
+
remove_keys a_parent, a_routing # a_parent and a_routing fileds wont be sent to elasticsearch
|
328
|
+
```
|
329
|
+
|
278
330
|
### write_operation
|
279
331
|
|
280
332
|
The write_operation can be any of:
|
@@ -318,7 +370,26 @@ retry_wait 1.0
|
|
318
370
|
num_threads 1
|
319
371
|
```
|
320
372
|
|
321
|
-
The value for option `buffer_chunk_limit` should not exceed value `http.max_content_length` in your Elasticsearch setup (by default it is
|
373
|
+
The value for option `buffer_chunk_limit` should not exceed value `http.max_content_length` in your Elasticsearch setup (by default it is 100mb).
|
374
|
+
|
375
|
+
### Hash flattening
|
376
|
+
|
377
|
+
Elasticsearch will complain if you send object and concrete values to the same field. For example, you might have logs that look this, from different places:
|
378
|
+
|
379
|
+
{"people" => 100}
|
380
|
+
{"people" => {"some" => "thing"}}
|
381
|
+
|
382
|
+
The second log line will be rejected by the Elasticsearch parser because objects and concrete values can't live in the same field. To combat this, you can enable hash flattening.
|
383
|
+
|
384
|
+
```
|
385
|
+
flatten_hashes true
|
386
|
+
flatten_hashes_separator _
|
387
|
+
```
|
388
|
+
|
389
|
+
This will produce elasticsearch output that looks like this:
|
390
|
+
{"people_some" => "thing"}
|
391
|
+
|
392
|
+
Note that the flattener does not deal with arrays at this time.
|
322
393
|
|
323
394
|
### Not seeing a config you need?
|
324
395
|
|
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = 'fluent-plugin-elasticsearch'
|
6
|
-
s.version = '1.
|
6
|
+
s.version = '1.5.0'
|
7
7
|
s.authors = ['diogo', 'pitr']
|
8
8
|
s.email = ['pitr.vern@gmail.com', 'me@diogoterror.com']
|
9
9
|
s.description = %q{ElasticSearch output plugin for Fluent event collector}
|
@@ -21,6 +21,7 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
21
21
|
config_param :scheme, :string, :default => 'http'
|
22
22
|
config_param :hosts, :string, :default => nil
|
23
23
|
config_param :target_index_key, :string, :default => nil
|
24
|
+
config_param :target_type_key, :string, :default => nil
|
24
25
|
config_param :time_key_format, :string, :default => nil
|
25
26
|
config_param :logstash_format, :bool, :default => false
|
26
27
|
config_param :logstash_prefix, :string, :default => "logstash"
|
@@ -31,16 +32,21 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
31
32
|
config_param :id_key, :string, :default => nil
|
32
33
|
config_param :write_operation, :string, :default => "index"
|
33
34
|
config_param :parent_key, :string, :default => nil
|
35
|
+
config_param :routing_key, :string, :default => nil
|
34
36
|
config_param :request_timeout, :time, :default => 5
|
35
37
|
config_param :reload_connections, :bool, :default => true
|
36
38
|
config_param :reload_on_failure, :bool, :default => false
|
37
39
|
config_param :resurrect_after, :time, :default => 60
|
38
40
|
config_param :time_key, :string, :default => nil
|
41
|
+
config_param :time_key_exclude_timestamp, :bool, :default => false
|
39
42
|
config_param :ssl_verify , :bool, :default => true
|
40
43
|
config_param :client_key, :string, :default => nil
|
41
44
|
config_param :client_cert, :string, :default => nil
|
42
45
|
config_param :client_key_pass, :string, :default => nil
|
43
46
|
config_param :ca_file, :string, :default => nil
|
47
|
+
config_param :remove_keys, :string, :default => nil
|
48
|
+
config_param :flatten_hashes, :bool, :default => false
|
49
|
+
config_param :flatten_hashes_separator, :string, :default => "_"
|
44
50
|
|
45
51
|
include Fluent::SetTagKeyMixin
|
46
52
|
config_set_default :include_tag_key, false
|
@@ -53,6 +59,10 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
53
59
|
def configure(conf)
|
54
60
|
super
|
55
61
|
@time_parser = TimeParser.new(@time_key_format, @router)
|
62
|
+
|
63
|
+
if @remove_keys
|
64
|
+
@remove_keys = @remove_keys.split(/\s*,\s*/)
|
65
|
+
end
|
56
66
|
end
|
57
67
|
|
58
68
|
def start
|
@@ -186,10 +196,29 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
186
196
|
end
|
187
197
|
end
|
188
198
|
|
199
|
+
def flatten_record(record, prefix=[])
|
200
|
+
ret = {}
|
201
|
+
if record.is_a? Hash
|
202
|
+
record.each { |key, value|
|
203
|
+
ret.merge! flatten_record(value, prefix + [key.to_s])
|
204
|
+
}
|
205
|
+
elsif record.is_a? Array
|
206
|
+
# Don't mess with arrays, leave them unprocessed
|
207
|
+
ret.merge!({prefix.join(@flatten_hashes_separator) => record})
|
208
|
+
else
|
209
|
+
return {prefix.join(@flatten_hashes_separator) => record}
|
210
|
+
end
|
211
|
+
ret
|
212
|
+
end
|
213
|
+
|
189
214
|
def write(chunk)
|
190
215
|
bulk_message = []
|
191
216
|
|
192
217
|
chunk.msgpack_each do |tag, time, record|
|
218
|
+
if @flatten_hashes
|
219
|
+
record = flatten_record(record)
|
220
|
+
end
|
221
|
+
|
193
222
|
next unless record.is_a? Hash
|
194
223
|
if @target_index_key && record[@target_index_key]
|
195
224
|
target_index = record.delete @target_index_key
|
@@ -199,7 +228,7 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
199
228
|
dt = @time_parser.parse(record["@timestamp"], time)
|
200
229
|
elsif record.has_key?(@time_key)
|
201
230
|
dt = @time_parser.parse(record[@time_key], time)
|
202
|
-
record['@timestamp'] = record[@time_key]
|
231
|
+
record['@timestamp'] = record[@time_key] unless time_key_exclude_timestamp
|
203
232
|
else
|
204
233
|
dt = Time.at(time).to_datetime
|
205
234
|
record.merge!({"@timestamp" => dt.to_s})
|
@@ -209,18 +238,31 @@ class Fluent::ElasticsearchOutput < Fluent::BufferedOutput
|
|
209
238
|
else
|
210
239
|
target_index = @index_name
|
211
240
|
end
|
212
|
-
|
241
|
+
|
242
|
+
# Change target_index to lower-case since Elasticsearch doesn't
|
243
|
+
# allow upper-case characters in index names.
|
244
|
+
target_index = target_index.downcase
|
245
|
+
|
213
246
|
if @include_tag_key
|
214
247
|
record.merge!(@tag_key => tag)
|
215
248
|
end
|
249
|
+
|
250
|
+
if @target_type_key && record[@target_type_key]
|
251
|
+
target_type = record.delete @target_type_key
|
252
|
+
else
|
253
|
+
target_type = @type_name
|
254
|
+
end
|
255
|
+
|
256
|
+
meta = {"_index" => target_index, "_type" => target_type}
|
216
257
|
|
217
|
-
|
218
|
-
|
219
|
-
|
258
|
+
@meta_config_map ||= { 'id_key' => '_id', 'parent_key' => '_parent', 'routing_key' => '_routing' }
|
259
|
+
@meta_config_map.each_pair do |config_name, meta_key|
|
260
|
+
record_key = self.instance_variable_get("@#{config_name}")
|
261
|
+
meta[meta_key] = record[record_key] if record_key && record[record_key]
|
220
262
|
end
|
221
263
|
|
222
|
-
if @
|
223
|
-
|
264
|
+
if @remove_keys
|
265
|
+
@remove_keys.each { |key| record.delete(key) }
|
224
266
|
end
|
225
267
|
|
226
268
|
append_record_to_messages(@write_operation, meta, record, bulk_message)
|
@@ -11,6 +11,7 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
11
11
|
config_param :port, :string, :default => "9200"
|
12
12
|
config_param :logstash_format, :string, :default => "false"
|
13
13
|
config_param :utc_index, :string, :default => "true"
|
14
|
+
config_param :time_key_exclude_timestamp, :bool, :default => false
|
14
15
|
config_param :reload_connections, :string, :default => "true"
|
15
16
|
config_param :reload_on_failure, :string, :default => "false"
|
16
17
|
config_param :resurrect_after, :string, :default => "60"
|
@@ -131,7 +132,7 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
131
132
|
time = Time.parse record["@timestamp"]
|
132
133
|
elsif record.has_key?(dynamic_conf['time_key'])
|
133
134
|
time = Time.parse record[dynamic_conf['time_key']]
|
134
|
-
record['@timestamp'] = record[dynamic_conf['time_key']]
|
135
|
+
record['@timestamp'] = record[dynamic_conf['time_key']] unless time_key_exclude_timestamp
|
135
136
|
else
|
136
137
|
record.merge!({"@timestamp" => Time.at(time).to_datetime.to_s})
|
137
138
|
end
|
@@ -144,18 +145,22 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
144
145
|
else
|
145
146
|
target_index = dynamic_conf['index_name']
|
146
147
|
end
|
147
|
-
|
148
|
+
|
149
|
+
# Change target_index to lower-case since Elasticsearch doesn't
|
150
|
+
# allow upper-case characters in index names.
|
151
|
+
target_index = target_index.downcase
|
152
|
+
|
148
153
|
if @include_tag_key
|
149
154
|
record.merge!(dynamic_conf['tag_key'] => tag)
|
150
155
|
end
|
151
156
|
|
152
157
|
meta = {"_index" => target_index, "_type" => dynamic_conf['type_name']}
|
153
|
-
if dynamic_conf['id_key'] && record[dynamic_conf['id_key']]
|
154
|
-
meta['_id'] = record[dynamic_conf['id_key']]
|
155
|
-
end
|
156
158
|
|
157
|
-
|
158
|
-
|
159
|
+
@meta_config_map ||= { 'id_key' => '_id', 'parent_key' => '_parent', 'routing_key' => '_routing' }
|
160
|
+
@meta_config_map.each_pair do |config_name, meta_key|
|
161
|
+
if dynamic_conf[config_name] && record[dynamic_conf[config_name]]
|
162
|
+
meta[meta_key] = record[dynamic_conf[config_name]]
|
163
|
+
end
|
159
164
|
end
|
160
165
|
|
161
166
|
if dynamic_conf['hosts']
|
@@ -164,6 +169,10 @@ class Fluent::ElasticsearchOutputDynamic < Fluent::ElasticsearchOutput
|
|
164
169
|
host = "#{dynamic_conf['host']}:#{dynamic_conf['port']}"
|
165
170
|
end
|
166
171
|
|
172
|
+
if @remove_keys
|
173
|
+
@remove_keys.each { |key| record.delete(key) }
|
174
|
+
end
|
175
|
+
|
167
176
|
append_record_to_messages(dynamic_conf["write_operation"], meta, record, bulk_message[host])
|
168
177
|
end
|
169
178
|
|
@@ -17,7 +17,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def sample_record
|
20
|
-
{'age' => 26, 'request_id' => '42', 'parent_id' => 'parent'}
|
20
|
+
{'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
|
21
21
|
end
|
22
22
|
|
23
23
|
def stub_elastic_ping(url="http://localhost:9200")
|
@@ -156,6 +156,17 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
156
156
|
driver.run
|
157
157
|
assert_equal('myindex', index_cmds.first['index']['_index'])
|
158
158
|
end
|
159
|
+
|
160
|
+
def test_writes_to_speficied_index_uppercase
|
161
|
+
driver.configure("index_name MyIndex\n")
|
162
|
+
stub_elastic_ping
|
163
|
+
stub_elastic
|
164
|
+
driver.emit(sample_record)
|
165
|
+
driver.run
|
166
|
+
# Allthough index_name has upper-case characters,
|
167
|
+
# it should be set as lower-case when sent to elasticsearch.
|
168
|
+
assert_equal('myindex', index_cmds.first['index']['_index'])
|
169
|
+
end
|
159
170
|
|
160
171
|
def test_writes_to_target_index_key
|
161
172
|
driver.configure("target_index_key @target_index\n")
|
@@ -167,7 +178,7 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
167
178
|
assert_equal('local-override', index_cmds.first['index']['_index'])
|
168
179
|
assert_nil(index_cmds[1]['@target_index'])
|
169
180
|
end
|
170
|
-
|
181
|
+
|
171
182
|
def test_writes_to_target_index_key_logstash
|
172
183
|
driver.configure("target_index_key @target_index\n")
|
173
184
|
driver.configure("logstash_format true\n")
|
@@ -178,6 +189,19 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
178
189
|
driver.run
|
179
190
|
assert_equal('local-override', index_cmds.first['index']['_index'])
|
180
191
|
end
|
192
|
+
|
193
|
+
def test_writes_to_target_index_key_logstash_uppercase
|
194
|
+
driver.configure("target_index_key @target_index\n")
|
195
|
+
driver.configure("logstash_format true\n")
|
196
|
+
time = Time.parse Date.today.to_s
|
197
|
+
stub_elastic_ping
|
198
|
+
stub_elastic
|
199
|
+
driver.emit(sample_record.merge('@target_index' => 'Local-Override'), time)
|
200
|
+
driver.run
|
201
|
+
# Allthough @target_index has upper-case characters,
|
202
|
+
# it should be set as lower-case when sent to elasticsearch.
|
203
|
+
assert_equal('local-override', index_cmds.first['index']['_index'])
|
204
|
+
end
|
181
205
|
|
182
206
|
def test_writes_to_target_index_key_fallack
|
183
207
|
driver.configure("target_index_key @target_index\n")
|
@@ -209,6 +233,36 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
209
233
|
assert_equal('mytype', index_cmds.first['index']['_type'])
|
210
234
|
end
|
211
235
|
|
236
|
+
def test_writes_to_target_type_key
|
237
|
+
driver.configure("target_type_key @target_type\n")
|
238
|
+
stub_elastic_ping
|
239
|
+
stub_elastic
|
240
|
+
record = sample_record.clone
|
241
|
+
driver.emit(sample_record.merge('@target_type' => 'local-override'))
|
242
|
+
driver.run
|
243
|
+
assert_equal('local-override', index_cmds.first['index']['_type'])
|
244
|
+
assert_nil(index_cmds[1]['@target_type'])
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_writes_to_target_type_key_fallack_to_default
|
248
|
+
driver.configure("target_type_key @target_type\n")
|
249
|
+
stub_elastic_ping
|
250
|
+
stub_elastic
|
251
|
+
driver.emit(sample_record)
|
252
|
+
driver.run
|
253
|
+
assert_equal('fluentd', index_cmds.first['index']['_type'])
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_writes_to_target_type_key_fallack_to_type_name
|
257
|
+
driver.configure("target_type_key @target_type\n")
|
258
|
+
driver.configure("type_name mytype\n")
|
259
|
+
stub_elastic_ping
|
260
|
+
stub_elastic
|
261
|
+
driver.emit(sample_record)
|
262
|
+
driver.run
|
263
|
+
assert_equal('mytype', index_cmds.first['index']['_type'])
|
264
|
+
end
|
265
|
+
|
212
266
|
def test_writes_to_speficied_host
|
213
267
|
driver.configure("host 192.168.33.50\n")
|
214
268
|
stub_elastic_ping("http://192.168.33.50:9200")
|
@@ -258,6 +312,40 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
258
312
|
assert_equal(2000, total)
|
259
313
|
end
|
260
314
|
|
315
|
+
def test_nested_record_with_flattening_on
|
316
|
+
driver.configure("flatten_hashes true
|
317
|
+
flatten_hashes_separator |")
|
318
|
+
|
319
|
+
original_hash = {"foo" => {"bar" => "baz"}, "people" => [
|
320
|
+
{"age" => "25", "height" => "1ft"},
|
321
|
+
{"age" => "30", "height" => "2ft"}
|
322
|
+
]}
|
323
|
+
|
324
|
+
expected_output = {"foo|bar"=>"baz", "people" => [
|
325
|
+
{"age" => "25", "height" => "1ft"},
|
326
|
+
{"age" => "30", "height" => "2ft"}
|
327
|
+
]}
|
328
|
+
|
329
|
+
stub_elastic_ping
|
330
|
+
stub_elastic
|
331
|
+
driver.emit(original_hash)
|
332
|
+
driver.run
|
333
|
+
assert_equal expected_output, index_cmds[1]
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_nested_record_with_flattening_off
|
337
|
+
# flattening off by default
|
338
|
+
|
339
|
+
original_hash = {"foo" => {"bar" => "baz"}}
|
340
|
+
expected_output = {"foo" => {"bar" => "baz"}}
|
341
|
+
|
342
|
+
stub_elastic_ping
|
343
|
+
stub_elastic
|
344
|
+
driver.emit(original_hash)
|
345
|
+
driver.run
|
346
|
+
assert_equal expected_output, index_cmds[1]
|
347
|
+
end
|
348
|
+
|
261
349
|
def test_makes_bulk_request
|
262
350
|
stub_elastic_ping
|
263
351
|
stub_elastic
|
@@ -315,6 +403,20 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
315
403
|
driver.run
|
316
404
|
assert_equal(logstash_index, index_cmds.first['index']['_index'])
|
317
405
|
end
|
406
|
+
|
407
|
+
def test_writes_to_logstash_index_with_specified_prefix_uppercase
|
408
|
+
driver.configure("logstash_format true
|
409
|
+
logstash_prefix MyPrefix")
|
410
|
+
time = Time.parse Date.today.to_s
|
411
|
+
logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
|
412
|
+
stub_elastic_ping
|
413
|
+
stub_elastic
|
414
|
+
driver.emit(sample_record, time)
|
415
|
+
driver.run
|
416
|
+
# Allthough logstash_prefix has upper-case characters,
|
417
|
+
# it should be set as lower-case when sent to elasticsearch.
|
418
|
+
assert_equal(logstash_index, index_cmds.first['index']['_index'])
|
419
|
+
end
|
318
420
|
|
319
421
|
def test_writes_to_logstash_index_with_specified_dateformat
|
320
422
|
driver.configure("logstash_format true
|
@@ -383,6 +485,17 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
383
485
|
assert_equal(index_cmds[1]['@timestamp'], ts)
|
384
486
|
end
|
385
487
|
|
488
|
+
def test_uses_custom_time_key_exclude_timekey
|
489
|
+
driver.configure("logstash_format true
|
490
|
+
time_key vtm
|
491
|
+
time_key_exclude_timestamp true\n")
|
492
|
+
stub_elastic_ping
|
493
|
+
stub_elastic
|
494
|
+
ts = DateTime.new(2001,2,3).to_s
|
495
|
+
driver.emit(sample_record.merge!('vtm' => ts))
|
496
|
+
driver.run
|
497
|
+
assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be messing')
|
498
|
+
end
|
386
499
|
|
387
500
|
def test_uses_custom_time_key_format
|
388
501
|
driver.configure("logstash_format true
|
@@ -502,6 +615,52 @@ class ElasticsearchOutput < Test::Unit::TestCase
|
|
502
615
|
assert(!index_cmds[0]['index'].has_key?('_parent'))
|
503
616
|
end
|
504
617
|
|
618
|
+
def test_adds_routing_key_when_configured
|
619
|
+
driver.configure("routing_key routing_id\n")
|
620
|
+
stub_elastic_ping
|
621
|
+
stub_elastic
|
622
|
+
driver.emit(sample_record)
|
623
|
+
driver.run
|
624
|
+
assert_equal(index_cmds[0]['index']['_routing'], 'routing')
|
625
|
+
end
|
626
|
+
|
627
|
+
def test_doesnt_add_routing_key_if_missing_when_configured
|
628
|
+
driver.configure("routing_key another_routing_id\n")
|
629
|
+
stub_elastic_ping
|
630
|
+
stub_elastic
|
631
|
+
driver.emit(sample_record)
|
632
|
+
driver.run
|
633
|
+
assert(!index_cmds[0]['index'].has_key?('_routing'))
|
634
|
+
end
|
635
|
+
|
636
|
+
def test_adds_routing_key_when_not_configured
|
637
|
+
stub_elastic_ping
|
638
|
+
stub_elastic
|
639
|
+
driver.emit(sample_record)
|
640
|
+
driver.run
|
641
|
+
assert(!index_cmds[0]['index'].has_key?('_routing'))
|
642
|
+
end
|
643
|
+
|
644
|
+
def test_remove_one_key
|
645
|
+
driver.configure("remove_keys key1\n")
|
646
|
+
stub_elastic_ping
|
647
|
+
stub_elastic
|
648
|
+
driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
|
649
|
+
driver.run
|
650
|
+
assert(!index_cmds[1].has_key?('key1'))
|
651
|
+
assert(index_cmds[1].has_key?('key2'))
|
652
|
+
end
|
653
|
+
|
654
|
+
def test_remove_multi_keys
|
655
|
+
driver.configure("remove_keys key1, key2\n")
|
656
|
+
stub_elastic_ping
|
657
|
+
stub_elastic
|
658
|
+
driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
|
659
|
+
driver.run
|
660
|
+
assert(!index_cmds[1].has_key?('key1'))
|
661
|
+
assert(!index_cmds[1].has_key?('key2'))
|
662
|
+
end
|
663
|
+
|
505
664
|
def test_request_error
|
506
665
|
stub_elastic_ping
|
507
666
|
stub_elastic_unavailable
|
@@ -15,7 +15,7 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def sample_record
|
18
|
-
{'age' => 26, 'request_id' => '42', 'parent_id' => 'parent'}
|
18
|
+
{'age' => 26, 'request_id' => '42', 'parent_id' => 'parent', 'routing_id' => 'routing'}
|
19
19
|
end
|
20
20
|
|
21
21
|
def stub_elastic_ping(url="http://localhost:9200")
|
@@ -154,6 +154,15 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
154
154
|
driver.run
|
155
155
|
assert_equal('myindex', index_cmds.first['index']['_index'])
|
156
156
|
end
|
157
|
+
|
158
|
+
def test_writes_to_speficied_index_uppercase
|
159
|
+
driver.configure("index_name MyIndex\n")
|
160
|
+
stub_elastic_ping
|
161
|
+
stub_elastic
|
162
|
+
driver.emit(sample_record)
|
163
|
+
driver.run
|
164
|
+
assert_equal('myindex', index_cmds.first['index']['_index'])
|
165
|
+
end
|
157
166
|
|
158
167
|
def test_writes_to_speficied_type
|
159
168
|
driver.configure("type_name mytype\n")
|
@@ -266,6 +275,18 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
266
275
|
driver.run
|
267
276
|
assert_equal(logstash_index, index_cmds.first['index']['_index'])
|
268
277
|
end
|
278
|
+
|
279
|
+
def test_writes_to_logstash_index_with_specified_prefix_uppercase
|
280
|
+
driver.configure("logstash_format true
|
281
|
+
logstash_prefix MyPrefix")
|
282
|
+
time = Time.parse Date.today.to_s
|
283
|
+
logstash_index = "myprefix-#{time.getutc.strftime("%Y.%m.%d")}"
|
284
|
+
stub_elastic_ping
|
285
|
+
stub_elastic
|
286
|
+
driver.emit(sample_record, time)
|
287
|
+
driver.run
|
288
|
+
assert_equal(logstash_index, index_cmds.first['index']['_index'])
|
289
|
+
end
|
269
290
|
|
270
291
|
def test_writes_to_logstash_index_with_specified_dateformat
|
271
292
|
driver.configure("logstash_format true
|
@@ -334,6 +355,18 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
334
355
|
assert_equal(index_cmds[1]['@timestamp'], ts)
|
335
356
|
end
|
336
357
|
|
358
|
+
def test_uses_custom_time_key_exclude_timestamp
|
359
|
+
driver.configure("logstash_format true
|
360
|
+
time_key vtm
|
361
|
+
time_key_exclude_timestamp true\n")
|
362
|
+
stub_elastic_ping
|
363
|
+
stub_elastic
|
364
|
+
ts = DateTime.new(2001,2,3).to_s
|
365
|
+
driver.emit(sample_record.merge!('vtm' => ts))
|
366
|
+
driver.run
|
367
|
+
assert(!index_cmds[1].key?('@timestamp'), '@timestamp should be missing')
|
368
|
+
end
|
369
|
+
|
337
370
|
def test_doesnt_add_tag_key_by_default
|
338
371
|
stub_elastic_ping
|
339
372
|
stub_elastic
|
@@ -404,6 +437,52 @@ class ElasticsearchOutputDynamic < Test::Unit::TestCase
|
|
404
437
|
assert(!index_cmds[0]['index'].has_key?('_parent'))
|
405
438
|
end
|
406
439
|
|
440
|
+
def test_adds_routing_key_when_configured
|
441
|
+
driver.configure("routing_key routing_id\n")
|
442
|
+
stub_elastic_ping
|
443
|
+
stub_elastic
|
444
|
+
driver.emit(sample_record)
|
445
|
+
driver.run
|
446
|
+
assert_equal(index_cmds[0]['index']['_routing'], 'routing')
|
447
|
+
end
|
448
|
+
|
449
|
+
def test_doesnt_add_routing_key_if_missing_when_configured
|
450
|
+
driver.configure("routing_key another_routing_id\n")
|
451
|
+
stub_elastic_ping
|
452
|
+
stub_elastic
|
453
|
+
driver.emit(sample_record)
|
454
|
+
driver.run
|
455
|
+
assert(!index_cmds[0]['index'].has_key?('_routing'))
|
456
|
+
end
|
457
|
+
|
458
|
+
def test_adds_routing_key_when_not_configured
|
459
|
+
stub_elastic_ping
|
460
|
+
stub_elastic
|
461
|
+
driver.emit(sample_record)
|
462
|
+
driver.run
|
463
|
+
assert(!index_cmds[0]['index'].has_key?('_routing'))
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_remove_one_key
|
467
|
+
driver.configure("remove_keys key1\n")
|
468
|
+
stub_elastic_ping
|
469
|
+
stub_elastic
|
470
|
+
driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
|
471
|
+
driver.run
|
472
|
+
assert(!index_cmds[1].has_key?('key1'))
|
473
|
+
assert(index_cmds[1].has_key?('key2'))
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_remove_multi_keys
|
477
|
+
driver.configure("remove_keys key1, key2\n")
|
478
|
+
stub_elastic_ping
|
479
|
+
stub_elastic
|
480
|
+
driver.emit(sample_record.merge('key1' => 'v1', 'key2' => 'v2'))
|
481
|
+
driver.run
|
482
|
+
assert(!index_cmds[1].has_key?('key1'))
|
483
|
+
assert(!index_cmds[1].has_key?('key2'))
|
484
|
+
end
|
485
|
+
|
407
486
|
def test_request_error
|
408
487
|
stub_elastic_ping
|
409
488
|
stub_elastic_unavailable
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-elasticsearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- diogo
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-05-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fluentd
|
@@ -124,6 +124,7 @@ files:
|
|
124
124
|
- Gemfile
|
125
125
|
- History.md
|
126
126
|
- LICENSE.txt
|
127
|
+
- PULL_REQUEST_TEMPLATE.md
|
127
128
|
- README.md
|
128
129
|
- Rakefile
|
129
130
|
- fluent-plugin-elasticsearch.gemspec
|