/src/fluent-bit/plugins/in_podman_metrics/podman_metrics.c
Line | Count | Source |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2015-2026 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <fluent-bit/flb_input_plugin.h> |
21 | | #include <fluent-bit/flb_config.h> |
22 | | #include <fluent-bit/flb_metrics.h> |
23 | | #include <fluent-bit/flb_metrics_exporter.h> |
24 | | #include <fluent-bit/flb_jsmn.h> |
25 | | |
26 | | #include <monkey/mk_core/mk_list.h> |
27 | | |
28 | | #include "podman_metrics.h" |
29 | | #include "podman_metrics_config.h" |
30 | | #include "podman_metrics_data.h" |
31 | | |
32 | | /* |
33 | | * Collect information about podman containers (ID and Name) from podman configuration |
34 | | * file (default is /var/lib/containers/storage/overlay-containers/containers.json). |
35 | | * Since flb_jsmn library show JSON as a tree, search for objects with parent 0 (objects |
36 | | * that are children to root array, and in them, search for ID and name (which is also |
37 | | * an array. |
38 | | */ |
39 | | static int collect_container_data(struct flb_in_metrics *ctx) |
40 | 0 | { |
41 | | /* Buffers for reading data from JSON */ |
42 | 0 | char *buffer; |
43 | 0 | char name[CONTAINER_NAME_SIZE]; |
44 | 0 | char id[CONTAINER_ID_SIZE]; |
45 | 0 | char image_name[IMAGE_NAME_SIZE]; |
46 | 0 | char metadata[CONTAINER_METADATA_SIZE]; |
47 | 0 | char *metadata_token_start; |
48 | 0 | char *metadata_token_stop; |
49 | 0 | int metadata_token_size; |
50 | |
|
51 | 0 | int array_id; |
52 | 0 | int r, i, j; |
53 | 0 | size_t read_bytes = 0; |
54 | 0 | int collected_containers = 0; |
55 | 0 | int token_len; |
56 | |
|
57 | 0 | jsmn_parser p; |
58 | 0 | jsmntok_t t[JSON_TOKENS]; |
59 | |
|
60 | 0 | flb_utils_read_file(ctx->config, &buffer, &read_bytes); |
61 | 0 | if (!read_bytes) { |
62 | 0 | flb_plg_warn(ctx->ins, "Failed to open %s", ctx->config); |
63 | 0 | return -1; |
64 | 0 | } |
65 | 0 | buffer[read_bytes] = 0; |
66 | 0 | flb_plg_debug(ctx->ins, "Read %zu bytes", read_bytes); |
67 | |
|
68 | 0 | jsmn_init(&p); |
69 | 0 | r = jsmn_parse(&p, buffer, strlen(buffer), t, sizeof(t) / sizeof(t[0])); |
70 | 0 | if (r < 0) { |
71 | 0 | flb_plg_warn(ctx->ins, "Failed to parse JSON %d: %s", r, buffer); |
72 | 0 | free(buffer); |
73 | 0 | return -1; |
74 | 0 | } |
75 | | |
76 | 0 | flb_plg_debug(ctx->ins, "Got %d nested tokens", t[0].size); |
77 | |
|
78 | 0 | if (r < 1 || t[0].type != JSMN_ARRAY) { |
79 | 0 | flb_plg_warn(ctx->ins, "Expected array at the json root"); |
80 | 0 | free(buffer); |
81 | 0 | return -1; |
82 | 0 | } |
83 | | |
84 | 0 | for (i=0; i<r; i++) { |
85 | 0 | if (t[i].type == JSMN_STRING) { |
86 | 0 | if (sizeof(JSON_FIELD_ID)-1 == t[i].end - t[i].start && |
87 | 0 | strncmp(buffer + t[i].start, JSON_FIELD_ID, t[i].end - t[i].start) == 0) { |
88 | 0 | token_len = t[i + 1].end - t[i + 1].start; |
89 | 0 | strncpy(id, buffer + t[i+1].start, t[i + 1].end - t[i + 1].start); |
90 | 0 | id[token_len] = '\0'; |
91 | 0 | flb_plg_trace(ctx->ins, "Found id %s", id); |
92 | 0 | } |
93 | 0 | else if (sizeof(JSON_FIELD_NAMES)-1 == t[i].end - t[i].start && |
94 | 0 | strncmp(buffer + t[i].start, JSON_FIELD_NAMES, t[i].end - t[i].start) == 0) { |
95 | 0 | array_id = i + 1; |
96 | 0 | if (t[array_id].type == JSMN_ARRAY) { |
97 | 0 | j = array_id + 1; |
98 | 0 | while (t[j].parent == array_id) |
99 | 0 | { |
100 | 0 | strncpy(name, buffer + t[j].start, t[j].end - t[j].start); |
101 | 0 | name[t[j].end - t[j].start] = '\0'; |
102 | 0 | flb_plg_trace(ctx->ins, "Found name %s", name); |
103 | 0 | j++; |
104 | 0 | } |
105 | 0 | } |
106 | 0 | } |
107 | 0 | else if (sizeof(JSON_FIELD_METADATA)-1 == t[i].end - t[i].start && |
108 | 0 | strncmp(buffer + t[i].start, JSON_FIELD_METADATA, t[i].end - t[i].start) == 0) { |
109 | 0 | token_len = t[i + 1].end - t[i + 1].start; |
110 | 0 | strncpy(metadata, buffer + t[i+1].start, t[i + 1].end - t[i + 1].start); |
111 | 0 | metadata[token_len] = '\0'; |
112 | |
|
113 | 0 | metadata_token_start = strstr(metadata, JSON_SUBFIELD_IMAGE_NAME); |
114 | 0 | if (metadata_token_start) { |
115 | 0 | metadata_token_stop = strstr(metadata_token_start + JSON_SUBFIELD_SIZE_IMAGE_NAME+1, "\\\""); |
116 | 0 | metadata_token_size = metadata_token_stop - metadata_token_start - JSON_SUBFIELD_SIZE_IMAGE_NAME; |
117 | |
|
118 | 0 | strncpy(image_name, metadata_token_start+JSON_SUBFIELD_SIZE_IMAGE_NAME, metadata_token_size); |
119 | 0 | image_name[metadata_token_size] = '\0'; |
120 | |
|
121 | 0 | flb_plg_trace(ctx->ins, "Found image name %s", image_name); |
122 | 0 | add_container_to_list(ctx, id, name, image_name); |
123 | 0 | } |
124 | 0 | else { |
125 | 0 | flb_plg_warn(ctx->ins, "Image name was not found for %s", id); |
126 | 0 | add_container_to_list(ctx, id, name, "unknown"); |
127 | 0 | } |
128 | 0 | collected_containers++; |
129 | 0 | } |
130 | 0 | } |
131 | 0 | } |
132 | |
|
133 | 0 | flb_plg_debug(ctx->ins, "Collected %d containers from podman config file", collected_containers); |
134 | 0 | free(buffer); |
135 | 0 | return collected_containers; |
136 | 0 | } |
137 | | |
138 | | /* |
139 | | * Create structure instance based on previously found id, name and image name. Set all its values (like |
140 | | * memory or cpu to UINT64_MAX, in case it won't be found later. This function also adds this structure |
141 | | * to internal list, so it can be found by iteration later on. |
142 | | */ |
143 | | static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t name, flb_sds_t image_name) |
144 | 0 | { |
145 | 0 | struct container *cnt; |
146 | 0 | cnt = flb_malloc(sizeof(struct container)); |
147 | 0 | if (!cnt) { |
148 | 0 | flb_errno(); |
149 | 0 | return -1; |
150 | 0 | } |
151 | 0 | cnt->id = flb_sds_create(id); |
152 | 0 | cnt->name = flb_sds_create(name); |
153 | 0 | cnt->image_name = flb_sds_create(image_name); |
154 | |
|
155 | 0 | cnt->memory_usage = UINT64_MAX; |
156 | 0 | cnt->memory_max_usage = UINT64_MAX; |
157 | 0 | cnt->memory_limit = UINT64_MAX; |
158 | 0 | cnt->rss = UINT64_MAX; |
159 | 0 | cnt->cpu_user = UINT64_MAX; |
160 | 0 | cnt->cpu = UINT64_MAX; |
161 | |
|
162 | 0 | mk_list_init(&cnt->net_data); |
163 | |
|
164 | 0 | mk_list_add(&cnt->_head, &ctx->items); |
165 | 0 | return 0; |
166 | 0 | } |
167 | | |
168 | | /* |
169 | | * Iterate over container list and remove collected data |
170 | | */ |
171 | | static int destroy_container_list(struct flb_in_metrics *ctx) |
172 | 0 | { |
173 | 0 | struct container *cnt; |
174 | 0 | struct net_iface *iface; |
175 | 0 | struct sysfs_path *pth; |
176 | 0 | struct mk_list *head; |
177 | 0 | struct mk_list *tmp; |
178 | 0 | struct mk_list *inner_head; |
179 | 0 | struct mk_list *inner_tmp; |
180 | |
|
181 | 0 | mk_list_foreach_safe(head, tmp, &ctx->items) { |
182 | 0 | cnt = mk_list_entry(head, struct container, _head); |
183 | 0 | flb_plg_debug(ctx->ins, "Destroying container data (id: %s, name: %s", cnt->id, cnt->name); |
184 | |
|
185 | 0 | flb_sds_destroy(cnt->id); |
186 | 0 | flb_sds_destroy(cnt->name); |
187 | 0 | flb_sds_destroy(cnt->image_name); |
188 | 0 | mk_list_foreach_safe(inner_head, inner_tmp, &cnt->net_data) { |
189 | 0 | iface = mk_list_entry(inner_head, struct net_iface, _head); |
190 | 0 | flb_sds_destroy(iface->name); |
191 | 0 | mk_list_del(&iface->_head); |
192 | 0 | flb_free(iface); |
193 | 0 | } |
194 | 0 | mk_list_del(&cnt->_head); |
195 | 0 | flb_free(cnt); |
196 | 0 | } |
197 | |
|
198 | 0 | mk_list_foreach_safe(head, tmp, &ctx->sysfs_items) { |
199 | 0 | pth = mk_list_entry(head, struct sysfs_path, _head); |
200 | 0 | flb_plg_trace(ctx->ins, "Destroying sysfs data (name: %s", pth->path); |
201 | 0 | flb_sds_destroy(pth->path); |
202 | 0 | mk_list_del(&pth->_head); |
203 | 0 | flb_free(pth); |
204 | 0 | } |
205 | 0 | return 0; |
206 | 0 | } |
207 | | |
208 | | |
209 | | /* |
210 | | * Create counter for given metric name, using name, image name and value as counter labels. Counters |
211 | | * are created per counter name, so they are "shared" between multiple containers - counter |
212 | | * name remains the same, only labels like ID are changed. |
213 | | * This function creates counter only once per counter name - every next call only sets counter |
214 | | * value for specific labels. |
215 | | */ |
216 | | static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **counter, flb_sds_t id, flb_sds_t name, flb_sds_t image_name, flb_sds_t metric_prefix, |
217 | | flb_sds_t *fields, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value) |
218 | 0 | { |
219 | 0 | flb_sds_t *labels; |
220 | 0 | uint64_t fvalue = value; |
221 | |
|
222 | 0 | int label_count; |
223 | 0 | if (value == UINT64_MAX) { |
224 | 0 | flb_plg_debug(ctx->ins, "Ignoring invalid counter for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
225 | 0 | return -1; |
226 | 0 | } |
227 | | |
228 | 0 | if (strcmp(metric_name, COUNTER_CPU) == 0 || strcmp(metric_name, COUNTER_CPU_USER) == 0) { |
229 | 0 | fvalue = fvalue / 1000000000; |
230 | 0 | flb_plg_trace(ctx->ins, "Converting %s from nanoseconds to seconds (%lu -> %lu)", metric_name, value, fvalue); |
231 | |
|
232 | 0 | } |
233 | |
|
234 | 0 | labels = (char *[]){id, name, image_name, interface}; |
235 | 0 | if (interface == NULL) { |
236 | 0 | label_count = 3; |
237 | 0 | } |
238 | 0 | else { |
239 | 0 | label_count = 4; |
240 | 0 | } |
241 | | |
242 | | /* if counter was not yet created, it means that this function is called for the first time per counter type */ |
243 | 0 | if (*counter == NULL) { |
244 | 0 | flb_plg_debug(ctx->ins, "Creating counter for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
245 | 0 | *counter = cmt_counter_create(ctx->ins->cmt, COUNTER_PREFIX, metric_prefix, metric_name, description, label_count, fields); |
246 | 0 | } |
247 | | |
248 | | /* Allow setting value that is not grater that current one (if, for example, memory usage stays exactly the same) */ |
249 | 0 | cmt_counter_allow_reset(*counter); |
250 | 0 | flb_plg_debug(ctx->ins, "Set counter for %s, %s_%s_%s: %lu", name, COUNTER_PREFIX, metric_prefix, metric_name, fvalue); |
251 | 0 | if (cmt_counter_set(*counter, cfl_time_now(), fvalue, label_count, labels) == -1) { |
252 | 0 | flb_plg_warn(ctx->ins, "Failed to set counter for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
253 | 0 | return -1; |
254 | 0 | } |
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | | /* |
259 | | * Create gauge for given metric name, using name, image name and value as counter labels. Gauges |
260 | | * are created per counter name, so they are "shared" between multiple containers - counter |
261 | | * name remains the same, only labels like ID are changed. |
262 | | * This function creates gauge only once per counter name - every next call only sets gauge |
263 | | * value for specific labels. |
264 | | */ |
265 | | static int create_gauge(struct flb_in_metrics *ctx, struct cmt_gauge **gauge, flb_sds_t id, flb_sds_t name, flb_sds_t image_name, flb_sds_t metric_prefix, |
266 | | flb_sds_t *fields, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value) |
267 | 0 | { |
268 | 0 | flb_sds_t *labels; |
269 | 0 | int label_count; |
270 | 0 | if (value == UINT64_MAX) { |
271 | 0 | flb_plg_debug(ctx->ins, "Ignoring invalid gauge for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
272 | 0 | return -1; |
273 | 0 | } |
274 | | |
275 | 0 | labels = (char *[]){id, name, image_name}; |
276 | 0 | label_count = 3; |
277 | | |
278 | | /* if gauge was not yet created, it means that this function is called for the first time per counter type */ |
279 | 0 | if (*gauge == NULL) { |
280 | 0 | flb_plg_debug(ctx->ins, "Creating gauge for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
281 | 0 | *gauge = cmt_gauge_create(ctx->ins->cmt, COUNTER_PREFIX, metric_prefix, metric_name, description, label_count, fields); |
282 | 0 | } |
283 | |
|
284 | 0 | flb_plg_debug(ctx->ins, "Set gauge for %s, %s_%s_%s: %lu", name, COUNTER_PREFIX, metric_prefix, metric_name, value); |
285 | 0 | if (cmt_gauge_set(*gauge, cfl_time_now(), value, label_count, labels) == -1) { |
286 | 0 | flb_plg_warn(ctx->ins, "Failed to set gauge for %s, %s_%s_%s", name, COUNTER_PREFIX, metric_prefix, metric_name); |
287 | 0 | return -1; |
288 | 0 | } |
289 | 0 | return 0; |
290 | 0 | } |
291 | | |
292 | | /* |
293 | | * Call create_counter for every counter type defined in this plugin. |
294 | | * |
295 | | * Currently supported counters are: |
296 | | * - container_memory_usage_bytes |
297 | | * - container_memory_max_usage_bytes |
298 | | * - container_memory_rss |
299 | | * - container_spec_memory_limit_bytes |
300 | | * - container_cpu_user_seconds_total |
301 | | * - container_cpu_usage_seconds_total |
302 | | * - container_network_receive_bytes_total |
303 | | * - container_network_receive_errors_total |
304 | | * - container_network_transmit_bytes_total |
305 | | * - container_network_transmit_errors_total |
306 | | */ |
307 | | static int create_counters(struct flb_in_metrics *ctx) |
308 | 0 | { |
309 | 0 | struct container *cnt; |
310 | 0 | struct net_iface *iface; |
311 | 0 | struct mk_list *head; |
312 | 0 | struct mk_list *tmp; |
313 | 0 | struct mk_list *inner_head; |
314 | 0 | struct mk_list *inner_tmp; |
315 | |
|
316 | 0 | mk_list_foreach_safe(head, tmp, &ctx->items) |
317 | 0 | { |
318 | 0 | cnt = mk_list_entry(head, struct container, _head); |
319 | 0 | create_counter(ctx, &ctx->c_memory_usage, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_USAGE, |
320 | 0 | DESCRIPTION_MEMORY_USAGE, NULL, cnt->memory_usage); |
321 | 0 | create_counter(ctx, &ctx->c_memory_max_usage, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_MAX_USAGE, |
322 | 0 | DESCRIPTION_MEMORY_MAX_USAGE, NULL, cnt->memory_max_usage); |
323 | 0 | create_counter(ctx, &ctx->c_memory_limit, cnt->id, cnt->name, cnt->image_name, COUNTER_SPEC_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_LIMIT, |
324 | 0 | DESCRIPTION_MEMORY_LIMIT, NULL, cnt->memory_limit); |
325 | 0 | create_gauge(ctx, &ctx->g_rss, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, GAUGE_MEMORY_RSS, |
326 | 0 | DESCRIPTION_MEMORY_RSS, NULL, cnt->rss); |
327 | 0 | create_counter(ctx, &ctx->c_cpu_user, cnt->id, cnt->name, cnt->image_name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU_USER, |
328 | 0 | DESCRIPTION_CPU_USER, NULL, cnt->cpu_user); |
329 | 0 | create_counter(ctx, &ctx->c_cpu, cnt->id, cnt->name, cnt->image_name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU, |
330 | 0 | DESCRIPTION_CPU, NULL, cnt->cpu); |
331 | 0 | mk_list_foreach_safe(inner_head, inner_tmp, &cnt->net_data) |
332 | 0 | { |
333 | 0 | iface = mk_list_entry(inner_head, struct net_iface, _head); |
334 | 0 | create_counter(ctx, &ctx->rx_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_BYTES, |
335 | 0 | DESCRIPTION_RX_BYTES, iface->name, iface->rx_bytes); |
336 | 0 | create_counter(ctx, &ctx->rx_errors, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_ERRORS, |
337 | 0 | DESCRIPTION_RX_ERRORS, iface->name, iface->rx_errors); |
338 | 0 | create_counter(ctx, &ctx->tx_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_BYTES, |
339 | 0 | DESCRIPTION_TX_BYTES, iface->name, iface->tx_bytes); |
340 | 0 | create_counter(ctx, &ctx->tx_errors, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_ERRORS, |
341 | 0 | DESCRIPTION_TX_ERRORS, iface->name, iface->tx_errors); |
342 | 0 | } |
343 | 0 | } |
344 | 0 | return 0; |
345 | 0 | } |
346 | | |
347 | | /* Main function. Destroy (optionally) previous data, gather container data and |
348 | | * create counters. |
349 | | */ |
350 | | static int scrape_metrics(struct flb_config *config, struct flb_in_metrics *ctx) |
351 | 0 | { |
352 | 0 | uint64_t start_ts = cfl_time_now(); |
353 | 0 | flb_plg_debug(ctx->ins, "Starting to scrape podman metrics"); |
354 | 0 | if (destroy_container_list(ctx) == -1) { |
355 | 0 | flb_plg_error(ctx->ins, "Could not destroy previous container data"); |
356 | 0 | return -1; |
357 | 0 | } |
358 | | |
359 | 0 | if (collect_container_data(ctx) == -1) { |
360 | 0 | flb_plg_error(ctx->ins, "Could not collect container ids"); |
361 | 0 | return -1; |
362 | 0 | } |
363 | | |
364 | 0 | if (collect_sysfs_directories(ctx, ctx->sysfs_path) == -1) |
365 | 0 | { |
366 | 0 | flb_plg_error(ctx->ins, "Could not collect sysfs data"); |
367 | 0 | return -1; |
368 | 0 | } |
369 | | |
370 | 0 | if (ctx->cgroup_version == CGROUP_V1) { |
371 | 0 | if (fill_counters_with_sysfs_data_v1(ctx) == -1) { |
372 | 0 | flb_plg_error(ctx->ins, "Could not collect V1 sysfs data"); |
373 | 0 | return -1; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | else if (ctx->cgroup_version == CGROUP_V2) { |
377 | 0 | if (fill_counters_with_sysfs_data_v2(ctx) == -1) { |
378 | 0 | flb_plg_error(ctx->ins, "Could not collect V2 sysfs data"); |
379 | 0 | return -1; |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | 0 | if (create_counters(ctx) == -1) { |
384 | 0 | flb_plg_error(ctx->ins, "Could not create container counters"); |
385 | 0 | return -1; |
386 | 0 | } |
387 | | |
388 | 0 | if (flb_input_metrics_append(ctx->ins, NULL, 0, ctx->ins->cmt) == -1) { |
389 | 0 | flb_plg_error(ctx->ins, "Could not append metrics"); |
390 | 0 | return -1; |
391 | 0 | } |
392 | | |
393 | 0 | flb_plg_info(ctx->ins, "Scraping metrics took %luns", cfl_time_now() - start_ts); |
394 | 0 | return 0; |
395 | 0 | } |
396 | | |
397 | | /* |
398 | | * Call scrape_metrics function every `scrape interval`. |
399 | | */ |
400 | | static int cb_metrics_collect_runtime(struct flb_input_instance *ins, struct flb_config *config, void *in_context) |
401 | 0 | { |
402 | 0 | return scrape_metrics(config, in_context); |
403 | 0 | } |
404 | | |
405 | | /* |
406 | | * Initialize plugin, setup config file path and (optionally) scrape container |
407 | | * data (if `scrape_at_start` is set). |
408 | | */ |
409 | | static int in_metrics_init(struct flb_input_instance *in, struct flb_config *config, void *data) |
410 | 0 | { |
411 | 0 | struct flb_in_metrics *ctx; |
412 | 0 | int coll_fd_runtime; |
413 | |
|
414 | 0 | ctx = flb_calloc(1, sizeof(struct flb_in_metrics)); |
415 | 0 | if (!ctx) { |
416 | 0 | return -1; |
417 | 0 | } |
418 | 0 | ctx->ins = in; |
419 | |
|
420 | 0 | ctx->c_memory_usage = NULL; |
421 | 0 | ctx->c_memory_max_usage = NULL; |
422 | 0 | ctx->g_rss = NULL; |
423 | 0 | ctx->c_memory_limit = NULL; |
424 | 0 | ctx->c_cpu_user = NULL; |
425 | 0 | ctx->c_cpu = NULL; |
426 | 0 | ctx->rx_bytes = NULL; |
427 | 0 | ctx->rx_errors = NULL; |
428 | 0 | ctx->tx_bytes = NULL; |
429 | 0 | ctx->tx_errors = NULL; |
430 | |
|
431 | 0 | if (flb_input_config_map_set(in, (void *) ctx) == -1) { |
432 | 0 | flb_free(ctx); |
433 | 0 | return -1; |
434 | 0 | } |
435 | | |
436 | 0 | flb_input_set_context(in, ctx); |
437 | 0 | coll_fd_runtime = flb_input_set_collector_time(in, cb_metrics_collect_runtime, ctx->scrape_interval, 0, config); |
438 | 0 | if (coll_fd_runtime == -1) { |
439 | 0 | flb_plg_error(ctx->ins, "Could not set collector for podman metrics plugin"); |
440 | 0 | return -1; |
441 | 0 | } |
442 | 0 | ctx->coll_fd_runtime = coll_fd_runtime; |
443 | |
|
444 | 0 | if (ctx->podman_config_path) { |
445 | 0 | flb_plg_info(ctx->ins, "Using config file %s", ctx->podman_config_path); |
446 | 0 | ctx->config = flb_sds_create(ctx->podman_config_path); |
447 | 0 | } |
448 | 0 | else { |
449 | 0 | flb_plg_info(ctx->ins, "Using default config file %s", PODMAN_CONFIG_DEFAULT_PATH); |
450 | 0 | ctx->config = flb_sds_create(PODMAN_CONFIG_DEFAULT_PATH); |
451 | 0 | } |
452 | |
|
453 | 0 | if (get_cgroup_version(ctx) == CGROUP_V2) { |
454 | 0 | flb_plg_info(ctx->ins, "Detected cgroups v2"); |
455 | 0 | ctx->cgroup_version = CGROUP_V2; |
456 | 0 | } |
457 | 0 | else { |
458 | 0 | flb_plg_info(ctx->ins, "Detected cgroups v1"); |
459 | 0 | ctx->cgroup_version = CGROUP_V1; |
460 | 0 | } |
461 | |
|
462 | 0 | mk_list_init(&ctx->items); |
463 | 0 | mk_list_init(&ctx->sysfs_items); |
464 | |
|
465 | 0 | if (ctx->scrape_interval >= 2 && ctx->scrape_on_start) { |
466 | 0 | flb_plg_info(ctx->ins, "Generating podman metrics (initial scrape)"); |
467 | 0 | if (scrape_metrics(config, ctx) == -1) { |
468 | 0 | flb_plg_error(ctx->ins, "Could not start collector for podman metrics plugin"); |
469 | 0 | flb_sds_destroy(ctx->config); |
470 | 0 | destroy_container_list(ctx); |
471 | 0 | flb_free(ctx); |
472 | 0 | return -1; |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | 0 | flb_plg_info(ctx->ins, "Generating podman metrics"); |
477 | |
|
478 | 0 | return 0; |
479 | 0 | } |
480 | | |
481 | | /* |
482 | | * Function called at plugin exit - destroy collected container data list. |
483 | | */ |
484 | | static int in_metrics_exit(void *data, struct flb_config *config) |
485 | 0 | { |
486 | 0 | struct flb_in_metrics *ctx = data; |
487 | |
|
488 | 0 | if (!ctx) { |
489 | 0 | return 0; |
490 | 0 | } |
491 | | |
492 | 0 | flb_sds_destroy(ctx->config); |
493 | 0 | destroy_container_list(ctx); |
494 | 0 | flb_free(ctx); |
495 | 0 | return 0; |
496 | 0 | } |
497 | | |
498 | | /* |
499 | | * Function called at plugin pause. |
500 | | */ |
501 | | static void in_metrics_pause(void *data, struct flb_config *config) |
502 | 0 | { |
503 | 0 | struct flb_in_metrics *ctx = data; |
504 | 0 | flb_input_collector_pause(ctx->coll_fd_runtime, ctx->ins); |
505 | 0 | } |
506 | | |
507 | | /* |
508 | | * Function called at plugin resume. |
509 | | */ |
510 | | static void in_metrics_resume(void *data, struct flb_config *config) |
511 | 0 | { |
512 | 0 | struct flb_in_metrics *ctx = data; |
513 | 0 | flb_input_collector_resume(ctx->coll_fd_runtime, ctx->ins); |
514 | 0 | } |