fluent-plugin-kubernetes_metadata_filter 1.2.2 → 2.0.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 +5 -5
- data/Gemfile +1 -5
- data/README.md +3 -35
- data/circle.yml +2 -0
- data/fluent-plugin-kubernetes_metadata_filter.gemspec +4 -13
- data/lib/fluent/plugin/filter_kubernetes_metadata.rb +116 -79
- data/lib/fluent/plugin/kubernetes_metadata_cache_strategy.rb +1 -1
- data/lib/fluent/plugin/kubernetes_metadata_common.rb +0 -46
- data/lib/fluent/plugin/kubernetes_metadata_watch_pods.rb +0 -3
- data/test/cassettes/kubernetes_docker_metadata_using_bearer_token.yml +1 -1
- data/test/plugin/test_filter_kubernetes_metadata.rb +247 -345
- data/test/plugin/test_watch_pods.rb +3 -46
- metadata +13 -10
- data/test/cassettes/metadata_from_tag_and_journald_fields.yml +0 -408
- data/test/cassettes/metadata_from_tag_journald_and_kubernetes_fields.yml +0 -540
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3e76bf94f6dd2d7d375b01379c3a0533670291e7
|
4
|
+
data.tar.gz: 0cf265d4423a322313a6233a9360c0438081f878
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c52356d4f5edc444bfb26b9f812257cafc250328f7de81708bb7f3e64711c1c85895a46877537d7fd5d17e486f75328900a848d80625e6450922672005b7ce6a
|
7
|
+
data.tar.gz: 4d0e4b4cdfd0734736419d32fe4237130e81fd04cc6612a5ea5f1eca22c69b8300b8ea4baeeca943b63dad93f256aeb7f35bd160f753a1a28ad650d395ba43b4
|
data/Gemfile
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
gem 'codeclimate-test-reporter', '<1.0.0', :group => :test, :require => nil
|
4
|
-
|
5
|
-
gem 'rubocop', '<0.51.0', require: false
|
6
|
-
else
|
7
|
-
gem 'rubocop', require: false
|
8
|
-
end
|
4
|
+
gem 'rubocop', require: false
|
9
5
|
|
10
6
|
# Specify your gem's dependencies in fluent-plugin-add.gemspec
|
11
7
|
gemspec
|
data/README.md
CHANGED
@@ -42,10 +42,11 @@ 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`)
|
45
47
|
* `de_dot` - replace dots in labels and annotations with configured `de_dot_separator`, required for ElasticSearch 2.x compatibility (default: `true`)
|
46
48
|
* `de_dot_separator` - separator to use if `de_dot` is enabled (default: `_`)
|
47
|
-
*
|
48
|
-
if available, otherwise, will use the tag in the `tag_to_kubernetes_name_regexp` format.
|
49
|
+
* `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.
|
49
50
|
* `container_name_to_kubernetes_regexp` - The regular expression used to extract the k8s metadata encoded in the journal `CONTAINER_NAME` field (default: `'^(?<name_prefix>[^_]+)_(?<container_name>[^\._]+)(\.(?<container_hash>[^_]+))?_(?<pod_name>[^_]+)_(?<namespace>[^_]+)_[^_]+_[^_]+$'`
|
50
51
|
* This corresponds to the definition [in the source](https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockertools/docker.go#L317)
|
51
52
|
* `annotation_match` - Array of regular expressions matching annotation field names. Matched annotations are added to a log record.
|
@@ -53,23 +54,6 @@ if available, otherwise, will use the tag in the `tag_to_kubernetes_name_regexp`
|
|
53
54
|
when true (default: `true`)
|
54
55
|
* `orphaned_namespace_name` - The namespace to associate with records where the namespace can not be determined (default: `.orphaned`)
|
55
56
|
* `orphaned_namespace_id` - The namespace id to associate with records where the namespace can not be determined (default: `orphaned`)
|
56
|
-
* `lookup_from_k8s_field` - If the field `kubernetes` is present, lookup the metadata from the given subfields such as `kubernetes.namespace_name`, `kubernetes.pod_name`, etc. This allows you to avoid having to pass in metadata to lookup in an explicitly formatted tag name or in an explicitly formatted `CONTAINER_NAME` value. For example, set `kubernetes.namespace_name`, `kubernetes.pod_name`, `kubernetes.container_name`, and `docker.id` in the record, and the filter will fill in the rest. (default: `true`)
|
57
|
-
|
58
|
-
**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
|
59
|
-
payload. The following configuration options are removed:
|
60
|
-
|
61
|
-
* `merge_json_log`
|
62
|
-
* `preserve_json_log`
|
63
|
-
|
64
|
-
**NOTE** As of this release, the use of `use_journal` is **DEPRECATED**. If this setting is not present, the plugin will
|
65
|
-
attempt to figure out the source of the metadata fields from the following:
|
66
|
-
- If `lookup_from_k8s_field true` (the default) and the following fields are present in the record:
|
67
|
-
`docker.container_id`, `kubernetes.namespace_name`, `kubernetes.pod_name`, `kubernetes.container_name`,
|
68
|
-
then the plugin will use those values as the source to use to lookup the metadata
|
69
|
-
- If `use_journal true`, or `use_journal` is unset, and the fields `CONTAINER_NAME` and `CONTAINER_ID_FULL` are present in the record,
|
70
|
-
then the plugin will parse those values using `container_name_to_kubernetes_regexp` and use those as the source to lookup the metadata
|
71
|
-
- Otherwise, if the tag matches `tag_to_kubernetes_name_regexp`, the plugin will parse the tag and use those values to
|
72
|
-
lookup the metdata
|
73
57
|
|
74
58
|
Reading from the JSON formatted log files with `in_tail` and wildcard filenames:
|
75
59
|
```
|
@@ -120,22 +104,6 @@ Reading from the systemd journal (requires the fluentd `fluent-plugin-systemd` a
|
|
120
104
|
</match>
|
121
105
|
```
|
122
106
|
|
123
|
-
## Environment variables for Kubernetes
|
124
|
-
|
125
|
-
If the name of the Kubernetes node the plugin is running on is set as
|
126
|
-
an environment variable with the name `K8S_NODE_NAME`, it will reduce cache
|
127
|
-
misses and needless calls to the Kubernetes API.
|
128
|
-
|
129
|
-
In the Kubernetes container definition, this is easily accomplished by:
|
130
|
-
|
131
|
-
```yaml
|
132
|
-
env:
|
133
|
-
- name: K8S_NODE_NAME
|
134
|
-
valueFrom:
|
135
|
-
fieldRef:
|
136
|
-
fieldPath: spec.nodeName
|
137
|
-
```
|
138
|
-
|
139
107
|
## Example input/output
|
140
108
|
|
141
109
|
Kubernetes creates symlinks to Docker log files in `/var/log/containers/*.log`. Docker logs in JSON format.
|
data/circle.yml
CHANGED
@@ -7,9 +7,11 @@ dependencies:
|
|
7
7
|
- 'rvm-exec 2.1.9 bundle install'
|
8
8
|
- 'rvm-exec 2.2.5 bundle install'
|
9
9
|
- 'rvm-exec 2.3.1 bundle install'
|
10
|
+
- 'rvm-exec 2.4.3 bundle install'
|
10
11
|
|
11
12
|
test:
|
12
13
|
override:
|
13
14
|
- 'rvm-exec 2.1.9 bundle exec rake test'
|
14
15
|
- 'rvm-exec 2.2.5 bundle exec rake test'
|
15
16
|
- 'rvm-exec 2.3.1 bundle exec rake test'
|
17
|
+
- 'rvm-exec 2.4.3 bundle exec rake test'
|
@@ -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 = "
|
7
|
+
gem.version = "2.0.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}
|
@@ -18,23 +18,14 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.has_rdoc = false
|
20
20
|
|
21
|
-
gem.required_ruby_version = '>= 2.
|
21
|
+
gem.required_ruby_version = '>= 2.1.0'
|
22
22
|
|
23
|
-
gem.add_runtime_dependency
|
23
|
+
gem.add_runtime_dependency 'fluentd', ['>= 0.14.0', '< 2']
|
24
24
|
gem.add_runtime_dependency "lru_redux"
|
25
25
|
gem.add_runtime_dependency "kubeclient", "~> 1.1.4"
|
26
|
-
if RUBY_VERSION == "2.0.0"
|
27
|
-
gem.add_runtime_dependency "public_suffix", "< 3"
|
28
|
-
gem.add_runtime_dependency "parallel", "< 1.14"
|
29
|
-
gem.add_runtime_dependency "rainbow", "< 3"
|
30
|
-
end
|
31
26
|
|
32
27
|
gem.add_development_dependency "bundler", "~> 1.3"
|
33
|
-
|
34
|
-
gem.add_development_dependency "rake", "< 13"
|
35
|
-
else
|
36
|
-
gem.add_development_dependency "rake"
|
37
|
-
end
|
28
|
+
gem.add_development_dependency "rake"
|
38
29
|
gem.add_development_dependency "minitest", "~> 4.0"
|
39
30
|
gem.add_development_dependency "test-unit", "~> 3.0.2"
|
40
31
|
gem.add_development_dependency "test-unit-rr", "~> 1.0.3"
|
@@ -23,8 +23,10 @@ require_relative 'kubernetes_metadata_stats'
|
|
23
23
|
require_relative 'kubernetes_metadata_watch_namespaces'
|
24
24
|
require_relative 'kubernetes_metadata_watch_pods'
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
require 'fluent/plugin/filter'
|
27
|
+
|
28
|
+
module Fluent::Plugin
|
29
|
+
class KubernetesMetadataFilter < Fluent::Plugin::Filter
|
28
30
|
K8_POD_CA_CERT = 'ca.crt'
|
29
31
|
K8_POD_TOKEN = 'token'
|
30
32
|
|
@@ -48,6 +50,8 @@ module Fluent
|
|
48
50
|
:string,
|
49
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$'
|
50
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
|
51
55
|
config_param :secret_dir, :string, default: '/var/run/secrets/kubernetes.io/serviceaccount'
|
52
56
|
config_param :de_dot, :bool, default: true
|
53
57
|
config_param :de_dot_separator, :string, default: '_'
|
@@ -55,7 +59,7 @@ module Fluent
|
|
55
59
|
# format:
|
56
60
|
# CONTAINER_NAME=k8s_$containername.$containerhash_$podname_$namespacename_$poduuid_$rand32bitashex
|
57
61
|
# CONTAINER_FULL_ID=dockeridassha256hexvalue
|
58
|
-
config_param :use_journal, :bool, default:
|
62
|
+
config_param :use_journal, :bool, default: false
|
59
63
|
# Field 2 is the container_hash, field 5 is the pod_id, and field 6 is the pod_randhex
|
60
64
|
# I would have included them as named groups, but you can't have named groups that are
|
61
65
|
# non-capturing :P
|
@@ -69,7 +73,6 @@ module Fluent
|
|
69
73
|
config_param :allow_orphans, :bool, default: true
|
70
74
|
config_param :orphaned_namespace_name, :string, default: '.orphaned'
|
71
75
|
config_param :orphaned_namespace_id, :string, default: 'orphaned'
|
72
|
-
config_param :lookup_from_k8s_field, :bool, default: true
|
73
76
|
|
74
77
|
def fetch_pod_metadata(namespace_name, pod_name)
|
75
78
|
log.trace("fetching pod metadata: #{namespace_name}/#{pod_name}") if log.trace?
|
@@ -89,12 +92,12 @@ module Fluent
|
|
89
92
|
rescue Exception=>e
|
90
93
|
log.debug(e)
|
91
94
|
@stats.bump(:pod_cache_api_nil_bad_resp_payload)
|
92
|
-
log.trace("returning empty metadata for #{namespace_name}/#{pod_name} due to error
|
95
|
+
log.trace("returning empty metadata for #{namespace_name}/#{pod_name} due to error") if log.trace?
|
93
96
|
end
|
94
97
|
end
|
95
|
-
rescue
|
98
|
+
rescue KubeException=>e
|
96
99
|
@stats.bump(:pod_cache_api_nil_error)
|
97
|
-
log.debug "Exception
|
100
|
+
log.debug "Exception encountered fetching pod metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{e.message}"
|
98
101
|
end
|
99
102
|
{}
|
100
103
|
end
|
@@ -126,17 +129,17 @@ module Fluent
|
|
126
129
|
metadata = parse_namespace_metadata(metadata)
|
127
130
|
@stats.bump(:namespace_cache_api_updates)
|
128
131
|
log.trace("parsed metadata for #{namespace_name}: #{metadata}") if log.trace?
|
129
|
-
|
132
|
+
@namespace_cache[metadata['namespace_id']] = metadata
|
130
133
|
return metadata
|
131
134
|
rescue Exception => e
|
132
135
|
log.debug(e)
|
133
136
|
@stats.bump(:namespace_cache_api_nil_bad_resp_payload)
|
134
|
-
log.trace("returning empty metadata for #{namespace_name} due to error
|
137
|
+
log.trace("returning empty metadata for #{namespace_name} due to error") if log.trace?
|
135
138
|
end
|
136
139
|
end
|
137
|
-
rescue
|
140
|
+
rescue KubeException => kube_error
|
138
141
|
@stats.bump(:namespace_cache_api_nil_error)
|
139
|
-
log.debug "Exception
|
142
|
+
log.debug "Exception encountered fetching namespace metadata from Kubernetes API #{@apiVersion} endpoint #{@kubernetes_url}: #{kube_error.message}"
|
140
143
|
end
|
141
144
|
{}
|
142
145
|
end
|
@@ -154,6 +157,7 @@ module Fluent
|
|
154
157
|
end
|
155
158
|
|
156
159
|
require 'kubeclient'
|
160
|
+
require 'active_support/core_ext/object/blank'
|
157
161
|
require 'lru_redux'
|
158
162
|
@stats = KubernetesMetadata::Stats.new
|
159
163
|
|
@@ -180,23 +184,29 @@ module Fluent
|
|
180
184
|
|
181
185
|
# Use Kubernetes default service account if we're in a pod.
|
182
186
|
if @kubernetes_url.nil?
|
187
|
+
log.debug "Kubernetes URL is not set - inspecting environ"
|
188
|
+
|
183
189
|
env_host = ENV['KUBERNETES_SERVICE_HOST']
|
184
190
|
env_port = ENV['KUBERNETES_SERVICE_PORT']
|
185
191
|
if env_host.present? && env_port.present?
|
186
192
|
@kubernetes_url = "https://#{env_host}:#{env_port}/api"
|
193
|
+
log.debug "Kubernetes URL is now '#{@kubernetes_url}'"
|
187
194
|
end
|
188
195
|
end
|
189
196
|
|
190
197
|
# Use SSL certificate and bearer token from Kubernetes service account.
|
191
198
|
if Dir.exist?(@secret_dir)
|
199
|
+
log.debug "Found directory with secrets: #{@secret_dir}"
|
192
200
|
ca_cert = File.join(@secret_dir, K8_POD_CA_CERT)
|
193
201
|
pod_token = File.join(@secret_dir, K8_POD_TOKEN)
|
194
202
|
|
195
203
|
if !@ca_file.present? and File.exist?(ca_cert)
|
204
|
+
log.debug "Found CA certificate: #{ca_cert}"
|
196
205
|
@ca_file = ca_cert
|
197
206
|
end
|
198
207
|
|
199
208
|
if !@bearer_token_file.present? and File.exist?(pod_token)
|
209
|
+
log.debug "Found pod token: #{pod_token}"
|
200
210
|
@bearer_token_file = pod_token
|
201
211
|
end
|
202
212
|
end
|
@@ -217,6 +227,7 @@ module Fluent
|
|
217
227
|
auth_options[:bearer_token] = bearer_token
|
218
228
|
end
|
219
229
|
|
230
|
+
log.debug "Creating K8S client"
|
220
231
|
@client = Kubeclient::Client.new @kubernetes_url, @apiVersion,
|
221
232
|
ssl_options: ssl_options,
|
222
233
|
auth_options: auth_options
|
@@ -234,10 +245,15 @@ module Fluent
|
|
234
245
|
namespace_thread.abort_on_exception = true
|
235
246
|
end
|
236
247
|
end
|
237
|
-
@
|
238
|
-
|
239
|
-
|
240
|
-
|
248
|
+
if @use_journal
|
249
|
+
log.debug "Will stream from the journal"
|
250
|
+
@merge_json_log_key = 'MESSAGE'
|
251
|
+
self.class.class_eval { alias_method :filter_stream, :filter_stream_from_journal }
|
252
|
+
else
|
253
|
+
log.debug "Will stream from the files"
|
254
|
+
@merge_json_log_key = 'log'
|
255
|
+
self.class.class_eval { alias_method :filter_stream, :filter_stream_from_files }
|
256
|
+
end
|
241
257
|
|
242
258
|
@annotations_regexps = []
|
243
259
|
@annotation_match.each do |regexp|
|
@@ -250,93 +266,114 @@ module Fluent
|
|
250
266
|
|
251
267
|
end
|
252
268
|
|
253
|
-
def get_metadata_for_record(
|
269
|
+
def get_metadata_for_record(match_data, cache_key, create_time, batch_miss_cache)
|
270
|
+
namespace_name = match_data['namespace']
|
271
|
+
pod_name = match_data['pod_name']
|
254
272
|
metadata = {
|
255
|
-
'
|
256
|
-
'
|
257
|
-
|
258
|
-
'namespace_name' => namespace_name,
|
259
|
-
'pod_name' => pod_name
|
260
|
-
}
|
273
|
+
'container_name' => match_data['container_name'],
|
274
|
+
'namespace_name' => namespace_name,
|
275
|
+
'pod_name' => pod_name
|
261
276
|
}
|
262
277
|
if @kubernetes_url.present?
|
263
|
-
pod_metadata = get_pod_metadata(
|
278
|
+
pod_metadata = get_pod_metadata(cache_key, namespace_name, pod_name, create_time, batch_miss_cache)
|
279
|
+
metadata.merge!(pod_metadata) if pod_metadata
|
280
|
+
end
|
281
|
+
metadata
|
282
|
+
end
|
264
283
|
|
265
|
-
|
266
|
-
|
267
|
-
|
284
|
+
def create_time_from_record(record)
|
285
|
+
time = if @use_journal
|
286
|
+
record['_SOURCE_REALTIME_TIMESTAMP'].nil? ? record['_SOURCE_REALTIME_TIMESTAMP'] : record['__REALTIME_TIMESTAMP']
|
287
|
+
else
|
288
|
+
record['time']
|
268
289
|
end
|
290
|
+
(time.nil? || time.chop.empty?) ? Time.now : Time.parse(time)
|
291
|
+
end
|
269
292
|
|
270
|
-
|
271
|
-
|
272
|
-
end
|
273
|
-
metadata
|
293
|
+
def filter_stream(tag, es)
|
294
|
+
es
|
274
295
|
end
|
275
296
|
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
297
|
+
def filter_stream_from_files(tag, es)
|
298
|
+
new_es = Fluent::MultiEventStream.new
|
299
|
+
|
300
|
+
match_data = tag.match(@tag_to_kubernetes_name_regexp_compiled)
|
301
|
+
batch_miss_cache = {}
|
302
|
+
if match_data
|
303
|
+
container_id = match_data['docker_id']
|
304
|
+
metadata = {
|
305
|
+
'docker' => {
|
306
|
+
'container_id' => container_id
|
307
|
+
},
|
308
|
+
'kubernetes' => get_metadata_for_record(match_data, container_id, create_time_from_record(es.first[1]), batch_miss_cache)
|
309
|
+
}
|
285
310
|
end
|
286
|
-
|
311
|
+
|
312
|
+
es.each { |time, record|
|
313
|
+
record = merge_json_log(record) if @merge_json_log
|
314
|
+
|
315
|
+
record = record.merge(Marshal.load(Marshal.dump(metadata))) if metadata
|
316
|
+
|
317
|
+
new_es.add(time, record)
|
318
|
+
}
|
319
|
+
dump_stats
|
320
|
+
new_es
|
287
321
|
end
|
288
322
|
|
289
|
-
def
|
290
|
-
return es if (es.respond_to?(:empty?) && es.empty?) || !es.is_a?(Fluent::EventStream)
|
323
|
+
def filter_stream_from_journal(tag, es)
|
291
324
|
new_es = Fluent::MultiEventStream.new
|
292
|
-
tag_match_data = tag.match(@tag_to_kubernetes_name_regexp_compiled) unless @use_journal
|
293
|
-
tag_metadata = nil
|
294
325
|
batch_miss_cache = {}
|
295
|
-
es.each
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
326
|
+
es.each { |time, record|
|
327
|
+
record = merge_json_log(record) if @merge_json_log
|
328
|
+
metadata = nil
|
329
|
+
if record.has_key?('CONTAINER_NAME') && record.has_key?('CONTAINER_ID_FULL')
|
330
|
+
metadata = record['CONTAINER_NAME'].match(@container_name_to_kubernetes_regexp_compiled) do |match_data|
|
331
|
+
container_id = record['CONTAINER_ID_FULL']
|
332
|
+
metadata = {
|
333
|
+
'docker' => {
|
334
|
+
'container_id' => container_id
|
335
|
+
},
|
336
|
+
'kubernetes' => get_metadata_for_record(match_data, container_id, create_time_from_record(record), batch_miss_cache)
|
337
|
+
}
|
338
|
+
|
339
|
+
metadata
|
340
|
+
end
|
341
|
+
unless metadata
|
342
|
+
log.debug "Error: could not match CONTAINER_NAME from record #{record}"
|
343
|
+
@stats.bump(:container_name_match_failed)
|
344
|
+
end
|
345
|
+
elsif record.has_key?('CONTAINER_NAME') && record['CONTAINER_NAME'].start_with?('k8s_')
|
346
|
+
log.debug "Error: no container name and id in record #{record}"
|
347
|
+
@stats.bump(:container_name_id_missing)
|
304
348
|
end
|
305
|
-
|
306
|
-
|
307
|
-
record
|
308
|
-
record['kubernetes'].has_key?('pod_name') &&
|
309
|
-
record['kubernetes'].has_key?('container_name') &&
|
310
|
-
record['docker'].has_key?('container_id') &&
|
311
|
-
(k_metadata = get_metadata_for_record(record['kubernetes']['namespace_name'], record['kubernetes']['pod_name'],
|
312
|
-
record['kubernetes']['container_name'], record['docker']['container_id'],
|
313
|
-
create_time_from_record(record, time), batch_miss_cache))
|
314
|
-
metadata = k_metadata
|
349
|
+
|
350
|
+
if metadata
|
351
|
+
record = record.merge(metadata)
|
315
352
|
end
|
316
353
|
|
317
|
-
record = record.merge(metadata) if metadata
|
318
354
|
new_es.add(time, record)
|
319
|
-
|
355
|
+
}
|
356
|
+
|
320
357
|
dump_stats
|
321
358
|
new_es
|
322
359
|
end
|
323
360
|
|
324
|
-
def
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
record
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
334
374
|
end
|
335
|
-
elsif record.has_key?('CONTAINER_NAME') && record['CONTAINER_NAME'].start_with?('k8s_')
|
336
|
-
log.debug "Error: no container name and id in record #{record}"
|
337
|
-
@stats.bump(:container_name_id_missing)
|
338
375
|
end
|
339
|
-
|
376
|
+
record
|
340
377
|
end
|
341
378
|
|
342
379
|
def de_dot!(h)
|