fluent-plugin-kubernetes_metadata_filter 2.0.0 → 2.1.0
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 +4 -4
- data/README.md +22 -2
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +1 -1
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +5 -33
- data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +3 -0
- data/test/plugin/test_filter_kubernetes_metadata.rb +0 -83
- data/test/plugin/test_watch_pods.rb +11 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58bdc9ed97a93eb46eeec306ad5851b94d3b5656
|
4
|
+
data.tar.gz: 56806c61750f533d2190c0a0915fb1fed0b4d46e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e38271b6f13d95781df47a4c99474ec9d54bd8926a48a55d2613086079997728902d74b1207986325e36f9ea647b65786b0602f280a8ae5d4c37f3ae4737973a
|
7
|
+
data.tar.gz: 90a46813a80eec7928f35387adc4778d3c07e1e6f61eea0cf3ca1725ef8195bf73816f733bb7c5cb0464cd69269981a8fb7562bc2a3e17ffaf00384624821b74
|
data/README.md
CHANGED
@@ -42,8 +42,6 @@ This must used named capture groups for `container_name`, `pod_name` & `namespac
|
|
42
42
|
* `cache_size` - size of the cache of Kubernetes metadata to reduce requests to the API server (default: `1000`)
|
43
43
|
* `cache_ttl` - TTL in seconds of each cached element. Set to negative value to disable TTL eviction (default: `3600` - 1 hour)
|
44
44
|
* `watch` - set up a watch on pods on the API server for updates to metadata (default: `true`)
|
45
|
-
* `merge_json_log` - merge logs in JSON format as top level keys (default: `true`)
|
46
|
-
* `preserve_json_log` - preserve JSON logs in raw form in the `log` key, only used if the previous option is true (default: `true`)
|
47
45
|
* `de_dot` - replace dots in labels and annotations with configured `de_dot_separator`, required for ElasticSearch 2.x compatibility (default: `true`)
|
48
46
|
* `de_dot_separator` - separator to use if `de_dot` is enabled (default: `_`)
|
49
47
|
* `use_journal` - If false (default), messages are expected to be formatted and tagged as if read by the fluentd in\_tail plugin with wildcard filename. If true, messages are expected to be formatted as if read from the systemd journal. The `MESSAGE` field has the full message. The `CONTAINER_NAME` field has the encoded k8s metadata (see below). The `CONTAINER_ID_FULL` field has the full container uuid. This requires docker to use the `--log-driver=journald` log driver.
|
@@ -55,6 +53,12 @@ when true (default: `true`)
|
|
55
53
|
* `orphaned_namespace_name` - The namespace to associate with records where the namespace can not be determined (default: `.orphaned`)
|
56
54
|
* `orphaned_namespace_id` - The namespace id to associate with records where the namespace can not be determined (default: `orphaned`)
|
57
55
|
|
56
|
+
**NOTE:** As of the release 1.1.x of this plugin, it no longer supports parsing the source message into JSON and attaching it to the
|
57
|
+
payload. The following configuration options are removed:
|
58
|
+
|
59
|
+
* `merge_json_log`
|
60
|
+
* `preserve_json_log`
|
61
|
+
|
58
62
|
Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
|
59
63
|
```
|
60
64
|
<source>
|
@@ -104,6 +108,22 @@ Reading from the systemd journal (requires the fluentd `fluent-plugin-systemd` a
|
|
104
108
|
</match>
|
105
109
|
```
|
106
110
|
|
111
|
+
## Environment variables for Kubernetes
|
112
|
+
|
113
|
+
If the name of the Kubernetes node the plugin is running on is set as
|
114
|
+
an environment variable with the name `K8S_NODE_NAME`, it will reduce cache
|
115
|
+
misses and needless calls to the Kubernetes API.
|
116
|
+
|
117
|
+
In the Kubernetes container definition, this is easily accomplished by:
|
118
|
+
|
119
|
+
```yaml
|
120
|
+
env:
|
121
|
+
- name: K8S_NODE_NAME
|
122
|
+
valueFrom:
|
123
|
+
fieldRef:
|
124
|
+
fieldPath: spec.nodeName
|
125
|
+
```
|
126
|
+
|
107
127
|
## Example input/output
|
108
128
|
|
109
129
|
Kubernetes creates symlinks to Docker log files in `/var/log/containers/*.log`. Docker logs in JSON format.
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "fluent-plugin-kubernetes_metadata_filter"
|
7
|
-
gem.version = "2.
|
7
|
+
gem.version = "2.1.0"
|
8
8
|
gem.authors = ["Jimmi Dyson"]
|
9
9
|
gem.email = ["jimmidyson@gmail.com"]
|
10
10
|
gem.description = %q{Filter plugin to add Kubernetes metadata}
|
@@ -50,8 +50,6 @@ module Fluent::Plugin
|
|
50
50
|
:string,
|
51
51
|
:default => 'var\.log\.containers\.(?<pod_name>[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)_(?<namespace>[^_]+)_(?<container_name>.+)-(?<docker_id>[a-z0-9]{64})\.log$'
|
52
52
|
config_param :bearer_token_file, :string, default: nil
|
53
|
-
config_param :merge_json_log, :bool, default: true
|
54
|
-
config_param :preserve_json_log, :bool, default: true
|
55
53
|
config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
|
56
54
|
config_param :de_dot, :bool, default: true
|
57
55
|
config_param :de_dot_separator, :string, default: '_'
|
@@ -247,11 +245,9 @@ module Fluent::Plugin
|
|
247
245
|
end
|
248
246
|
if @use_journal
|
249
247
|
log.debug "Will stream from the journal"
|
250
|
-
@merge_json_log_key = 'MESSAGE'
|
251
248
|
self.class.class_eval { alias_method :filter_stream, :filter_stream_from_journal }
|
252
249
|
else
|
253
250
|
log.debug "Will stream from the files"
|
254
|
-
@merge_json_log_key = 'log'
|
255
251
|
self.class.class_eval { alias_method :filter_stream, :filter_stream_from_files }
|
256
252
|
end
|
257
253
|
|
@@ -309,13 +305,10 @@ module Fluent::Plugin
|
|
309
305
|
}
|
310
306
|
end
|
311
307
|
|
312
|
-
es.each
|
313
|
-
record = merge_json_log(record) if @merge_json_log
|
314
|
-
|
308
|
+
es.each do |time, record|
|
315
309
|
record = record.merge(Marshal.load(Marshal.dump(metadata))) if metadata
|
316
|
-
|
317
310
|
new_es.add(time, record)
|
318
|
-
|
311
|
+
end
|
319
312
|
dump_stats
|
320
313
|
new_es
|
321
314
|
end
|
@@ -323,8 +316,7 @@ module Fluent::Plugin
|
|
323
316
|
def filter_stream_from_journal(tag, es)
|
324
317
|
new_es = Fluent::MultiEventStream.new
|
325
318
|
batch_miss_cache = {}
|
326
|
-
es.each
|
327
|
-
record = merge_json_log(record) if @merge_json_log
|
319
|
+
es.each do |time, record|
|
328
320
|
metadata = nil
|
329
321
|
if record.has_key?('CONTAINER_NAME') && record.has_key?('CONTAINER_ID_FULL')
|
330
322
|
metadata = record['CONTAINER_NAME'].match(@container_name_to_kubernetes_regexp_compiled) do |match_data|
|
@@ -347,35 +339,15 @@ module Fluent::Plugin
|
|
347
339
|
@stats.bump(:container_name_id_missing)
|
348
340
|
end
|
349
341
|
|
350
|
-
if metadata
|
351
|
-
record = record.merge(metadata)
|
352
|
-
end
|
342
|
+
record = record.merge(metadata) if metadata
|
353
343
|
|
354
344
|
new_es.add(time, record)
|
355
|
-
|
345
|
+
end
|
356
346
|
|
357
347
|
dump_stats
|
358
348
|
new_es
|
359
349
|
end
|
360
350
|
|
361
|
-
def merge_json_log(record)
|
362
|
-
if record.has_key?(@merge_json_log_key)
|
363
|
-
value = record[@merge_json_log_key].strip
|
364
|
-
if value[0].eql?('{') && value[-1].eql?('}')
|
365
|
-
begin
|
366
|
-
record = JSON.parse(value).merge(record)
|
367
|
-
unless @preserve_json_log
|
368
|
-
record.delete(@merge_json_log_key)
|
369
|
-
end
|
370
|
-
rescue JSON::ParserError=>e
|
371
|
-
@stats.bump(:merge_json_parse_errors)
|
372
|
-
log.debug(e)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
record
|
377
|
-
end
|
378
|
-
|
379
351
|
def de_dot!(h)
|
380
352
|
h.keys.each do |ref|
|
381
353
|
if h[ref] && ref =~ /\./
|
@@ -42,6 +42,9 @@ module KubernetesMetadata
|
|
42
42
|
if cached
|
43
43
|
@cache[cache_key] = parse_pod_metadata(notice.object)
|
44
44
|
@stats.bump(:pod_cache_watch_updates)
|
45
|
+
elsif ENV['K8S_NODE_NAME'] == notice.object['spec']['nodeName'] then
|
46
|
+
@cache[cache_key] = parse_pod_metadata(notice.object)
|
47
|
+
@stats.bump(:pod_cache_host_updates)
|
45
48
|
else
|
46
49
|
@stats.bump(:pod_cache_watch_misses)
|
47
50
|
end
|
@@ -381,45 +381,6 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
381
381
|
assert_false(filtered[0].has_key?(:kubernetes))
|
382
382
|
end
|
383
383
|
|
384
|
-
test 'merges json log data' do
|
385
|
-
json_log = {
|
386
|
-
'hello' => 'world'
|
387
|
-
}
|
388
|
-
msg = {
|
389
|
-
'log' => "#{json_log.to_json}"
|
390
|
-
}
|
391
|
-
filtered = emit_with_tag('non-kubernetes', msg, '')
|
392
|
-
assert_equal(msg.merge(json_log), filtered[0])
|
393
|
-
end
|
394
|
-
|
395
|
-
test 'merges json log data in MESSAGE' do
|
396
|
-
json_log = {
|
397
|
-
'hello' => 'world'
|
398
|
-
}
|
399
|
-
msg = {
|
400
|
-
'MESSAGE' => "#{json_log.to_json}"
|
401
|
-
}
|
402
|
-
filtered = emit_with_tag('non-kubernetes', msg, 'use_journal true')
|
403
|
-
assert_equal(msg.merge(json_log), filtered[0])
|
404
|
-
end
|
405
|
-
|
406
|
-
test 'merges json log data with message field' do
|
407
|
-
json_log = {
|
408
|
-
'timeMillis' => 1459853347608,
|
409
|
-
'thread' => 'main',
|
410
|
-
'level' => 'INFO',
|
411
|
-
'loggerName' => 'org.apache.camel.spring.SpringCamelContext',
|
412
|
-
'message' => 'Total 1 routes, of which 1 is started.',
|
413
|
-
'endOfBatch' => false,
|
414
|
-
'loggerFqcn' => 'org.apache.logging.slf4j.Log4jLogger'
|
415
|
-
}
|
416
|
-
msg = {
|
417
|
-
'log' => "#{json_log.to_json}"
|
418
|
-
}
|
419
|
-
filtered = emit_with_tag('non-kubernetes', msg, '')
|
420
|
-
assert_equal(msg.merge(json_log), filtered[0])
|
421
|
-
end
|
422
|
-
|
423
384
|
test 'ignores invalid json in log field' do
|
424
385
|
json_log = "{'foo':123}"
|
425
386
|
msg = {
|
@@ -429,50 +390,6 @@ class KubernetesMetadataFilterTest < Test::Unit::TestCase
|
|
429
390
|
assert_equal(msg, filtered[0])
|
430
391
|
end
|
431
392
|
|
432
|
-
test 'merges json log data with message field in MESSAGE' do
|
433
|
-
json_log = {
|
434
|
-
'timeMillis' => 1459853347608,
|
435
|
-
'thread' => 'main',
|
436
|
-
'level' => 'INFO',
|
437
|
-
'loggerName' => 'org.apache.camel.spring.SpringCamelContext',
|
438
|
-
'message' => 'Total 1 routes, of which 1 is started.',
|
439
|
-
'endOfBatch' => false,
|
440
|
-
'loggerFqcn' => 'org.apache.logging.slf4j.Log4jLogger'
|
441
|
-
}
|
442
|
-
msg = {
|
443
|
-
'MESSAGE' => "#{json_log.to_json}"
|
444
|
-
}
|
445
|
-
filtered = emit_with_tag('non-kubernetes', msg, 'use_journal true')
|
446
|
-
assert_equal(msg.merge(json_log), filtered[0])
|
447
|
-
end
|
448
|
-
|
449
|
-
test 'emit individual fields from json, throw out whole original string' do
|
450
|
-
json_log = {
|
451
|
-
'hello' => 'world',
|
452
|
-
'more' => 'data'
|
453
|
-
}
|
454
|
-
msg = {
|
455
|
-
'log' => "#{json_log.to_json}"
|
456
|
-
}
|
457
|
-
filtered = emit_with_tag('non-kubernetes', msg, 'preserve_json_log false')
|
458
|
-
assert_equal(json_log, filtered[0])
|
459
|
-
end
|
460
|
-
|
461
|
-
test 'emit individual fields from json, throw out whole original string in MESSAGE' do
|
462
|
-
json_log = {
|
463
|
-
'hello' => 'world',
|
464
|
-
'more' => 'data'
|
465
|
-
}
|
466
|
-
msg = {
|
467
|
-
'MESSAGE' => "#{json_log.to_json}"
|
468
|
-
}
|
469
|
-
filtered = emit_with_tag('non-kubernetes', msg, '
|
470
|
-
preserve_json_log false
|
471
|
-
use_journal true
|
472
|
-
')
|
473
|
-
assert_equal(json_log, filtered[0])
|
474
|
-
end
|
475
|
-
|
476
393
|
test 'with kubernetes dotted labels, de_dot enabled' do
|
477
394
|
VCR.use_cassette('kubernetes_docker_metadata_dotted_labels') do
|
478
395
|
filtered = emit({}, '
|
@@ -81,6 +81,17 @@ class DefaultPodWatchStrategyTest < WatchTest
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
test 'pod MODIFIED cached when hostname matches' do
|
85
|
+
orig_env_val = ENV['K8S_NODE_NAME']
|
86
|
+
ENV['K8S_NODE_NAME'] = 'aNodeName'
|
87
|
+
@client.stub :watch_pods, [@modified] do
|
88
|
+
start_pod_watch
|
89
|
+
assert_equal(true, @cache.key?('modified_uid'))
|
90
|
+
assert_equal(1, @stats[:pod_cache_host_updates])
|
91
|
+
end
|
92
|
+
ENV['K8S_NODE_NAME'] = orig_env_val
|
93
|
+
end
|
94
|
+
|
84
95
|
test 'pod watch notice is updated when MODIFIED is received' do
|
85
96
|
@cache['modified_uid'] = {}
|
86
97
|
@client.stub :watch_pods, [@modified] do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-kubernetes_metadata_filter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jimmi Dyson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|