fluent-plugin-node-exporter-metrics 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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