Coverage Report

Created: 2026-06-20 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}