Skip to content

Commit

Permalink
in_podman_metrics: Added image label
Browse files Browse the repository at this point in the history
Added "image" label to all container metrics - it points to
container image used by referenced container. Also, added
new unit test which checks if out-of-order fields in json
configuration file still work.

Signed-off-by: Paweł Cendrzak <[email protected]>
  • Loading branch information
pabloxxl authored and edsiper committed May 2, 2023
1 parent 43682ad commit bdcaec2
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 28 deletions.
76 changes: 52 additions & 24 deletions plugins/in_podman_metrics/podman_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ static int collect_container_data(struct flb_in_metrics *ctx)
char *buffer;
char name[CONTAINER_NAME_SIZE];
char id[CONTAINER_ID_SIZE];
char image_name[IMAGE_NAME_SIZE];
char metadata[CONTAINER_METADATA_SIZE];
char *metadata_token_start;
char *metadata_token_stop;
int metadata_token_size;

int array_id;
int r, i, j;
Expand Down Expand Up @@ -95,12 +100,33 @@ static int collect_container_data(struct flb_in_metrics *ctx)
strncpy(name, buffer + t[j].start, t[j].end - t[j].start);
name[t[j].end - t[j].start] = '\0';
flb_plg_trace(ctx->ins, "Found name %s", name);
add_container_to_list(ctx, id, name);
j++;
collected_containers++;
}
}
}
else if (sizeof(JSON_FIELD_METADATA)-1 == t[i].end - t[i].start &&
strncmp(buffer + t[i].start, JSON_FIELD_METADATA, t[i].end - t[i].start) == 0) {
token_len = t[i + 1].end - t[i + 1].start;
strncpy(metadata, buffer + t[i+1].start, t[i + 1].end - t[i + 1].start);
metadata[token_len] = '\0';

metadata_token_start = strstr(metadata, JSON_SUBFIELD_IMAGE_NAME);
if (metadata_token_start) {
metadata_token_stop = strstr(metadata_token_start + JSON_SUBFIELD_SIZE_IMAGE_NAME+1, "\\\"");
metadata_token_size = metadata_token_stop - metadata_token_start - JSON_SUBFIELD_SIZE_IMAGE_NAME;

strncpy(image_name, metadata_token_start+JSON_SUBFIELD_SIZE_IMAGE_NAME, metadata_token_size);
image_name[metadata_token_size] = '\0';

flb_plg_trace(ctx->ins, "Found image name %s", image_name);
add_container_to_list(ctx, id, name, image_name);
}
else {
flb_plg_warn(ctx->ins, "Image name was not found for %s", id);
add_container_to_list(ctx, id, name, "unknown");
}
collected_containers++;
}
}
}

Expand All @@ -110,11 +136,11 @@ static int collect_container_data(struct flb_in_metrics *ctx)
}

/*
* Create structure instance based on previously found id and name. Set all its values (like
* Create structure instance based on previously found id, name and image name. Set all its values (like
* memory or cpu to UINT64_MAX, in case it won't be found later. This function also adds this structure
* to internal list, so it can be found by iteration later on.
*/
static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t name)
static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t name, flb_sds_t image_name)
{
struct container *cnt;
cnt = flb_malloc(sizeof(struct container));
Expand All @@ -124,6 +150,7 @@ static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_s
}
cnt->id = flb_sds_create(id);
cnt->name = flb_sds_create(name);
cnt->image_name = flb_sds_create(image_name);

cnt->memory_usage = UINT64_MAX;
cnt->memory_max_usage = UINT64_MAX;
Expand Down Expand Up @@ -157,6 +184,7 @@ static int destroy_container_list(struct flb_in_metrics *ctx)

flb_sds_destroy(cnt->id);
flb_sds_destroy(cnt->name);
flb_sds_destroy(cnt->image_name);
mk_list_foreach_safe(inner_head, inner_tmp, &cnt->net_data) {
iface = mk_list_entry(inner_head, struct net_iface, _head);
flb_sds_destroy(iface->name);
Expand All @@ -179,13 +207,13 @@ static int destroy_container_list(struct flb_in_metrics *ctx)


/*
* Create counter for given metric name, using name and value as counter labels. Counters
* Create counter for given metric name, using name, image name and value as counter labels. Counters
* are created per counter name, so they are "shared" between multiple containers - counter
* name remains the same, only labels like ID are changed.
* This function creates counter only once per counter name - every next call only sets counter
* value for specific labels.
*/
static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **counter, flb_sds_t id, flb_sds_t name, flb_sds_t metric_prefix,
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,
flb_sds_t *fields, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value)
{
flb_sds_t *labels;
Expand All @@ -204,12 +232,12 @@ static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **count
}

if (interface == NULL) {
labels = (char *[]){id, name};
label_count = 2;
labels = (char *[]){id, name, image_name};
label_count = 3;
}
else {
labels = (char *[]){id, name, interface};
label_count = 3;
labels = (char *[]){id, name, image_name, interface};
label_count = 4;
}

/* if counter was not yet created, it means that this function is called for the first time per counter type */
Expand All @@ -229,13 +257,13 @@ static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **count
}

/*
* Create gauge for given metric name, using name and value as counter labels. Gauges
* Create gauge for given metric name, using name, image name and value as counter labels. Gauges
* are created per counter name, so they are "shared" between multiple containers - counter
* name remains the same, only labels like ID are changed.
* This function creates gauge only once per counter name - every next call only sets gauge
* value for specific labels.
*/
static int create_gauge(struct flb_in_metrics *ctx, struct cmt_gauge **gauge, flb_sds_t id, flb_sds_t name, flb_sds_t metric_prefix,
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,
flb_sds_t *fields, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value)
{
flb_sds_t *labels;
Expand All @@ -245,8 +273,8 @@ static int create_gauge(struct flb_in_metrics *ctx, struct cmt_gauge **gauge, fl
return -1;
}

labels = (char *[]){id, name};
label_count = 2;
labels = (char *[]){id, name, image_name};
label_count = 3;

/* if gauge was not yet created, it means that this function is called for the first time per counter type */
if (*gauge == NULL) {
Expand Down Expand Up @@ -289,28 +317,28 @@ static int create_counters(struct flb_in_metrics *ctx)
mk_list_foreach_safe(head, tmp, &ctx->items)
{
cnt = mk_list_entry(head, struct container, _head);
create_counter(ctx, &ctx->c_memory_usage, cnt->id, cnt->name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_USAGE,
create_counter(ctx, &ctx->c_memory_usage, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_USAGE,
DESCRIPTION_MEMORY_USAGE, NULL, cnt->memory_usage);
create_counter(ctx, &ctx->c_memory_max_usage, cnt->id, cnt->name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_MAX_USAGE,
create_counter(ctx, &ctx->c_memory_max_usage, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_MAX_USAGE,
DESCRIPTION_MEMORY_MAX_USAGE, NULL, cnt->memory_max_usage);
create_counter(ctx, &ctx->c_memory_limit, cnt->id, cnt->name, COUNTER_SPEC_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_LIMIT,
create_counter(ctx, &ctx->c_memory_limit, cnt->id, cnt->name, cnt->image_name, COUNTER_SPEC_MEMORY_PREFIX, FIELDS_METRIC, COUNTER_MEMORY_LIMIT,
DESCRIPTION_MEMORY_LIMIT, NULL, cnt->memory_limit);
create_gauge(ctx, &ctx->g_rss, cnt->id, cnt->name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, GAUGE_MEMORY_RSS,
create_gauge(ctx, &ctx->g_rss, cnt->id, cnt->name, cnt->image_name, COUNTER_MEMORY_PREFIX, FIELDS_METRIC, GAUGE_MEMORY_RSS,
DESCRIPTION_MEMORY_RSS, NULL, cnt->rss);
create_counter(ctx, &ctx->c_cpu_user, cnt->id, cnt->name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU_USER,
create_counter(ctx, &ctx->c_cpu_user, cnt->id, cnt->name, cnt->image_name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU_USER,
DESCRIPTION_CPU_USER, NULL, cnt->cpu_user);
create_counter(ctx, &ctx->c_cpu, cnt->id, cnt->name, COUNTER_CPU_PREFIX, FIELDS_METRIC, COUNTER_CPU,
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);
mk_list_foreach_safe(inner_head, inner_tmp, &cnt->net_data)
{
iface = mk_list_entry(inner_head, struct net_iface, _head);
create_counter(ctx, &ctx->rx_bytes, cnt->id, cnt->name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_BYTES,
create_counter(ctx, &ctx->rx_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_BYTES,
DESCRIPTION_RX_BYTES, iface->name, iface->rx_bytes);
create_counter(ctx, &ctx->rx_errors, cnt->id, cnt->name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_ERRORS,
create_counter(ctx, &ctx->rx_errors, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_RX_ERRORS,
DESCRIPTION_RX_ERRORS, iface->name, iface->rx_errors);
create_counter(ctx, &ctx->tx_bytes, cnt->id, cnt->name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_BYTES,
create_counter(ctx, &ctx->tx_bytes, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_BYTES,
DESCRIPTION_TX_BYTES, iface->name, iface->tx_bytes);
create_counter(ctx, &ctx->tx_errors, cnt->id, cnt->name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_ERRORS,
create_counter(ctx, &ctx->tx_errors, cnt->id, cnt->name, cnt->image_name, COUNTER_NETWORK_PREFIX, FIELDS_METRIC_WITH_IFACE, COUNTER_TX_ERRORS,
DESCRIPTION_TX_ERRORS, iface->name, iface->tx_errors);
}
}
Expand Down
6 changes: 4 additions & 2 deletions plugins/in_podman_metrics/podman_metrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
#include "podman_metrics_config.h"

static int collect_container_data(struct flb_in_metrics *ctx);
static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t name);
static int add_container_to_list(struct flb_in_metrics *ctx, flb_sds_t id, flb_sds_t name, flb_sds_t image_name);
static int destroy_container_list(struct flb_in_metrics *ctx);

static int create_counter(struct flb_in_metrics *ctx, struct cmt_counter **counter, flb_sds_t id, flb_sds_t name, flb_sds_t metric_prefix,
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,
flb_sds_t *fieds, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value);
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,
flb_sds_t *fields, flb_sds_t metric_name, flb_sds_t description, flb_sds_t interface, uint64_t value);
static int create_counters(struct flb_in_metrics *ctx);

static int scrape_metrics(struct flb_config *config, struct flb_in_metrics *ctx);
Expand Down
11 changes: 9 additions & 2 deletions plugins/in_podman_metrics/podman_metrics_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#define JSON_TOKENS 2048
#define CONTAINER_NAME_SIZE 50
#define CONTAINER_ID_SIZE 80
#define CONTAINER_METADATA_SIZE 512
#define IMAGE_NAME_SIZE 512
#define PID_BUFFER_SIZE 21
#define SYSFS_FILE_PATH_SIZE 512
#define PROCFS_FILE_PATH_SIZE 512
Expand All @@ -46,6 +48,10 @@

#define JSON_FIELD_NAMES "names"
#define JSON_FIELD_ID "id"
#define JSON_FIELD_METADATA "metadata"

#define JSON_SUBFIELD_IMAGE_NAME "image-name\\\":\\\""
#define JSON_SUBFIELD_SIZE_IMAGE_NAME 15

#define CGROUP_V2_PATH "cgroup.controllers"
#define CGROUP_V1 1
Expand Down Expand Up @@ -81,8 +87,8 @@
#define STAT_KEY_CPU_USER "user_usec"

/* Static lists of fields in counters or gauges */
#define FIELDS_METRIC (char*[2]){"id", "name" }
#define FIELDS_METRIC_WITH_IFACE (char*[3]){"id", "name", "interface" }
#define FIELDS_METRIC (char*[3]){"id", "name", "image" }
#define FIELDS_METRIC_WITH_IFACE (char*[4]){"id", "name", "image", "interface" }

/* Files from sysfs containing required data (cgroups v1) */
#define V1_SYSFS_FILE_MEMORY "memory.usage_in_bytes"
Expand Down Expand Up @@ -144,6 +150,7 @@ struct net_iface {
struct container {
flb_sds_t name;
flb_sds_t id;
flb_sds_t image_name;
struct mk_list _head;

uint64_t memory_usage;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 34275905 6362 0 0 0 0 0 0 34275905 6362 0 0 0 0 0 0
enp6s0: 9089298401 6228223 0 0 0 0 0 5669 173774157 2534993 0 0 0 0 0 0
wlp5s0: 2802033 11801 0 0 0 0 0 0 790512 6492 0 0 0 0 0 0
virbr0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 change: 1 addition & 0 deletions tests/runtime/data/podman/reversed/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"id":"8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9","names":["determined_mcnulty"],"image":"27941809078cc9b2802deb2b0bb6feed6c236cde01e487f200e24653533701ee","layer":"633c06ce1a553c72c4fbf12686acd5129a453f57b73385f8e7afc975fa657d86","metadata":"{\"image-id\":\"27941809078cc9b2802deb2b0bb6feed6c236cde01e487f200e24653533701ee\",\"name\":\"determined_mcnulty\",\"created-at\":1657980361,\"image-name\":\"docker.io/library/ubuntu:latest\"}","created":"2022-07-16T14:06:01.521179687Z","flags":{"MountLabel":"system_u:object_r:container_file_t:s0:c664,c969","ProcessLabel":"system_u:system_r:container_t:s0:c664,c969"}}]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
42
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
42
18 changes: 18 additions & 0 deletions tests/runtime/in_podman_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "flb_tests_runtime.h"

#define DPATH_PODMAN_REGULAR FLB_TESTS_DATA_PATH "/data/podman/regular"
#define DPATH_PODMAN_REVERSED FLB_TESTS_DATA_PATH "/data/podman/reversed"
#define DPATH_PODMAN_NO_CONFIG FLB_TESTS_DATA_PATH "/data/podman/no_config"
#define DPATH_PODMAN_GARBAGE_CONFIG FLB_TESTS_DATA_PATH "/data/podman/garbage_config"
#define DPATH_PODMAN_NO_SYSFS FLB_TESTS_DATA_PATH "/data/podman/no_sysfs"
Expand Down Expand Up @@ -103,6 +104,22 @@ void flb_test_ipm_regular() {
do_destroy(ctx);
}

void flb_test_ipm_reversed() {
flb_ctx_t *ctx = flb_create();
do_create(ctx,
"podman_metrics",
"path.config", DPATH_PODMAN_REVERSED "/config.json",
"scrape_on_start", "true",
"path.sysfs", DPATH_PODMAN_REVERSED,
"path.procfs", DPATH_PODMAN_REVERSED,
NULL);
TEST_CHECK(flb_start(ctx) == 0);
sleep(1);
TEST_CHECK(check_metric(ctx, "usage_bytes") == 0);
TEST_CHECK(check_metric(ctx, "receive_bytes_total") == 0);
do_destroy(ctx);
}

void flb_test_ipm_garbage_config() {
flb_ctx_t *ctx = flb_create();
do_create(ctx,
Expand Down Expand Up @@ -195,6 +212,7 @@ void flb_test_ipm_cgroupv2() {

TEST_LIST = {
{"regular", flb_test_ipm_regular},
{"reversed", flb_test_ipm_reversed},
{"no_config", flb_test_ipm_no_config},
{"garbage_config", flb_test_ipm_garbage_config},
{"no_sysfs_data", flb_test_ipm_no_sysfs},
Expand Down

0 comments on commit bdcaec2

Please sign in to comment.