Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions plugins/in_podman_metrics/podman_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_s
cnt->rss = UINT64_MAX;
cnt->cpu_user = UINT64_MAX;
cnt->cpu = UINT64_MAX;
cnt->disk_read_bytes = UINT64_MAX;
cnt->disk_write_bytes = UINT64_MAX;
cnt->disk_reads = UINT64_MAX;
cnt->disk_writes = UINT64_MAX;

mk_list_init(&cnt->net_data);

Expand Down Expand Up @@ -303,6 +307,10 @@ static int create_gauge(struct flb_in_metrics *ctx, struct cmt_gauge **gauge, fl
* - container_network_receive_errors_total
* - container_network_transmit_bytes_total
* - container_network_transmit_errors_total
* - container_disk_read_bytes_total
* - container_disk_write_bytes_total
* - container_disk_reads_total
* - container_disk_writes_total
*/
static int create_counters(struct flb_in_metrics *ctx)
{
Expand All @@ -328,6 +336,14 @@ static int create_counters(struct flb_in_metrics *ctx)
DESCRIPTION_CPU_USER, NULL, cnt->cpu_user);
create_counter(ctx, &ctx->c_cpu, cnt->id, cnt->name, cnt->image_name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU,
DESCRIPTION_CPU, NULL, cnt->cpu);
create_counter(ctx, &ctx->c_disk_read_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_DISK_PREFIX, FIELDS_METRIC, COUNTER_DISK_READ_BYTES,
DESCRIPTION_DISK_READ_BYTES, NULL, cnt->disk_read_bytes);
create_counter(ctx, &ctx->c_disk_write_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_DISK_PREFIX, FIELDS_METRIC, COUNTER_DISK_WRITE_BYTES,
DESCRIPTION_DISK_WRITE_BYTES, NULL, cnt->disk_write_bytes);
create_counter(ctx, &ctx->c_disk_reads, cnt->id, cnt->name, cnt->image_name, COUNTER_DISK_PREFIX, FIELDS_METRIC, COUNTER_DISK_READS,
DESCRIPTION_DISK_READS, NULL, cnt->disk_reads);
create_counter(ctx, &ctx->c_disk_writes, cnt->id, cnt->name, cnt->image_name, COUNTER_DISK_PREFIX, FIELDS_METRIC, COUNTER_DISK_WRITES,
DESCRIPTION_DISK_WRITES, NULL, cnt->disk_writes);
mk_list_foreach_safe(inner_head, inner_tmp, &cnt->net_data)
{
iface = mk_list_entry(inner_head, struct net_iface, _head);
Expand Down Expand Up @@ -423,6 +439,10 @@ static int in_metrics_init(struct flb_input_instance *in, struct flb_config *con
ctx->c_memory_limit = NULL;
ctx->c_cpu_user = NULL;
ctx->c_cpu = NULL;
ctx->c_disk_read_bytes = NULL;
ctx->c_disk_write_bytes = NULL;
ctx->c_disk_reads = NULL;
ctx->c_disk_writes = NULL;
ctx->rx_bytes = NULL;
ctx->rx_errors = NULL;
ctx->tx_bytes = NULL;
Expand Down
25 changes: 25 additions & 0 deletions plugins/in_podman_metrics/podman_metrics_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@
#define STAT_KEY_CPU "usage_usec"
#define STAT_KEY_CPU_USER "user_usec"

/* Field tokens in cgroups v2 io.stat (per block device, summed across devices) */
#define IO_STAT_KEY_READ_BYTES "rbytes="
#define IO_STAT_KEY_WRITE_BYTES "wbytes="
#define IO_STAT_KEY_READS "rios="
#define IO_STAT_KEY_WRITES "wios="

/* Static lists of fields in counters or gauges */
#define FIELDS_METRIC (char*[3]){"id", "name", "image" }
#define FIELDS_METRIC_WITH_IFACE (char*[4]){"id", "name", "image", "interface" }
Expand All @@ -107,6 +113,7 @@
#define V2_SYSFS_FILE_CPU_STAT "cpu.stat"
#define V2_SYSFS_FILE_PIDS "cgroup.procs"
#define V2_SYSFS_FILE_PIDS_ALT "containers/cgroup.procs"
#define V2_SYSFS_FILE_IO_STAT "io.stat"

/* Values used to construct counters/gauges names and descriptions */
#define COUNTER_PREFIX "container"
Expand Down Expand Up @@ -138,6 +145,16 @@
#define COUNTER_TX_ERRORS "transmit_errors_total"
#define DESCRIPTION_TX_ERRORS "Network transmitedd errors"

#define COUNTER_DISK_PREFIX "disk"
#define COUNTER_DISK_READ_BYTES "read_bytes_total"
#define DESCRIPTION_DISK_READ_BYTES "Container block I/O bytes read"
#define COUNTER_DISK_WRITE_BYTES "write_bytes_total"
#define DESCRIPTION_DISK_WRITE_BYTES "Container block I/O bytes written"
#define COUNTER_DISK_READS "reads_total"
#define DESCRIPTION_DISK_READS "Container block I/O reads completed"
#define COUNTER_DISK_WRITES "writes_total"
#define DESCRIPTION_DISK_WRITES "Container block I/O writes completed"


struct net_iface {
flb_sds_t name;
Expand All @@ -160,6 +177,10 @@ struct container {
uint64_t cpu;
uint64_t cpu_user;
uint64_t rss;
uint64_t disk_read_bytes;
uint64_t disk_write_bytes;
uint64_t disk_reads;
uint64_t disk_writes;

struct mk_list net_data;
};
Expand Down Expand Up @@ -192,6 +213,10 @@ struct flb_in_metrics {
struct cmt_counter *rx_errors;
struct cmt_counter *tx_bytes;
struct cmt_counter *tx_errors;
struct cmt_counter *c_disk_read_bytes;
struct cmt_counter *c_disk_write_bytes;
struct cmt_counter *c_disk_reads;
struct cmt_counter *c_disk_writes;

/* cgroup version used by host */
int cgroup_version;
Expand Down
68 changes: 68 additions & 0 deletions plugins/in_podman_metrics/podman_metrics_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,73 @@ uint64_t get_data_from_sysfs(struct flb_in_metrics *ctx, flb_sds_t dir, flb_sds_
return data;
}

/*
* Read all cgroups v2 io.stat counters in a single pass and store them in cnt.
* io.stat lines look like:
* "8:0 rbytes=1024 wbytes=0 rios=2 wios=0 dbytes=0 dios=0"
* The rbytes/wbytes/rios/wios fields are summed across all block devices. On a
* missing or unreadable file (for example cgroups v1, where io.stat does not
* exist) the four counters are set to UINT64_MAX so they are treated as invalid
* and skipped, mirroring the other sysfs readers. An existing but empty io.stat
* (no I/O yet) yields 0 for each counter.
*/
void read_io_stat(struct flb_in_metrics *ctx, flb_sds_t dir, flb_sds_t name, struct container *cnt)
{
char path[SYSFS_FILE_PATH_SIZE];
FILE *fp;
char *line = NULL;
char *pos;
size_t len = 0;
int i;
struct {
const char *key;
size_t key_len;
uint64_t *total;
} fields[] = {
{ IO_STAT_KEY_READ_BYTES, sizeof(IO_STAT_KEY_READ_BYTES) - 1, &cnt->disk_read_bytes },
{ IO_STAT_KEY_WRITE_BYTES, sizeof(IO_STAT_KEY_WRITE_BYTES) - 1, &cnt->disk_write_bytes },
{ IO_STAT_KEY_READS, sizeof(IO_STAT_KEY_READS) - 1, &cnt->disk_reads },
{ IO_STAT_KEY_WRITES, sizeof(IO_STAT_KEY_WRITES) - 1, &cnt->disk_writes },
};

cnt->disk_read_bytes = UINT64_MAX;
cnt->disk_write_bytes = UINT64_MAX;
cnt->disk_reads = UINT64_MAX;
cnt->disk_writes = UINT64_MAX;

if (dir == NULL) {
return;
}

snprintf(path, sizeof(path), "%s/%s", dir, name);

fp = fopen(path, "r");
if (!fp) {
flb_plg_warn(ctx->ins, "Failed to read %s", path);
return;
}

for (i = 0; i < 4; i++) {
*fields[i].total = 0;
}

while (getline(&line, &len, fp) != -1) {
for (i = 0; i < 4; i++) {
pos = line;
while ((pos = strstr(pos, fields[i].key)) != NULL) {
pos += fields[i].key_len;
*fields[i].total += strtoull(pos, NULL, 10);
}
}
}
flb_free(line);
fclose(fp);

flb_plg_debug(ctx->ins, "%s: rbytes=%lu wbytes=%lu rios=%lu wios=%lu", path,
cnt->disk_read_bytes, cnt->disk_write_bytes,
cnt->disk_reads, cnt->disk_writes);
}

/*
* Check if container sysfs data is pressent in previously generated list of sysfs directories.
* For cgroups v1, use subsystem (directory, for example memory) to search full path.
Expand Down Expand Up @@ -367,6 +434,7 @@ int fill_counters_with_sysfs_data_v2(struct flb_in_metrics *ctx)
cnt->memory_limit = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_MEMORY_LIMIT, NULL);
cnt->cpu_user = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU_USER);
cnt->cpu = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU);
read_io_stat(ctx, path, V2_SYSFS_FILE_IO_STAT, cnt);
pid = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_PIDS, NULL);
if (!pid || pid == UINT64_MAX) {
pid = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_PIDS_ALT, NULL);
Expand Down
1 change: 1 addition & 0 deletions plugins/in_podman_metrics/podman_metrics_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ int destroy_gauge(struct flb_in_metrics *ctx, struct cmt_gauge **g);
uint64_t read_from_file(struct flb_in_metrics *ctx, flb_sds_t path);
uint64_t read_key_value_from_file(struct flb_in_metrics *ctx, flb_sds_t path, flb_sds_t key);
uint64_t get_data_from_sysfs(struct flb_in_metrics *ctx, flb_sds_t dir, flb_sds_t name, flb_sds_t key);
void read_io_stat(struct flb_in_metrics *ctx, flb_sds_t dir, flb_sds_t name, struct container *cnt);

int get_container_sysfs_subdirectory(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t subsystem, flb_sds_t *path);
int get_net_data_from_proc(struct flb_in_metrics *ctx, struct container *cnt, uint64_t pid);
Expand Down