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,280 @@
1
+ #
2
+ # Copyright (C) 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class DiskstatsMetricsCollector < MetricsCollector
24
+
25
+ IGNORED_DEVICES = /^(ram|loop|fd|(h|s|v|xv)d[a-z]|nvme\d+n\d+p)\d+$/
26
+ # https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
27
+ # major number ... time spent flushing
28
+ DISKSTATS_KNOWN_FIELDS = 20
29
+ # assume sector size = 512
30
+ SECTOR_SIZE = 512
31
+
32
+ METRIC_NAMES = %w(
33
+ reads_completed_total
34
+ reads_merged_total
35
+ read_bytes_total
36
+ read_time_seconds_total
37
+ writes_completed_total
38
+ writes_merged_total
39
+ written_bytes_total
40
+ write_time_seconds_total
41
+ io_now
42
+ io_time_seconds_total
43
+ io_time_weighted_seconds_total
44
+ discards_completed_total
45
+ discards_merged_total
46
+ discarded_sectors_total
47
+ discard_time_seconds_total
48
+ flush_requests_total
49
+ flush_requests_time_seconds_total
50
+ )
51
+
52
+ DISCARD_METRIC_NAMES = %w(
53
+ discards_completed_total
54
+ discards_merged_total
55
+ discarded_sectors_total
56
+ discard_time_seconds_total
57
+ )
58
+
59
+ FLUSH_METRIC_NAMES = %w(
60
+ flush_requests_total
61
+ flush_requests_time_seconds_total
62
+ )
63
+
64
+ def initialize(config={})
65
+ super(config)
66
+
67
+ @reads_completed_total = CMetrics::Counter.new
68
+ @reads_completed_total.create("node", "disk", "reads_completed_total",
69
+ "The total number of reads completed successfully.",
70
+ ["device"])
71
+
72
+ @reads_merged_total = CMetrics::Counter.new
73
+ @reads_merged_total.create("node", "disk", "reads_merged_total",
74
+ "The total number of reads merged.",
75
+ ["device"])
76
+
77
+ @read_bytes_total = CMetrics::Counter.new
78
+ @read_bytes_total.create("node", "disk", "read_bytes_total",
79
+ "The total number of bytes read successfully.",
80
+ ["device"])
81
+
82
+ @read_time_seconds_total = CMetrics::Counter.new
83
+ @read_time_seconds_total.create("node", "disk", "reads_time_seconds_total",
84
+ "The total number of seconds spent by all reads.",
85
+ ["device"])
86
+
87
+ @writes_completed_total = CMetrics::Counter.new
88
+ @writes_completed_total.create("node", "disk", "writes_completed_total",
89
+ "The total number of writes completed successfully.",
90
+ ["device"])
91
+
92
+ @writes_merged_total = CMetrics::Counter.new
93
+ @writes_merged_total.create("node", "disk", "writes_merged_total",
94
+ "The number of writes merged.",
95
+ ["device"])
96
+
97
+ @written_bytes_total = CMetrics::Counter.new
98
+ @written_bytes_total.create("node", "disk", "written_bytes_total",
99
+ "The total number of bytes written successfully.",
100
+ ["device"])
101
+
102
+ @write_time_seconds_total = CMetrics::Counter.new
103
+ @write_time_seconds_total.create("node", "disk", "write_time_seconds_total",
104
+ "This is the total number of seconds spent by all writes.",
105
+ ["device"])
106
+
107
+ @io_now = CMetrics::Gauge.new
108
+ @io_now.create("node", "disk", "io_now",
109
+ "The number of I/Os currently in progress.",
110
+ ["device"])
111
+
112
+ @io_time_seconds_total = CMetrics::Counter.new
113
+ @io_time_seconds_total.create("node", "disk", "io_time_seconds_total",
114
+ "Total seconds spent doing I/Os.",
115
+ ["device"])
116
+
117
+ @io_time_weighted_seconds_total = CMetrics::Counter.new
118
+ @io_time_weighted_seconds_total.create("node", "disk", "io_time_weighted_seconds_total",
119
+ "The number of I/Os currently in progress.",
120
+ ["device"])
121
+
122
+ if kernel_version_over4_18?
123
+ # Kernel >= 4.18
124
+ @discards_completed_total = CMetrics::Counter.new
125
+ @discards_completed_total.create("node", "disk", "discards_completed_total",
126
+ "The total number of discards completed successfully.",
127
+ ["device"])
128
+
129
+ @discards_merged_total = CMetrics::Counter.new
130
+ @discards_merged_total.create("node", "disk", "discards_merged_total",
131
+ "The total number of discards merged.", ["device"])
132
+
133
+ @discarded_sectors_total = CMetrics::Counter.new
134
+ @discarded_sectors_total.create("node", "disk", "discards_sectors_total",
135
+ "The total number of sectors discarded successfully.",
136
+ ["device"])
137
+
138
+ @discard_time_seconds_total = CMetrics::Counter.new
139
+ @discard_time_seconds_total.create("node", "disk", "discard_time_seconds_total",
140
+ "The total number of seconds spent by all discards.",
141
+ ["device"])
142
+ end
143
+
144
+ if kernel_version_over5_5?
145
+ @flush_requests_total = CMetrics::Counter.new
146
+ @flush_requests_total.create("node", "disk", "flush_requests_total",
147
+ "The total number of flush requests completed successfully",
148
+ ["device"])
149
+
150
+ @flush_requests_time_seconds_total = CMetrics::Counter.new
151
+ @flush_requests_time_seconds_total.create("node", "disk", "flush_requests_time_seconds_total",
152
+ "This is the total number of seconds spent by all flush requests.",
153
+ ["device"])
154
+ end
155
+
156
+ @metrics = {}
157
+ end
158
+
159
+ def kernel_version_over4_18?
160
+ Gem::Version.new(Etc.uname[:release].split('-', 2).first) >= Gem::Version.new("4.18")
161
+ end
162
+
163
+ def kernel_version_over5_5?
164
+ Gem::Version.new(Etc.uname[:release].split('-', 2).first) >= Gem::Version.new("5.5.0")
165
+ end
166
+
167
+ def target_devices
168
+ devices = []
169
+ diskstats_path = File.join(@procfs_path, "diskstats")
170
+ File.readlines(diskstats_path).each do |line|
171
+ _, _, device, _ = line.split(' ', DISKSTATS_KNOWN_FIELDS)
172
+ unless IGNORED_DEVICES.match?(device)
173
+ devices << device
174
+ end
175
+ end
176
+ devices
177
+ end
178
+
179
+ def run
180
+ diskstats_update
181
+ end
182
+
183
+ def diskstats_update
184
+ diskstats_path = File.join(@procfs_path, "diskstats")
185
+ File.readlines(diskstats_path).each do |line|
186
+ _, _, device,
187
+ reads_completed_value, reads_merged_value, read_bytes_value, read_time_seconds_value,
188
+ writes_completed_value, writes_merged_value, written_bytes_value, write_time_seconds_value,
189
+ io_now_value, io_time_seconds_value, io_time_weighted_seconds_value,
190
+ discards_completed_value, discards_merged_value, discarded_sectors_value, discard_time_seconds_value,
191
+ flush_requests_value, flush_requests_time_seconds_value = line.split(' ', DISKSTATS_KNOWN_FIELDS)
192
+ unless IGNORED_DEVICES.match?(device)
193
+ METRIC_NAMES.each do |field|
194
+ case field
195
+ when "reads_completed_total"
196
+ @reads_completed_total.set(reads_completed_value.to_f, [device])
197
+ when "reads_merged_total"
198
+ @reads_merged_total.set(reads_merged_value.to_f, [device])
199
+ when "read_bytes_total"
200
+ @read_bytes_total.set(read_bytes_value.to_f * SECTOR_SIZE, [device])
201
+ when "read_time_seconds_total"
202
+ @read_time_seconds_total.set(read_time_seconds_value.to_f * 0.001, [device])
203
+ when "writes_completed_total"
204
+ @writes_completed_total.set(writes_completed_value.to_f, [device])
205
+ when "writes_merged_total"
206
+ @writes_merged_total.set(writes_merged_value.to_f, [device])
207
+ when "written_bytes_total"
208
+ @written_bytes_total.set(written_bytes_value.to_f * SECTOR_SIZE, [device])
209
+ when "write_time_seconds_total"
210
+ @write_time_seconds_total.set(write_time_seconds_value.to_f * 0.001, [device])
211
+ when "io_now"
212
+ @io_now.set(io_now_value.to_f, [device])
213
+ when "io_time_seconds_total"
214
+ @io_time_seconds_total.set(io_time_seconds_value.to_f * 0.001, [device])
215
+ when "io_time_weighted_seconds_total"
216
+ @io_time_weighted_seconds_total.set(io_time_weighted_seconds_value.to_f * 0.001, [device])
217
+ when "discards_completed_total"
218
+ if kernel_version_over4_18?
219
+ @discards_completed_total.set(discards_completed_value.to_f, [device])
220
+ end
221
+ when "discards_merged_total"
222
+ if kernel_version_over4_18?
223
+ @discards_merged_total.set(discards_merged_value.to_f, [device])
224
+ end
225
+ when "discarded_sectors_total"
226
+ if kernel_version_over4_18?
227
+ @discarded_sectors_total.set(discarded_sectors_value.to_f, [device])
228
+ end
229
+ when "discard_time_seconds_total"
230
+ if kernel_version_over4_18?
231
+ @discard_time_seconds_total.set(discard_time_seconds_value.to_f * 0.001, [device])
232
+ end
233
+ when "flush_requests_total"
234
+ if kernel_version_over5_5?
235
+ @flush_requests_total.set(flush_requests_value.to_f, [device])
236
+ end
237
+ when "flush_requests_time_seconds_total"
238
+ if kernel_version_over5_5?
239
+ @flush_requests_time_seconds_total.set(flush_requests_time_seconds_value.to_f * 0.001, [device])
240
+ end
241
+ end
242
+ end
243
+ @metrics = {
244
+ reads_completed_total: @reads_completed_total,
245
+ reads_merged_total: @reads_merged_total,
246
+ read_bytes_total: @read_bytes_total,
247
+ read_time_seconds_total: @read_time_seconds_total,
248
+ writes_completed_total: @writes_completed_total,
249
+ writes_merged_total: @writes_merged_total,
250
+ written_bytes_total: @written_bytes_total,
251
+ write_time_seconds_total: @write_time_seconds_total,
252
+ io_now: @io_now,
253
+ io_time_seconds_total: @io_time_seconds_total,
254
+ io_time_weighted_seconds_total: @io_time_weighted_seconds_total
255
+ }
256
+ if kernel_version_over4_18?
257
+ @metrics.merge!({
258
+ discards_completed_total: @discards_completed_total,
259
+ discards_merged_total: @discards_merged_total,
260
+ discarded_sectors_total: @discarded_sectors_total,
261
+ discard_time_seconds_total: @discard_time_seconds_total
262
+ })
263
+ end
264
+ if kernel_version_over5_5?
265
+ @metrics.merge!({
266
+ flush_requests_total: @flush_requests_total,
267
+ flush_requests_time_seconds_total: @flush_requests_time_seconds_total
268
+ })
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ def cmetrics
275
+ @metrics
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Copyright 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class FilefdMetricsCollector < MetricsCollector
24
+ def initialize(config={})
25
+ super(config)
26
+
27
+ @allocated = CMetrics::Gauge.new
28
+ @allocated.create("node", "filefd", "allocated", "File descriptor statistics: allocated.")
29
+
30
+ @maximum = CMetrics::Gauge.new
31
+ @maximum.create("node", "filefd", "maximum", "File descriptor statistics: maximum.")
32
+ end
33
+
34
+ def run
35
+ filefd_update
36
+ end
37
+
38
+ def filefd_update
39
+ # Etc.uname returns at least sysname,release,version,machine,nodename
40
+ # but it is not guaranteed to return domainname.
41
+ file_nr_path = File.join(@procfs_path, "/sys/fs/file-nr")
42
+ entry = File.read(file_nr_path).split
43
+ unless entry.size == 3
44
+ $log.warn("invalid number of field <#{file_nr_path}>: #{entry.size}")
45
+ return
46
+ end
47
+ @allocated.set(entry.first.to_f)
48
+ @maximum.set(entry.last.to_f)
49
+ end
50
+
51
+ def cmetrics
52
+ {
53
+ filefd_allocated: @allocated,
54
+ filefd_maximum: @maximum
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class LoadavgMetricsCollector < MetricsCollector
24
+ def initialize(config={})
25
+ super(config)
26
+
27
+ @load1 = CMetrics::Gauge.new
28
+ @load1.create("node", "", "load1", "1m load average.")
29
+
30
+ @load5 = CMetrics::Gauge.new
31
+ @load5.create("node", "", "load5", "5m load average.")
32
+
33
+ @load15 = CMetrics::Gauge.new
34
+ @load15.create("node", "", "load15", "15m load average.")
35
+ end
36
+
37
+ def run
38
+ loadavg_update
39
+ end
40
+
41
+ def loadavg_update
42
+ loadavg_path = File.join(@procfs_path, "/loadavg")
43
+ # Use 1 explicitly for default gauge value
44
+ fields = File.read(loadavg_path).split
45
+ unless fields.size == 5
46
+ $log.warn("invalid number of fields <#{loadavg_path}>: <#{fields.size}>")
47
+ return
48
+ end
49
+ @load1.set(fields[0].to_f)
50
+ @load5.set(fields[1].to_f)
51
+ @load15.set(fields[2].to_f)
52
+ end
53
+
54
+ def cmetrics
55
+ {
56
+ loadavg1: @load1,
57
+ loadavg5: @load5,
58
+ loadavg15: @load15
59
+ }
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # Copyright 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class MeminfoMetricsCollector < MetricsCollector
24
+
25
+ def initialize(config={})
26
+ super(config)
27
+
28
+ @metrics = {}
29
+ end
30
+
31
+ def run
32
+ meminfo_update
33
+ end
34
+
35
+ def meminfo_update
36
+ meminfo_path = File.join(@procfs_path, "meminfo")
37
+ File.readlines(meminfo_path).each do |line|
38
+ name, value, unit = line.split
39
+ name.delete!(":")
40
+ if name.end_with?("(anon)") or name.end_with?("(file)")
41
+ name.sub!(/\((anon)\)|\((file)\)/, "_\\1\\2")
42
+ end
43
+ if unit
44
+ name << "_bytes"
45
+ value = value.to_f * 1024
46
+ end
47
+ metric_name = "node_memory_#{name}"
48
+ @gauge = CMetrics::Gauge.new
49
+ @gauge.create("node", "memory", name, "#{name}.")
50
+ @gauge.set(value.to_f)
51
+ @metrics[metric_name.intern] = @gauge
52
+ end
53
+ end
54
+
55
+ def cmetrics
56
+ @metrics
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,92 @@
1
+ #
2
+ # Copyright 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class NetdevMetricsCollector < MetricsCollector
24
+
25
+ def initialize(config={})
26
+ super(config)
27
+
28
+ @metrics = {}
29
+ end
30
+
31
+ def run
32
+ netdev_update
33
+ end
34
+
35
+ RECEIVE_FIELDS = %w(bytes packets errs drop fifo frame compressed multicast)
36
+ TRANSMIT_FIELDS = %w(bytes packets errs drop fifo colls carrier compressed)
37
+
38
+ def target_devices
39
+ devices = []
40
+ netdev_path = File.join(@procfs_path, "net/dev")
41
+ File.readlines(netdev_path).each_with_index do |line, index|
42
+ next if index < 2
43
+ interface, _ = line.split
44
+ interface.delete!(":")
45
+ devices << interface
46
+ end
47
+ devices
48
+ end
49
+
50
+ def netdev_update
51
+ netdev_path = File.join(@procfs_path, "net/dev")
52
+ RECEIVE_FIELDS.each_with_index do |field, index|
53
+ metric_name = "receive_#{field}_total"
54
+ @counter = CMetrics::Counter.new
55
+ @counter.create("node", "network", metric_name, "Network device statistic #{metric_name}.", ["device"])
56
+ @metrics[metric_name.intern] = @counter
57
+ end
58
+ TRANSMIT_FIELDS.each_with_index do |field, index|
59
+ metric_name = "transmit_#{field}_total"
60
+ @counter = CMetrics::Counter.new
61
+ @counter.create("node", "network", metric_name, "Network device statistic #{metric_name}.", ["device"])
62
+ @metrics[metric_name.intern] = @counter
63
+ end
64
+ File.readlines(netdev_path).each_with_index do |line, index|
65
+ # net/dev must be 3 columns
66
+ if index == 0 and line.split("|").size != 3
67
+ break
68
+ end
69
+ # first 2 line are header (Inter-face/Receive/Transmit)
70
+ next if index < 2
71
+
72
+ interface, *values = line.split
73
+ interface.delete!(":")
74
+
75
+ RECEIVE_FIELDS.each_with_index do |field, index|
76
+ metric_name = "receive_#{field}_total"
77
+ @metrics[metric_name.intern].set(values[index].to_f, [interface])
78
+ end
79
+ TRANSMIT_FIELDS.each_with_index do |field, index|
80
+ metric_name = "transmit_#{field}_total"
81
+ @metrics[metric_name.intern].set(values[index + RECEIVE_FIELDS.size].to_f, [interface])
82
+ end
83
+ end
84
+ end
85
+
86
+ def cmetrics
87
+ @metrics
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,84 @@
1
+ #
2
+ # Copyright 2021- Kentaro Hayashi
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "cmetrics"
17
+ require "fluent/plugin/input"
18
+ require "fluent/plugin/node_exporter/collector"
19
+
20
+ module Fluent
21
+ module Plugin
22
+ module NodeExporter
23
+ class StatMetricsCollector < MetricsCollector
24
+ def initialize(config={})
25
+ super(config)
26
+
27
+ @intr_total = CMetrics::Counter.new
28
+ @intr_total.create("node", "", "intr_total", "Total number of interrupts serviced.")
29
+
30
+ @context_switches_total = CMetrics::Counter.new
31
+ @context_switches_total.create("node", "", "context_switches_total", "Total number of context switches.")
32
+
33
+ @forks_total = CMetrics::Counter.new
34
+ @forks_total.create("node", "", "forks_total", "Total number of forks.")
35
+
36
+ @boot_time_seconds = CMetrics::Gauge.new
37
+ @boot_time_seconds.create("node", "", "boot_time_seconds", "Node boot time, in unixtime.")
38
+
39
+ @procs_running = CMetrics::Gauge.new
40
+ @procs_running.create("node", "", "procs_running", "Number of processes in runnable state.")
41
+
42
+ @procs_blocked = CMetrics::Gauge.new
43
+ @procs_blocked.create("node", "", "procs_blocked", "Number of processes blocked waiting for I/O to complete.")
44
+ end
45
+
46
+ def run
47
+ stat_update
48
+ end
49
+
50
+ def stat_update
51
+ stat_path = File.join(@procfs_path, "stat")
52
+ File.readlines(stat_path).each do |line|
53
+ entry, value, _ = line.split
54
+ case entry
55
+ when "intr"
56
+ @intr_total.set(value.to_f)
57
+ when "ctxt"
58
+ @context_switches_total.set(value.to_f)
59
+ when "btime"
60
+ @boot_time_seconds.set(value.to_f)
61
+ when "processes"
62
+ @forks_total.set(value.to_f)
63
+ when "procs_running"
64
+ @procs_running.set(value.to_f)
65
+ when "procs_blocked"
66
+ @procs_blocked.set(value.to_f)
67
+ end
68
+ end
69
+ end
70
+
71
+ def cmetrics
72
+ {
73
+ intr_total: @intr_total,
74
+ context_switches_total: @context_switches_total,
75
+ forks_total: @forks_total,
76
+ boot_time_seconds: @boot_time_seconds,
77
+ procs_running: @procs_running,
78
+ procs_blocked: @procs_blocked
79
+ }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end