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,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