fluent-plugin-kubernetes-metrics 1.1.7 → 1.1.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7953f3fade3d0c126f70d9b6922d6b36eccb92461903a723975eb5cb29ee958
4
- data.tar.gz: ceb8d47bbb69b1de2bfafa6c9c05cf8f5ad2909db2d432c7eed78721f6c985f5
3
+ metadata.gz: 7cba1f817de8b2ebcb68a6f96dcb0776105c9330ed7b7e6d46888bd1fe2a8290
4
+ data.tar.gz: 79b5be5e27f54edad68981e9f48f8827fe698c93584115287ea41b594591e928
5
5
  SHA512:
6
- metadata.gz: 5a310b0ac5c2f1af6cdb34c9c74413dc6b1e4bef7a42f996dc6741a512a80f1fc1822302c313f57ef6772f0a6416b61b64188fe75ff1a3c2a3cee9a969c13828
7
- data.tar.gz: 63dec59922164f39a20eb8ed51bb4f11d464811544eee28b591bf9eba79a7b29f29c3ffb80a89496f7abe433a0fd8b5872f8fe7d841e7bff5f6919a438977b45
6
+ metadata.gz: 4d4fd43d51357507698126408a618d38e81d7a5a9a956a3aafe4c46521b9d95bf22d680c52fca119d9c3f236b60dcdf028368948cc258981a64e34cd0f1e4ce8
7
+ data.tar.gz: 03ff9d6abf9511af983f52c1083062bc389fd976e0baf3045609df3a81e833e8ae2c787c5078870921a76246c37f3f2e01c3e20270ba0e0ca502aaa7105d8011
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fluent-plugin-kubernetes-metrics (1.1.7)
4
+ fluent-plugin-kubernetes-metrics (1.1.10)
5
5
  fluentd (>= 1.9.1)
6
6
  kubeclient (~> 4.6.0)
7
7
  multi_json (~> 1.14.1)
@@ -19,14 +19,14 @@ GEM
19
19
  docile (1.4.0)
20
20
  domain_name (0.5.20190701)
21
21
  unf (>= 0.0.5, < 1.0.0)
22
- ffi (1.15.4)
22
+ ffi (1.15.5)
23
23
  ffi-compiler (1.0.1)
24
24
  ffi (>= 1.0.0)
25
25
  rake
26
- fluentd (1.14.2)
26
+ fluentd (1.14.4)
27
27
  bundler
28
28
  cool.io (>= 1.4.5, < 2.0.0)
29
- http_parser.rb (>= 0.5.1, < 0.8.0)
29
+ http_parser.rb (>= 0.5.1, < 0.9.0)
30
30
  msgpack (>= 1.3.1, < 2.0.0)
31
31
  serverengine (>= 2.2.2, < 3.0.0)
32
32
  sigdump (~> 0.2.2)
@@ -47,16 +47,16 @@ GEM
47
47
  http-form_data (2.3.0)
48
48
  http-parser (1.2.3)
49
49
  ffi-compiler (>= 1.0, < 2.0)
50
- http_parser.rb (0.7.0)
50
+ http_parser.rb (0.8.0)
51
51
  json (2.6.1)
52
52
  kubeclient (4.6.0)
53
53
  http (>= 3.0, < 5.0)
54
54
  recursive-open-struct (~> 1.0, >= 1.0.4)
55
55
  rest-client (~> 2.0)
56
- mime-types (3.3.1)
56
+ mime-types (3.4.1)
57
57
  mime-types-data (~> 3.2015)
58
- mime-types-data (3.2021.0901)
59
- msgpack (1.4.2)
58
+ mime-types-data (3.2022.0105)
59
+ msgpack (1.4.4)
60
60
  multi_json (1.14.1)
61
61
  netrc (0.11.0)
62
62
  oj (3.10.18)
@@ -70,7 +70,7 @@ GEM
70
70
  mime-types (>= 1.16, < 4.0)
71
71
  netrc (~> 0.8)
72
72
  rexml (3.2.5)
73
- serverengine (2.2.4)
73
+ serverengine (2.2.5)
74
74
  sigdump (~> 0.2.2)
75
75
  sigdump (0.2.4)
76
76
  simplecov (0.16.1)
@@ -107,4 +107,4 @@ DEPENDENCIES
107
107
  webmock (~> 3.5.1)
108
108
 
109
109
  BUNDLED WITH
110
- 2.2.30
110
+ 2.3.9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.7
1
+ 1.1.10
@@ -90,8 +90,13 @@ module Fluent
90
90
  super
91
91
 
92
92
  timer_execute :metric_scraper, @interval, &method(:scrape_metrics)
93
- timer_execute :stats_metric_scraper, @interval, &method(:scrape_stats_metrics)
94
93
  timer_execute :cadvisor_metric_scraper, @interval, &method(:scrape_cadvisor_metrics)
94
+ # It is done to optionally fetch from 'stats' for k8s version <1.21
95
+ if is_stats_endpoint_available?
96
+ timer_execute :stats_metric_scraper, @interval, &method(:scrape_stats_metrics)
97
+ else
98
+ log.info "'/stats' endpoint is not available. It has been deprecated since k8s v1.15, disabled since v1.18, and removed in v1.21 and onwards"
99
+ end
95
100
  end
96
101
 
97
102
  def close
@@ -310,7 +315,7 @@ module Fluent
310
315
  unless metrics['time'].nil?
311
316
  time = parse_time metrics['time']
312
317
  if usage_rate = metrics['usageNanoCores']
313
- router.emit generate_tag("#{tag}.cpu.usage_rate"), time, labels.merge('value' => usage_rate / 1_000_000)
318
+ router.emit generate_tag("#{tag}.cpu.usage_rate"), time, labels.merge('value' => usage_rate / 1_000_000.0)
314
319
  end
315
320
  if usage = metrics['usageNanoCores']
316
321
  router.emit generate_tag("#{tag}.cpu.usage"), time, labels.merge('value' => usage)
@@ -411,13 +416,13 @@ module Fluent
411
416
 
412
417
  def emit_cpu_metrics_stats(tag:, metrics:, labels:, time:)
413
418
  if cpu_usage_total = metrics['usage']['total']
414
- router.emit generate_tag("#{tag}.cpu.usage.total"), time, labels.merge('value' => cpu_usage_total / 1_000_000)
419
+ router.emit generate_tag("#{tag}.cpu.usage.total"), time, labels.merge('value' => cpu_usage_total / 1_000_000.0)
415
420
  end
416
421
  if cpu_usage_user = metrics['usage']['user']
417
- router.emit generate_tag("#{tag}.cpu.usage.user"), time, labels.merge('value' => cpu_usage_user / 1_000_000)
422
+ router.emit generate_tag("#{tag}.cpu.usage.user"), time, labels.merge('value' => cpu_usage_user / 1_000_000.0)
418
423
  end
419
424
  if cpu_usage_system = metrics['usage']['system']
420
- router.emit generate_tag("#{tag}.cpu.usage.system"), time, labels.merge('value' => cpu_usage_system / 1_000_000)
425
+ router.emit generate_tag("#{tag}.cpu.usage.system"), time, labels.merge('value' => cpu_usage_system / 1_000_000.0)
421
426
  end
422
427
 
423
428
  if cpu_cfs_periods = metrics['cfs']['periods']
@@ -571,8 +576,42 @@ module Fluent
571
576
 
572
577
  unless pod['startTime'].nil?
573
578
  emit_uptime tag: tag, start_time: pod['startTime'], labels: labels
574
- emit_cpu_metrics tag: tag, metrics: pod['cpu'], labels: labels if pod['cpu'] unless pod['cpu'].nil?
575
- emit_memory_metrics tag: tag, metrics: pod['memory'], labels: labels if pod['memory'] unless pod['memory'].nil?
579
+ if pod['cpu'].nil?
580
+ if pod['containers'].nil? or Array(pod['containers']).empty?
581
+ log.warn "Summary API response has no pod cpu metrics information"
582
+ else
583
+ usageNanoCores = 0
584
+ usageCoreNanoSeconds = 0
585
+ time = nil
586
+ Array(pod['containers']).each do |container|
587
+ time = container['time'] unless container['time'].nil?
588
+ usageNanoCores += container['usageNanoCores']
589
+ usageCoreNanoSeconds += container['usageCoreNanoSeconds']
590
+ end
591
+ pod['cpu'] = { 'time' => time, 'usageNanoCores' => usageNanoCores, 'usageCoreNanoSeconds' => usageCoreNanoSeconds }
592
+ end
593
+ end
594
+ emit_cpu_metrics tag: tag, metrics: pod['cpu'], labels: labels unless pod['cpu'].nil?
595
+ if pod['memory'].nil?
596
+ if pod['containers'].nil? or Array(pod['containers']).empty?
597
+ log.warn "Summary API response has no pod memory metrics information"
598
+ else
599
+ Array(pod['containers']).each do |container|
600
+ time = nil
601
+ memory_metrics = {}
602
+ %w[availableBytes usageBytes workingSetBytes rssBytes pageFaults majorPageFaults].each do |name|
603
+ time = container['time'] unless container['time'].nil?
604
+ if value = metrics[name]
605
+ memory_metrics[name] = 0 if memory_metrics[name].nil?
606
+ memory_metrics[name] += value
607
+ end
608
+ end
609
+ end
610
+ memory_metrics['time'] = time
611
+ pod['memory'] = memory_metrics
612
+ end
613
+ end
614
+ emit_memory_metrics tag: tag, metrics: pod['memory'], labels: labels unless pod['memory'].nil?
576
615
  emit_network_metrics tag: tag, metrics: pod['network'], labels: labels unless pod['network'].nil?
577
616
  emit_fs_metrics tag: "#{tag}.ephemeral-storage", metrics: pod['ephemeral-storage'], labels: labels unless pod['ephemeral-storage'].nil?
578
617
  unless pod['volume'].nil?
@@ -590,6 +629,7 @@ module Fluent
590
629
 
591
630
  def emit_metrics(metrics)
592
631
  emit_node_metrics(metrics['node']) unless metrics['node'].nil?
632
+ log.warn "Summary API received empty pods info" if (metrics['pods'].nil? or metrics['pods'].empty?)
593
633
  Array(metrics['pods']).each &method(:emit_pod_metrics).curry.call(metrics['node']['nodeName']) unless metrics['pods'].nil?
594
634
  end
595
635
 
@@ -597,33 +637,35 @@ module Fluent
597
637
  emit_stats_breakdown(metrics['stats']) unless metrics['stats'].nil?
598
638
  end
599
639
 
640
+ # Make sure regex has only one capturing group
641
+ def grep_using_regex(metric, regex)
642
+ match = metric.match(regex)
643
+ return nil if match.nil?
644
+ match[1]
645
+ end
646
+
600
647
  def emit_cadvisor_metrics(metrics)
601
648
  metrics = metrics.split("\n")
602
649
  metrics.each do |metric|
603
- next unless metric.include? 'container_name='
604
-
605
- next unless metric.match(/^((?!container_name="").)*$/) && metric[0] != '#'
606
-
650
+
651
+ next if metric[0] == '#' or not container_name = grep_using_regex(metric, /container(?:_name)?="([^"]*)"/)
652
+ next if container_name.empty?
653
+
607
654
  metric_str, metric_val = metric.split(' ')
608
655
  metric_val = metric_val.to_f if metric_val.is_a? String
609
656
  first_occur = metric_str.index('{')
610
657
  metric_name = metric_str[0..first_occur - 1]
611
- pod_name = metric.match(/pod_name="\S*"/).to_s
612
- pod_name = pod_name.split('"')[1]
613
- image_name = metric.match(/image="\S*"/).to_s
614
- image_name = image_name.split('"')[1]
615
- namespace = metric.match(/namespace="\S*"/).to_s
616
- namespace = namespace.split('"')[1]
658
+ pod_name = grep_using_regex(metric, /pod(?:_name)?="([^"]*)"/).to_s
659
+ image_name = grep_using_regex(metric, /image="([^"]*)"/).to_s
660
+ namespace = grep_using_regex(metric, /namespace="([^"]*)"/).to_s
617
661
  metric_labels = { 'pod_name' => pod_name, 'image' => image_name, 'namespace' => namespace, 'value' => metric_val, 'node' => @node_name }
618
- if metric =~ /^((?!container_name="POD").)*$/
662
+ if container_name=="POD"
619
663
  tag = 'pod'
620
664
  tag = generate_tag("#{tag}#{metric_name.tr('_', '.')}")
621
665
  tag = tag.gsub('container', '')
622
666
  else
623
- container_name = metric.match(/container_name="\S*"/).to_s
624
- container_name = container_name.split('"')[1]
625
667
  container_label = { 'container_name' => container_name }
626
- metric_labels.merge(container_label)
668
+ metric_labels.merge!(container_label)
627
669
  tag = generate_tag(metric_name.tr('_', '.').to_s)
628
670
  end
629
671
  router.emit tag, @scraped_at_cadvisor, metric_labels
@@ -642,6 +684,20 @@ module Fluent
642
684
  end
643
685
  end
644
686
 
687
+ def is_stats_endpoint_available?
688
+ if @use_rest_client
689
+ response_stats = RestClient::Request.execute request_options_stats
690
+ else
691
+ @node_names.each do |node|
692
+ @node_name = node
693
+ response_stats = stats_proxy_api(node).get(@client.headers)
694
+ end
695
+ end
696
+ true
697
+ rescue RestClient::NotFound
698
+ false
699
+ end
700
+
645
701
  def scrape_stats_metrics
646
702
  if @use_rest_client
647
703
  response_stats = RestClient::Request.execute request_options_stats
@@ -35,6 +35,9 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
35
35
  ).freeze
36
36
 
37
37
  setup do
38
+ stub_k8s_requests
39
+
40
+ return unless @@hash_map_test.empty?
38
41
  Fluent::Test.setup
39
42
 
40
43
  @@parsed_unit_string = JSON.parse(get_unit_parsed_string)
@@ -45,8 +48,6 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
45
48
  get_cadvisor_parsed_string = f.read
46
49
  end.close
47
50
 
48
- stub_k8s_requests
49
-
50
51
  @@ca_driver = create_driver
51
52
  @@ca_driver.run timeout: 20, expect_emits: 1, shutdown: true
52
53
 
@@ -56,8 +57,12 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
56
57
  metrics = get_cadvisor_parsed_string.split("\n")
57
58
  metrics.each do |metric|
58
59
  next unless metric.include? 'container_name='
60
+ next unless metric[0] != '#'
59
61
 
60
- next unless metric.match(/^((?!container_name="").)*$/) && metric[0] != '#'
62
+ container_name = metric.match(/container_name="\S*"/).to_s
63
+ container_name = container_name.split('"')[1]
64
+
65
+ next if container_name.empty?
61
66
 
62
67
  metric_str, metric_val = metric.split(' ')
63
68
  metric_val = metric_val.to_f if metric_val.is_a? String
@@ -70,13 +75,11 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
70
75
  namespace = metric.match(/namespace="\S*"/).to_s
71
76
  namespace = namespace.split('"')[1]
72
77
  metric_labels = { 'pod_name' => pod_name, 'image' => image_name, 'namespace' => namespace, 'value' => metric_val, 'node' => @node_name }
73
- if metric =~ /^((?!container_name="POD").)*$/
78
+ if container_name == 'POD'
74
79
  tag = 'pod'
75
80
  tag = generate_tag("#{tag}#{metric_name.tr('_', '.')}", @@driver.instance.tag)
76
81
  tag = tag.gsub('container', '')
77
82
  else
78
- container_name = metric.match(/container_name="\S*"/).to_s
79
- container_name = container_name.split('"')[1]
80
83
  container_label = { 'container_name' => container_name }
81
84
  metric_labels.merge(container_label)
82
85
  tag = generate_tag(metric_name.tr('_', '.').to_s, @@driver.instance.tag)
@@ -112,7 +115,7 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
112
115
  assert_equal @@parsed_unit_string['node']['cpu']['usageNanoCores'], @@hash_map_test['kube.node.cpu.usage'][2]['value']
113
116
 
114
117
  assert_not_nil @@hash_map_test.key?('kube.node.cpu.usage_rate')
115
- assert_equal @@parsed_unit_string['node']['cpu']['usageNanoCores'] / 1_000_000, @@hash_map_test['kube.node.cpu.usage_rate'][2]['value']
118
+ assert_equal @@parsed_unit_string['node']['cpu']['usageNanoCores'] / 1_000_000.0, @@hash_map_test['kube.node.cpu.usage_rate'][2]['value']
116
119
  end
117
120
 
118
121
  test 'test_emit_memory_metrics' do
@@ -252,11 +255,10 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
252
255
  assert_true @@hash_map_cadvisor.key?('kube.container.fs.read.seconds.total')
253
256
  assert_equal @@hash_map_cadvisor['kube.container.fs.read.seconds.total'], @@hash_map_test['kube.container.fs.read.seconds.total'][2]['value']
254
257
  end
255
-
256
- # TODO: Current Test does not work - metric present in metrics_cadvisor.txt but not being parsed by connector in test/working in production
258
+
257
259
  test 'Test - metrics cadvisor: container_fs_reads_bytes_total' do
258
- assert_false @@hash_map_cadvisor.key?('kube.container.fs.reads.bytes.total')
259
- # assert_equal @@hash_map_cadvisor['kube.container.fs.reads.bytes.total'], @@hash_map_test["kube.container.fs.reads.bytes.total"][2]["value"]
260
+ assert_true @@hash_map_cadvisor.key?('kube.container.fs.reads.bytes.total')
261
+ assert_equal @@hash_map_cadvisor['kube.container.fs.reads.bytes.total'], @@hash_map_test["kube.container.fs.reads.bytes.total"][2]["value"]
260
262
  end
261
263
 
262
264
  test 'Test - metrics cadvisor: container_fs_reads_merged_total' do
@@ -289,10 +291,9 @@ class KubernetesMetricsInputTest < Test::Unit::TestCase
289
291
  assert_equal @@hash_map_cadvisor['kube.container.fs.write.seconds.total'], @@hash_map_test['kube.container.fs.write.seconds.total'][2]['value']
290
292
  end
291
293
 
292
- # TODO: Current Test does not work - metric present in metrics_cadvisor.txt but not being parsed by connector in test/working in production
293
294
  test 'Test - metrics cadvisor: container_fs_writes_bytes_total' do
294
- assert_false @@hash_map_cadvisor.key?('kube.container.fs.writes.bytes.total')
295
- # assert_equal @@hash_map_cadvisor['kube.container.fs.writes.bytes.total'], @@hash_map_test["kube.container.fs.writes.bytes.total"][2]["value"]
295
+ assert_true @@hash_map_cadvisor.key?('kube.container.fs.writes.bytes.total')
296
+ assert_equal @@hash_map_cadvisor['kube.container.fs.writes.bytes.total'], @@hash_map_test["kube.container.fs.writes.bytes.total"][2]["value"]
296
297
  end
297
298
 
298
299
  test 'Test - metrics cadvisor: container_fs_writes_merged_total' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-kubernetes-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.7
4
+ version: 1.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Splunk Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-04 00:00:00.000000000 Z
11
+ date: 2022-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -180,6 +180,6 @@ signing_key:
180
180
  specification_version: 4
181
181
  summary: A fluentd input plugin that collects kubernetes cluster metrics.
182
182
  test_files:
183
- - test/plugin/test_missing_timestamps.rb
184
- - test/plugin/test_in_kubernetes_metrics.rb
185
183
  - test/helper.rb
184
+ - test/plugin/test_in_kubernetes_metrics.rb
185
+ - test/plugin/test_missing_timestamps.rb