fluent-plugin-node-exporter-metrics 0.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.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/linux-test.yaml +42 -0
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +6 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +202 -0
  7. data/README.md +167 -0
  8. data/Rakefile +13 -0
  9. data/docs/cpu.md +26 -0
  10. data/docs/cpufreq.md +43 -0
  11. data/docs/diskstats.md +27 -0
  12. data/docs/filefd.md +12 -0
  13. data/docs/loadavg.md +13 -0
  14. data/docs/meminfo.md +61 -0
  15. data/docs/netdev.md +26 -0
  16. data/docs/stat.md +17 -0
  17. data/docs/time.md +9 -0
  18. data/docs/uname.md +15 -0
  19. data/docs/vmstat.md +17 -0
  20. data/fluent-plugin-node-exporter-metrics.gemspec +31 -0
  21. data/lib/fluent/plugin/in_node_exporter_metrics.rb +138 -0
  22. data/lib/fluent/plugin/node_exporter/cmetrics_dataschema_parser.rb +84 -0
  23. data/lib/fluent/plugin/node_exporter/collector.rb +41 -0
  24. data/lib/fluent/plugin/node_exporter/cpu_collector.rb +130 -0
  25. data/lib/fluent/plugin/node_exporter/cpufreq_collector.rb +97 -0
  26. data/lib/fluent/plugin/node_exporter/diskstats_collector.rb +280 -0
  27. data/lib/fluent/plugin/node_exporter/filefd_collector.rb +60 -0
  28. data/lib/fluent/plugin/node_exporter/loadavg_collector.rb +64 -0
  29. data/lib/fluent/plugin/node_exporter/meminfo_collector.rb +61 -0
  30. data/lib/fluent/plugin/node_exporter/netdev_collector.rb +92 -0
  31. data/lib/fluent/plugin/node_exporter/stat_collector.rb +84 -0
  32. data/lib/fluent/plugin/node_exporter/time_collector.rb +50 -0
  33. data/lib/fluent/plugin/node_exporter/uname_collector.rb +64 -0
  34. data/lib/fluent/plugin/node_exporter/vmstat_collector.rb +56 -0
  35. data/lib/fluent/plugin/parser_node_exporter_metrics.rb +54 -0
  36. data/test/fixtures/cpu/with_thermal_throttle/proc/stat +3 -0
  37. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu0/thermal_throttle/core_throttle_count +1 -0
  38. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu0/thermal_throttle/package_throttle_count +1 -0
  39. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu0/topology/core_id +1 -0
  40. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu0/topology/physical_package_id +1 -0
  41. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu1/thermal_throttle/core_throttle_count +1 -0
  42. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu1/thermal_throttle/package_throttle_count +1 -0
  43. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu1/topology/core_id +1 -0
  44. data/test/fixtures/cpu/with_thermal_throttle/sys/devices/system/cpu/cpu1/topology/physical_package_id +1 -0
  45. data/test/fixtures/cpu/without_thermal_throttle/proc/stat +3 -0
  46. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq +1 -0
  47. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq +1 -0
  48. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq +1 -0
  49. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq +1 -0
  50. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq +1 -0
  51. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq +1 -0
  52. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq +1 -0
  53. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq +1 -0
  54. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq +1 -0
  55. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq +1 -0
  56. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq +1 -0
  57. data/test/fixtures/cpufreq/with_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq +1 -0
  58. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq +1 -0
  59. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq +1 -0
  60. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq +1 -0
  61. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq +1 -0
  62. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq +1 -0
  63. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq +1 -0
  64. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_min_freq +1 -0
  65. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq +1 -0
  66. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq +1 -0
  67. data/test/fixtures/cpufreq/without_cur_freq/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq +1 -0
  68. data/test/helper.rb +24 -0
  69. data/test/plugin/test_cmetrics_data_schema_parser.rb +83 -0
  70. data/test/plugin/test_cpu_collector.rb +84 -0
  71. data/test/plugin/test_cpufreq_collector.rb +75 -0
  72. data/test/plugin/test_diskstats_collector.rb +200 -0
  73. data/test/plugin/test_filefd_collector.rb +39 -0
  74. data/test/plugin/test_in_node_exporter_metrics.rb +583 -0
  75. data/test/plugin/test_loadavg_collector.rb +41 -0
  76. data/test/plugin/test_meminfo_collector.rb +47 -0
  77. data/test/plugin/test_netdev_collector.rb +35 -0
  78. data/test/plugin/test_stat_collector.rb +37 -0
  79. data/test/plugin/test_time_collector.rb +15 -0
  80. data/test/plugin/test_uname_collector.rb +47 -0
  81. data/test/plugin/test_vmstat_collector.rb +53 -0
  82. metadata +273 -0
@@ -0,0 +1,583 @@
1
+ require "helper"
2
+ require "fluent/plugin/in_node_exporter_metrics.rb"
3
+
4
+ class NodeExporterMetricsInputTest < Test::Unit::TestCase
5
+ setup do
6
+ Fluent::Test.setup
7
+ @capability = Fluent::Capability.new(:current_process)
8
+ end
9
+
10
+ teardown do
11
+ Fluent::Engine.stop
12
+ end
13
+
14
+ CONFIG = config_element("ROOT", "", {
15
+ "scrape_interval" => 5,
16
+ "procfs_path" => "/proc",
17
+ "sysfs_path" => "/sys",
18
+ "cpufreq" => false # assume linux capability is not set by default environment
19
+ })
20
+
21
+ ALL_COLLECTOR_NAMES = %w(cpu cpufreq diskstats filefd loadavg meminfo netdev stat time uname vmstat)
22
+
23
+ def create_driver(conf = CONFIG)
24
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::NodeExporterMetricsInput).configure(conf)
25
+ end
26
+
27
+ def create_minimum_config_params
28
+ params = {"scrape_interval" => 1}
29
+ ALL_COLLECTOR_NAMES.each do |field|
30
+ params[field] = false
31
+ end
32
+ params
33
+ end
34
+
35
+ def cpufreq_readable?
36
+ freq_path = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq"
37
+ Dir.exist?("/sys/devices/system/cpu/cpu0/cpufreq") and
38
+ File.exist?(freq_path) and
39
+ (File.readable?(freq_path) or cpufreq_capability?)
40
+ end
41
+
42
+ def cpufreq_capability?
43
+ @capability.have_capability?(:effective, :dac_read_search)
44
+ end
45
+
46
+ sub_test_case "configure" do
47
+ def test_default_parameters
48
+ d = create_driver(CONFIG)
49
+ assert_equal([5, "/proc", "/sys"],
50
+ [d.instance.scrape_interval, d.instance.procfs_path, d.instance.sysfs_path])
51
+ end
52
+
53
+ def test_empty_collectors
54
+ params = {}
55
+ %w(cpu cpufreq diskstats filefd loadavg meminfo netdev stat time uname vmstat).each do |collector|
56
+ params[collector] = false
57
+ end
58
+ assert_raise(Fluent::ConfigError.new("all collectors are disabled. Enable at least one collector.")) do
59
+ create_driver(config_element("ROOT", "", params))
60
+ end
61
+ end
62
+
63
+ def test_default_collectors_with_capability
64
+ omit "skip assertion when linux capability is not available" unless cpufreq_readable?
65
+ d = create_driver(config_element("ROOT", "", {}))
66
+ assert_equal([true] * 11,
67
+ [d.instance.cpu,
68
+ d.instance.cpufreq,
69
+ d.instance.diskstats,
70
+ d.instance.filefd,
71
+ d.instance.loadavg,
72
+ d.instance.meminfo,
73
+ d.instance.netdev,
74
+ d.instance.stat,
75
+ d.instance.time,
76
+ d.instance.uname,
77
+ d.instance.vmstat])
78
+ end
79
+
80
+ def test_customizable
81
+ d = create_driver(config_element("ROOT", "", {
82
+ "scrape_interval" => 10,
83
+ "procfs_path" => "/proc/dummy",
84
+ "sysfs_path" => "/sys/dummy",
85
+ "cpu" => "true",
86
+ "cpufreq" => "false",
87
+ "diskstats" => "false",
88
+ "filefd" => "false",
89
+ "loadavg" => "false",
90
+ "meminfo" => "false",
91
+ "netdev" => "false",
92
+ "stat" => "false",
93
+ "time" => "false",
94
+ "uname" => "false",
95
+ "vmstat" => "false"
96
+ }))
97
+ assert_equal([10.0, "/proc/dummy", "/sys/dummy", true, false, false, false, false, false, false, false, false, false, false],
98
+ [d.instance.scrape_interval,
99
+ d.instance.procfs_path,
100
+ d.instance.sysfs_path,
101
+ d.instance.cpu,
102
+ d.instance.cpufreq,
103
+ d.instance.diskstats,
104
+ d.instance.filefd,
105
+ d.instance.loadavg,
106
+ d.instance.meminfo,
107
+ d.instance.netdev,
108
+ d.instance.stat,
109
+ d.instance.time,
110
+ d.instance.uname,
111
+ d.instance.vmstat])
112
+ end
113
+
114
+ sub_test_case "scrape interval" do
115
+ def test_shorter_interval
116
+ d = create_driver(config_element("ROOT", "", { "scrape_interval" => 2 , "cpufreq" => false}))
117
+ d.run(expect_records: 2, timeout: 5)
118
+ assert_equal(2, d.events.size)
119
+ end
120
+
121
+ def test_longer_interval
122
+ d = create_driver(config_element("ROOT", "", { "scrape_interval" => 10, "cpufreq" => false}))
123
+ d.run(expect_records: 1, timeout: 10)
124
+ assert_equal(1, d.events.size)
125
+ end
126
+ end
127
+ end
128
+
129
+ sub_test_case "capability" do
130
+ def test_no_capability_error
131
+ unless @capability.have_capability?(:effective, :dac_read_search)
132
+ assert_raise(Fluent::ConfigError.new("Linux capability CAP_DAC_READ_SEARCH must be enabled")) do
133
+ d = create_driver(config_element("ROOT", "", {}))
134
+ d.run
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ sub_test_case "collectors" do
141
+ sub_test_case "cpu collector" do
142
+ def test_cpu_with_thermal_throttle
143
+ omit "thermal throttle requires specific sysfs" unless Dir.exist?("/sys/devices/system/cpu/cpu0/thermal_throttle")
144
+
145
+ params = create_minimum_config_params
146
+ params["cpu"] = true
147
+ d = create_driver(config_element("ROOT", "", params))
148
+ d.run(expect_records: 1, timeout: 2)
149
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
150
+ # FIXME: size of core_throttles_total, package_throttles_total values
151
+ assert_equal([
152
+ 4,
153
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"core_throttles_total","desc"=>"Number of times this CPU core has been throttled."},
154
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"package_throttles_total", "desc"=>"Number of times this CPU package has been throttled."},
155
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"seconds_total", "desc"=>"Seconds the CPUs spent in each mode."},
156
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"guest_seconds_total","desc"=>"Seconds the CPUs spent in guests (VMs) for each mode."},
157
+ Etc.nprocessors * ["idle", "iowait", "irq", "nice", "softirq", "steal", "system", "user"].size,
158
+ Etc.nprocessors * ["user", "nice"].size,
159
+ ],
160
+ [
161
+ cmetrics.size,
162
+ cmetrics.collect do |metric|
163
+ metric["meta"]["opts"]
164
+ end,
165
+ cmetrics[2]["values"].size,
166
+ cmetrics[3]["values"].size
167
+ ].flatten)
168
+ end
169
+
170
+ def test_cpu_without_thermal_throttle
171
+ omit "thermal throttle requires specific sysfs" if Dir.exist?("/sys/devices/system/cpu/cpu0/thermal_throttle")
172
+
173
+ params = create_minimum_config_params
174
+ params["cpu"] = true
175
+ d = create_driver(config_element("ROOT", "", params))
176
+ d.run(expect_records: 1, timeout: 2)
177
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
178
+ assert_equal([
179
+ 2,
180
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"seconds_total", "desc"=>"Seconds the CPUs spent in each mode."},
181
+ Etc.nprocessors * ["idle", "iowait", "irq", "nice", "softirq", "steal", "system", "user"].size,
182
+ {"ns"=>"node", "ss"=>"cpu", "name"=>"guest_seconds_total", "desc"=>"Seconds the CPUs spent in guests (VMs) for each mode."},
183
+ Etc.nprocessors * ["nice", "user"].size,
184
+ ],
185
+ [
186
+ cmetrics.size,
187
+ cmetrics.first["meta"]["opts"],
188
+ cmetrics.first["values"].size,
189
+ cmetrics.last["meta"]["opts"],
190
+ cmetrics.last["values"].size
191
+ ])
192
+ end
193
+ end
194
+
195
+ sub_test_case "cpufreq collector" do
196
+ def test_cpufreq
197
+ omit "cpufreq collector requires linux capability" unless cpufreq_readable?
198
+ params = create_minimum_config_params
199
+ params["cpufreq"] = true
200
+ d = create_driver(config_element("ROOT", "", params))
201
+ d.run(expect_records: 1, timeout: 2)
202
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
203
+ value_counts = if File.exist?("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq")
204
+ [Etc.nprocessors] * 6
205
+ else
206
+ [0, [Etc.nprocessors] * 5].flatten
207
+ end
208
+ assert_equal([
209
+ 6,
210
+ {"desc"=>"Current cpu thread frequency in hertz.",
211
+ "name"=>"frequency_hertz",
212
+ "ns"=>"node",
213
+ "ss"=>"cpu"},
214
+ {"desc"=>"Maximum cpu thread frequency in hertz.",
215
+ "name"=>"frequency_max_hertz",
216
+ "ns"=>"node",
217
+ "ss"=>"cpu"},
218
+ {"desc"=>"Minimum cpu thread frequency in hertz.",
219
+ "name"=>"frequency_min_hertz",
220
+ "ns"=>"node",
221
+ "ss"=>"cpu"},
222
+ {"desc"=>"Current scaled CPU thread frequency in hertz.",
223
+ "name"=>"scaling_frequency_hertz",
224
+ "ns"=>"node",
225
+ "ss"=>"cpu"},
226
+ {"desc"=>"Maximum scaled CPU thread frequency in hertz.",
227
+ "name"=>"scaling_frequency_max_hertz",
228
+ "ns"=>"node",
229
+ "ss"=>"cpu"},
230
+ {"desc"=>"Minimum scaled CPU thread frequency in hertz.",
231
+ "name"=>"scaling_frequency_min_hertz",
232
+ "ns"=>"node",
233
+ "ss"=>"cpu"},
234
+ value_counts
235
+ ].flatten,
236
+ [
237
+ cmetrics.size,
238
+ cmetrics.collect do |cmetric|
239
+ cmetric["meta"]["opts"]
240
+ end,
241
+ cmetrics.collect do |cmetric|
242
+ cmetric["values"].size
243
+ end,
244
+ ].flatten)
245
+ end
246
+
247
+ def test_without_capability
248
+ omit "skip assertion if linux capability is enabled" if cpufreq_capability?
249
+ assert_raise(Fluent::ConfigError.new("Linux capability CAP_DAC_READ_SEARCH must be enabled")) do
250
+ params = create_minimum_config_params
251
+ params["cpufreq"] = true
252
+ create_driver(config_element("ROOT", "", params))
253
+ end
254
+ end
255
+ end
256
+
257
+ sub_test_case "diskstats collector" do
258
+ def test_diskstats
259
+ params = create_minimum_config_params
260
+ params["diskstats"] = true
261
+ d = create_driver(config_element("ROOT", "", params))
262
+ d.run(expect_records: 1, timeout: 2)
263
+ c = Fluent::Plugin::NodeExporter::DiskstatsMetricsCollector.new
264
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
265
+ assert_equal([
266
+ true,
267
+ ],
268
+ [
269
+ cmetrics.all? { |cmetric| cmetric["values"].size == c.target_devices.size }
270
+ ])
271
+ end
272
+ end
273
+
274
+ sub_test_case "filefd collector" do
275
+ def test_filefd
276
+ params = create_minimum_config_params
277
+ params["filefd"] = true
278
+ d = create_driver(config_element("ROOT", "", params))
279
+ d.run(expect_records: 1, timeout: 2)
280
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
281
+ assert_equal([
282
+ 2,
283
+ {"ns"=>"node", "ss"=>"filefd", "name"=>"allocated", "desc"=>"File descriptor statistics: allocated."},
284
+ 1,
285
+ {"ns"=>"node", "ss"=>"filefd", "name"=>"maximum", "desc"=>"File descriptor statistics: maximum."},
286
+ 1
287
+ ],
288
+ [
289
+ cmetrics.size,
290
+ cmetrics.first["meta"]["opts"],
291
+ cmetrics.first["values"].size,
292
+ cmetrics.last["meta"]["opts"],
293
+ cmetrics.last["values"].size
294
+ ])
295
+ end
296
+ end
297
+
298
+ sub_test_case "loadavg collector" do
299
+ def test_loadavg
300
+ params = create_minimum_config_params
301
+ params["loadavg"] = true
302
+ d = create_driver(config_element("ROOT", "", params))
303
+ d.run(expect_records: 1, timeout: 2)
304
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
305
+ assert_equal([
306
+ 3,
307
+ {"ns"=>"node", "ss"=>"", "name"=>"load1", "desc"=>"1m load average."},
308
+ {"ns"=>"node", "ss"=>"", "name"=>"load5", "desc"=>"5m load average."},
309
+ {"ns"=>"node", "ss"=>"", "name"=>"load15", "desc"=>"15m load average."},
310
+ ],
311
+ [
312
+ cmetrics.size,
313
+ cmetrics[0]["meta"]["opts"],
314
+ cmetrics[1]["meta"]["opts"],
315
+ cmetrics[2]["meta"]["opts"]
316
+ ])
317
+ end
318
+ end
319
+
320
+ sub_test_case "meminfo collector" do
321
+ def meminfo_key_exist?(key)
322
+ File.readlines("/proc/meminfo").any? { |v| v.start_with?(key) }
323
+ end
324
+
325
+ def test_meminfo
326
+ params = create_minimum_config_params
327
+ params["meminfo"] = true
328
+ d = create_driver(config_element("ROOT", "", params))
329
+ d.run(expect_records: 1, timeout: 2)
330
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
331
+ fields = %w(
332
+ MemTotal_bytes
333
+ MemFree_bytes
334
+ MemAvailable_bytes
335
+ Buffers_bytes
336
+ Cached_bytes
337
+ SwapCached_bytes
338
+ Active_bytes
339
+ Inactive_bytes
340
+ Active_anon_bytes
341
+ Inactive_anon_bytes
342
+ Active_file_bytes
343
+ Inactive_file_bytes
344
+ Unevictable_bytes
345
+ Mlocked_bytes
346
+ SwapTotal_bytes
347
+ SwapFree_bytes
348
+ Dirty_bytes
349
+ Writeback_bytes
350
+ AnonPages_bytes
351
+ Mapped_bytes
352
+ Shmem_bytes
353
+ )
354
+ fields.concat(["KReclaimable_bytes"]) if meminfo_key_exist?("KReclaimable")
355
+ fields.concat(%w(
356
+ Slab_bytes
357
+ SReclaimable_bytes
358
+ SUnreclaim_bytes
359
+ KernelStack_bytes
360
+ PageTables_bytes
361
+ NFS_Unstable_bytes
362
+ Bounce_bytes
363
+ WritebackTmp_bytes
364
+ CommitLimit_bytes
365
+ Committed_AS_bytes
366
+ VmallocTotal_bytes
367
+ VmallocUsed_bytes
368
+ VmallocChunk_bytes
369
+ Percpu_bytes
370
+ HardwareCorrupted_bytes
371
+ AnonHugePages_bytes
372
+ ))
373
+ fields.concat(["CmaTotal_bytes"]) if meminfo_key_exist?("CmaTotal")
374
+ fields.concat(["CmaFree_bytes"]) if meminfo_key_exist?("CmaFree")
375
+ fields.concat(["ShmemHugePages_bytes"]) if meminfo_key_exist?("ShmemHugePages")
376
+ fields.concat(["ShmemPmdMapped_bytes"]) if meminfo_key_exist?("ShmemPmdMapped")
377
+ fields.concat(["FileHugePages_bytes"]) if meminfo_key_exist?("FileHugePages")
378
+ fields.concat(["FilePmdMapped_bytes"]) if meminfo_key_exist?("FilePmdMapped")
379
+ fields.concat(%w(
380
+ HugePages_Total
381
+ HugePages_Free
382
+ HugePages_Rsvd
383
+ HugePages_Surp
384
+ Hugepagesize_bytes
385
+ ))
386
+ fields.concat(["Hugetlb_bytes"]) if meminfo_key_exist?("Hugetlb")
387
+ fields.concat(%w(
388
+ DirectMap4k_bytes
389
+ DirectMap2M_bytes
390
+ DirectMap1G_bytes
391
+ ))
392
+ opts = []
393
+ fields.each do |field|
394
+ opts << {"ns"=>"node", "ss"=>"memory", "name"=>field, "desc"=>"#{field}."}
395
+ end
396
+ assert_equal([
397
+ fields.size,
398
+ opts
399
+ ].flatten,
400
+ [
401
+ cmetrics.size,
402
+ cmetrics.collect do |metric| metric["meta"]["opts"] end
403
+ ].flatten)
404
+ end
405
+ end
406
+
407
+ sub_test_case "netdev collector" do
408
+ def test_netdev
409
+ params = create_minimum_config_params
410
+ params["netdev"] = true
411
+ d = create_driver(config_element("ROOT", "", params))
412
+ d.run(expect_records: 1, timeout: 2)
413
+ c = Fluent::Plugin::NodeExporter::NetdevMetricsCollector.new
414
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
415
+ opts = []
416
+ Fluent::Plugin::NodeExporter::NetdevMetricsCollector::RECEIVE_FIELDS.each do |field|
417
+ opts << {"ns"=>"node", "ss"=>"network",
418
+ "name"=>"receive_#{field}_total", "desc"=>"Network device statistic receive_#{field}_total."}
419
+ end
420
+ Fluent::Plugin::NodeExporter::NetdevMetricsCollector::TRANSMIT_FIELDS.each do |field|
421
+ opts << {"ns"=>"node", "ss"=>"network",
422
+ "name"=>"transmit_#{field}_total", "desc"=>"Network device statistic transmit_#{field}_total."}
423
+ end
424
+ assert_equal([
425
+ 16, # receive 8 + transmit 8 entries
426
+ opts,
427
+ [c.target_devices.size] * 16
428
+ ].flatten,
429
+ [
430
+ cmetrics.size,
431
+ cmetrics.collect do |cmetric|
432
+ cmetric["meta"]["opts"]
433
+ end,
434
+ cmetrics.collect do |cmetric|
435
+ cmetric["values"].size
436
+ end
437
+ ].flatten)
438
+ end
439
+ end
440
+
441
+ sub_test_case "stat collector" do
442
+ def test_stat
443
+ params = create_minimum_config_params
444
+ params["stat"] = true
445
+ d = create_driver(config_element("ROOT", "", params))
446
+ d.run(expect_records: 1, timeout: 2)
447
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
448
+ assert_equal([
449
+ 6,
450
+ {"desc"=>"Total number of interrupts serviced.",
451
+ "name"=>"intr_total",
452
+ "ns"=>"node",
453
+ "ss"=>""},
454
+ {"desc"=>"Total number of context switches.",
455
+ "name"=>"context_switches_total",
456
+ "ns"=>"node",
457
+ "ss"=>""},
458
+ {"desc"=>"Total number of forks.",
459
+ "name"=>"forks_total",
460
+ "ns"=>"node",
461
+ "ss"=>""},
462
+ {"desc"=>"Node boot time, in unixtime.",
463
+ "name"=>"boot_time_seconds",
464
+ "ns"=>"node",
465
+ "ss"=>""},
466
+ {"desc"=>"Number of processes in runnable state.",
467
+ "name"=>"procs_running",
468
+ "ns"=>"node",
469
+ "ss"=>""},
470
+ {"desc"=>"Number of processes blocked waiting for I/O to complete.",
471
+ "name"=>"procs_blocked",
472
+ "ns"=>"node",
473
+ "ss"=>""},
474
+ ],
475
+ [
476
+ cmetrics.size,
477
+ cmetrics.collect do |cmetric|
478
+ cmetric["meta"]["opts"]
479
+ end,
480
+ ].flatten)
481
+ end
482
+ end
483
+
484
+ sub_test_case "time collector" do
485
+ def test_time
486
+ params = create_minimum_config_params
487
+ params["time"] = true
488
+ d = create_driver(config_element("ROOT", "", params))
489
+ d.run(expect_records: 1, timeout: 2)
490
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
491
+ assert_equal([
492
+ 1,
493
+ {"desc"=>"System time in seconds since epoch (1970).",
494
+ "name"=>"time_seconds",
495
+ "ns"=>"node",
496
+ "ss"=>""}
497
+ ],
498
+ [
499
+ cmetrics.size,
500
+ cmetrics.collect do |cmetric|
501
+ cmetric["meta"]["opts"]
502
+ end,
503
+ ].flatten)
504
+ end
505
+ end
506
+
507
+ sub_test_case "uname collector" do
508
+ def test_uname
509
+ params = create_minimum_config_params
510
+ params["uname"] = true
511
+ d = create_driver(config_element("ROOT", "", params))
512
+ d.run(expect_records: 1, timeout: 2)
513
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
514
+ assert_equal([
515
+ 1,
516
+ {"desc"=>"Labeled system information as provided by the uname system call.",
517
+ "name"=>"info",
518
+ "ns"=>"node",
519
+ "ss"=>"uname"}
520
+ ],
521
+ [
522
+ cmetrics.size,
523
+ cmetrics.collect do |cmetric|
524
+ cmetric["meta"]["opts"]
525
+ end,
526
+ ].flatten)
527
+ end
528
+ end
529
+
530
+ sub_test_case "vmstat collector" do
531
+ def test_vmstat
532
+ params = create_minimum_config_params
533
+ params["vmstat"] = true
534
+ d = create_driver(config_element("ROOT", "", params))
535
+ d.run(expect_records: 1, timeout: 2)
536
+ cmetrics = MessagePack.unpack(d.events.first.last["cmetrics"])
537
+ expected = [
538
+ {"desc"=>"/proc/vmstat information field pgpgin.",
539
+ "name"=>"pgpgin",
540
+ "ns"=>"node",
541
+ "ss"=>"vmstat"},
542
+ {"desc"=>"/proc/vmstat information field pgpgout.",
543
+ "name"=>"pgpgout",
544
+ "ns"=>"node",
545
+ "ss"=>"vmstat"},
546
+ {"desc"=>"/proc/vmstat information field pswpin.",
547
+ "name"=>"pswpin",
548
+ "ns"=>"node",
549
+ "ss"=>"vmstat"},
550
+ {"desc"=>"/proc/vmstat information field pswpout.",
551
+ "name"=>"pswpout",
552
+ "ns"=>"node",
553
+ "ss"=>"vmstat"},
554
+ {"desc"=>"/proc/vmstat information field pgfault.",
555
+ "name"=>"pgfault",
556
+ "ns"=>"node",
557
+ "ss"=>"vmstat"},
558
+ {"desc"=>"/proc/vmstat information field pgmajfault.",
559
+ "name"=>"pgmajfault",
560
+ "ns"=>"node",
561
+ "ss"=>"vmstat"}
562
+ ]
563
+ if Gem::Version.new(Etc.uname[:release].split("-", 2).first) >= Gem::Version.new("4.13.0")
564
+ # oom_kill counter since kernel 4.13+
565
+ expected << {"desc"=>"/proc/vmstat information field oom_kill.",
566
+ "name"=>"oom_kill",
567
+ "ns"=>"node",
568
+ "ss"=>"vmstat"}
569
+ end
570
+ assert_equal([
571
+ expected.size,
572
+ expected
573
+ ].flatten,
574
+ [
575
+ cmetrics.size,
576
+ cmetrics.collect do |cmetric|
577
+ cmetric["meta"]["opts"]
578
+ end,
579
+ ].flatten)
580
+ end
581
+ end
582
+ end
583
+ end
@@ -0,0 +1,41 @@
1
+ require "helper"
2
+ require "fluent/plugin/in_node_exporter_metrics"
3
+ require "fluent/plugin/node_exporter/loadavg_collector"
4
+
5
+ class LoadavgColectorTest < Test::Unit::TestCase
6
+ sub_test_case "loadavg" do
7
+
8
+ def parse(input)
9
+ stub(File).read { input }
10
+ collector = Fluent::Plugin::NodeExporter::LoadavgMetricsCollector.new
11
+ collector.run
12
+ yield collector
13
+ end
14
+
15
+ def test_invalid_fields
16
+ proc_loadavg = <<EOS
17
+ 0.32 0.30 0.31 2/1880 70024 0
18
+ EOS
19
+ parse(proc_loadavg) do |collector|
20
+ loadavg1 = collector.cmetrics[:loadavg1]
21
+ loadavg5 = collector.cmetrics[:loadavg5]
22
+ loadavg15 = collector.cmetrics[:loadavg15]
23
+ assert_equal([0.0, 0.0, 0.0],
24
+ [loadavg1.val, loadavg5.val, loadavg15.val])
25
+ end
26
+ end
27
+
28
+ def test_valid_fields
29
+ proc_loadavg = <<EOS
30
+ 0.10 0.20 0.30 2/1880 70024
31
+ EOS
32
+ parse(proc_loadavg) do |collector|
33
+ loadavg1 = collector.cmetrics[:loadavg1]
34
+ loadavg5 = collector.cmetrics[:loadavg5]
35
+ loadavg15 = collector.cmetrics[:loadavg15]
36
+ assert_equal([0.10, 0.20, 0.30],
37
+ [loadavg1.val, loadavg5.val, loadavg15.val])
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ require "helper"
2
+ require "fluent/plugin/in_node_exporter_metrics"
3
+ require "fluent/plugin/node_exporter/meminfo_collector"
4
+
5
+ class MeminfoColectorTest < Test::Unit::TestCase
6
+ sub_test_case "metric name" do
7
+
8
+ def parse(input)
9
+ stub(File).readlines { input.split("\n") }
10
+ collector = Fluent::Plugin::NodeExporter::MeminfoMetricsCollector.new
11
+ collector.run
12
+ yield collector
13
+ end
14
+
15
+ def test_anon_file
16
+ proc_meminfo = <<EOS
17
+ Active(anon): 100 kB
18
+ Inactive(anon): 200 kB
19
+ Active(file): 300 kB
20
+ Inactive(file): 400 kB
21
+ EOS
22
+ parse(proc_meminfo) do |collector|
23
+ assert_equal([102400.0, 204800.0, 307200.0, 409600.0],
24
+ [collector.cmetrics[:node_memory_Active_anon_bytes].val,
25
+ collector.cmetrics[:node_memory_Inactive_anon_bytes].val,
26
+ collector.cmetrics[:node_memory_Active_file_bytes].val,
27
+ collector.cmetrics[:node_memory_Inactive_file_bytes].val])
28
+ end
29
+ end
30
+
31
+ def test_non_kb
32
+ proc_meminfo = <<EOS
33
+ HugePages_Total: 100
34
+ HugePages_Free: 200
35
+ HugePages_Rsvd: 300
36
+ HugePages_Surp: 400
37
+ EOS
38
+ parse(proc_meminfo) do |collector|
39
+ assert_equal([100, 200, 300, 400],
40
+ [collector.cmetrics[:node_memory_HugePages_Total].val,
41
+ collector.cmetrics[:node_memory_HugePages_Free].val,
42
+ collector.cmetrics[:node_memory_HugePages_Rsvd].val,
43
+ collector.cmetrics[:node_memory_HugePages_Surp].val])
44
+ end
45
+ end
46
+ end
47
+ end