Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

processor_metrics_selector: Implement delete by label value operation #8812

Merged
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
201 changes: 148 additions & 53 deletions plugins/processor_metrics_selector/selector.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,83 +48,138 @@ static void destroy_context(struct selector_ctx *context)
{
if (context != NULL) {
delete_metrics_rules(context);
flb_free(context->selector_pattern);
if (context->selector_pattern != NULL) {
flb_free(context->selector_pattern);
}
if (context->label_key != NULL) {
flb_sds_destroy(context->label_key);
}
if (context->label_value != NULL) {
flb_sds_destroy(context->label_value);
}
flb_free(context);
}
}

static int set_metrics_rules(struct selector_ctx *ctx, struct flb_processor_instance *p_ins)
{
flb_sds_t tmp;
const char *action;
const char *metric_name;
const char *op_type;
const char *context;
const char *label;
size_t name_len = 0;
struct mk_list *split;
struct flb_split_entry *sentry;

action = flb_processor_instance_get_property("action", p_ins);
if (action == NULL) {
ctx->action_type = SELECTOR_INCLUDE;
ctx->selector_pattern = NULL;
ctx->label_key = NULL;
ctx->label_value = NULL;

context = flb_processor_instance_get_property("context", p_ins);
if (context == NULL) {
ctx->context_type = SELECTOR_CONTEXT_FQNAME;
}
else if (strncasecmp(action, "include", 7) == 0) {
flb_plg_debug(ctx->ins, "action type INCLUDE");
ctx->action_type = SELECTOR_INCLUDE;
else if (strncasecmp(context, "metric_name", 11) == 0) {
ctx->context_type = SELECTOR_CONTEXT_FQNAME;
}
else if (strncasecmp(action, "exclude", 7) == 0) {
flb_plg_debug(ctx->ins, "action type EXCLUDE");
ctx->action_type = SELECTOR_EXCLUDE;
else if (strncasecmp(context, "delete_label_value", 18) == 0) {
ctx->context_type = SELECTOR_CONTEXT_DELETE_LABEL_VALUE;
}
else {
flb_plg_error(ctx->ins, "unknown action type '%s'", action);
flb_plg_error(ctx->ins, "unknown context '%s'", context);
delete_metrics_rules(ctx);
return -1;
}

metric_name = flb_processor_instance_get_property("metric_name", p_ins);
if (metric_name == NULL) {
flb_plg_error(ctx->ins, "metric_name is needed for selector");
return -1;
}
ctx->selector_pattern = flb_strdup(metric_name);
name_len = strlen(metric_name);
if (ctx->context_type == SELECTOR_CONTEXT_FQNAME) {
action = flb_processor_instance_get_property("action", p_ins);
if (action == NULL) {
ctx->action_type = SELECTOR_INCLUDE;
}
else if (strncasecmp(action, "include", 7) == 0) {
flb_plg_debug(ctx->ins, "action type INCLUDE");
ctx->action_type = SELECTOR_INCLUDE;
}
else if (strncasecmp(action, "exclude", 7) == 0) {
flb_plg_debug(ctx->ins, "action type EXCLUDE");
ctx->action_type = SELECTOR_EXCLUDE;
}
else {
flb_plg_error(ctx->ins, "unknown action type '%s'", action);
return -1;
}

op_type = flb_processor_instance_get_property("operation_type", p_ins);
if (op_type == NULL) {
ctx->op_type = SELECTOR_OPERATION_PREFIX;
}
else if (strncasecmp(op_type, "prefix", 6) == 0) {
flb_plg_debug(ctx->ins, "operation type PREFIX");
ctx->op_type = SELECTOR_OPERATION_PREFIX;
}
else if (strncasecmp(op_type, "substring", 9) == 0) {
flb_plg_debug(ctx->ins, "operation type SUBSTRING");
ctx->op_type = SELECTOR_OPERATION_SUBSTRING;
}
else {
flb_plg_error(ctx->ins, "unknown action type '%s'", op_type);
return -1;
}
metric_name = flb_processor_instance_get_property("metric_name", p_ins);
if (metric_name == NULL) {
flb_plg_error(ctx->ins, "metric_name is needed for selector");
return -1;
}
ctx->selector_pattern = flb_strdup(metric_name);
name_len = strlen(metric_name);

if (ctx->selector_pattern[0] == '/' && ctx->selector_pattern[name_len-1] == '/') {
/* Convert string to regex pattern for metrics */
ctx->name_regex = flb_regex_create(ctx->selector_pattern);
if (!ctx->name_regex) {
flb_plg_error(ctx->ins, "could not compile regex pattern '%s'",
ctx->selector_pattern);
op_type = flb_processor_instance_get_property("operation_type", p_ins);
if (op_type == NULL) {
ctx->op_type = SELECTOR_OPERATION_PREFIX;
}
else if (strncasecmp(op_type, "prefix", 6) == 0) {
flb_plg_debug(ctx->ins, "operation type PREFIX");
ctx->op_type = SELECTOR_OPERATION_PREFIX;
}
else if (strncasecmp(op_type, "substring", 9) == 0) {
flb_plg_debug(ctx->ins, "operation type SUBSTRING");
ctx->op_type = SELECTOR_OPERATION_SUBSTRING;
}
else {
flb_plg_error(ctx->ins, "unknown action type '%s'", op_type);
return -1;
}
ctx->op_type = SELECTOR_OPERATION_REGEX;
}

context = flb_processor_instance_get_property("context", p_ins);
if (context == NULL) {
ctx->context_type = SELECTOR_CONTEXT_FQNAME;
}
else if (strncasecmp(context, "metric_name", 11) == 0) {
ctx->context_type = SELECTOR_CONTEXT_FQNAME;
if (ctx->selector_pattern[0] == '/' && ctx->selector_pattern[name_len-1] == '/') {
/* Convert string to regex pattern for metrics */
ctx->name_regex = flb_regex_create(ctx->selector_pattern);
if (!ctx->name_regex) {
flb_plg_error(ctx->ins, "could not compile regex pattern '%s'",
ctx->selector_pattern);
return -1;
}
ctx->op_type = SELECTOR_OPERATION_REGEX;
}
}
else {
flb_plg_error(ctx->ins, "unknown context '%s'", context);
delete_metrics_rules(ctx);
return -1;
else if (ctx->context_type == SELECTOR_CONTEXT_DELETE_LABEL_VALUE) {
label = flb_processor_instance_get_property("label", p_ins);
if (label != NULL) {
split = flb_utils_split(label, ' ', 1);
if (mk_list_size(split) != 2) {
flb_plg_error(ctx->ins, "invalid value, expected key and value");
flb_utils_split_free(split);
return -1;
}

/* Get first value (label's key) */
sentry = mk_list_entry_first(split, struct flb_split_entry, _head);
tmp = flb_sds_create_len(sentry->value, sentry->len);
if (tmp == NULL) {
flb_plg_error(ctx->ins, "allocation failed for label key");
flb_utils_split_free(split);
return -1;
}
ctx->label_key = tmp;

/* Get last value (label's value) */
sentry = mk_list_entry_last(split, struct flb_split_entry, _head);
tmp = flb_sds_create_len(sentry->value, sentry->len);
if (tmp == NULL) {
flb_plg_error(ctx->ins, "allocation failed for label value");
flb_utils_split_free(split);
return -1;
}
ctx->label_value = tmp;
ctx->op_type = SELECTOR_CONTEXT_DELETE_LABEL_VALUE;

flb_utils_split_free(split);
}
}

return 0;
Expand Down Expand Up @@ -279,13 +334,48 @@ static inline int selector_metrics_process_fqname(struct cmt *cmt, struct cmt *o
return found ? SELECTOR_RET_EXCLUDE : SELECTOR_RET_KEEP;
}

static inline int selector_metrics_process_delete_label_value(struct cmt *cmt, struct cmt *out_cmt,
struct selector_ctx *ctx)
{
int ret;
int removed = FLB_FALSE;
struct cmt *filtered = NULL;

/* On processor_selector, we only process one rule in each of contexts */

filtered = cmt_create();
if (filtered == NULL) {
flb_plg_error(ctx->ins, "could not create filtered context");

return SELECTOR_FAILURE;
}

ret = cmt_filter_with_label_pair(filtered, cmt, ctx->label_key, ctx->label_value);

if (ret == 0) {
removed = FLB_TRUE;
}
else if (ret != 0) {
flb_plg_debug(ctx->ins, "not matched for a key-value pair: \"%s\",\"%s\"",
ctx->label_key, ctx->label_value);
}

cmt_cat(out_cmt, filtered);
cmt_destroy(filtered);

return removed ? SELECTOR_RET_EXCLUDE : SELECTOR_RET_KEEP;
}

/* Given a metrics context, do some select action based on the defined rules */
static inline int selector_metrics(struct cmt *cmt, struct cmt *out_cmt,
struct selector_ctx *ctx)
{
if (ctx->context_type == SELECTOR_CONTEXT_FQNAME) {
return selector_metrics_process_fqname(cmt, out_cmt, ctx);
}
else if (ctx->context_type == SELECTOR_CONTEXT_DELETE_LABEL_VALUE) {
return selector_metrics_process_delete_label_value(cmt, out_cmt, ctx);
}

return 0;
}
Expand Down Expand Up @@ -365,13 +455,18 @@ static struct flb_config_map config_map[] = {
{
FLB_CONFIG_MAP_STR, "context", NULL,
FLB_CONFIG_MAP_MULT, FLB_FALSE, 0,
"Specify matching context. Currently, metric_name is only supported."
"Specify matching context. Currently, metric_name and delete_label_value are only supported."
},
{
FLB_CONFIG_MAP_STR, "action", NULL,
0, FLB_FALSE, 0,
"Specify the action for specified metrics. INCLUDE and EXCLUDE are allowed."
},
{
FLB_CONFIG_MAP_STR, "label", NULL,
0, FLB_FALSE, 0,
"Specify a label key and value pair."
},
{
FLB_CONFIG_MAP_STR, "operation_type", NULL,
0, FLB_FALSE, 0,
Expand Down
16 changes: 10 additions & 6 deletions plugins/processor_metrics_selector/selector.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@
#define SELECTOR_NOTOUCH 1
#define SELECTOR_FAILURE 2

#define SELECTOR_OPERATION_REGEX 0
#define SELECTOR_OPERATION_PREFIX 1
#define SELECTOR_OPERATION_SUBSTRING 2
#define SELECTOR_OPERATION_REGEX 0
#define SELECTOR_OPERATION_PREFIX 1
#define SELECTOR_OPERATION_SUBSTRING 2
#define SELECTOR_OPERATION_LABEL_DELETION 3

/* context */
#define SELECTOR_CONTEXT_FQNAME 0
#define SELECTOR_CONTEXT_LABELS 1
#define SELECTOR_CONTEXT_DESC 2
#define SELECTOR_CONTEXT_FQNAME 0
#define SELECTOR_CONTEXT_LABELS 1
#define SELECTOR_CONTEXT_DESC 2
#define SELECTOR_CONTEXT_DELETE_LABEL_VALUE 3

struct selector_ctx {
struct mk_list metrics_rules;
Expand All @@ -55,6 +57,8 @@ struct selector_ctx {
int op_type;
int context_type;
char *selector_pattern;
flb_sds_t label_key;
flb_sds_t label_value;
struct flb_regex *name_regex;
struct flb_processor_instance *ins;
struct flb_config *config;
Expand Down
77 changes: 77 additions & 0 deletions tests/runtime/processor_metrics_selector.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,82 @@ void flb_test_selector_can_modify_output(void)
flb_stop(ctx);
flb_destroy(ctx);
}


void flb_test_selector_context_delete_label_value(void)
{
int ret;
flb_ctx_t *ctx;
int in_ffd;
int out_ffd;
struct flb_processor *proc;
struct flb_processor_unit *pu;
struct cfl_variant var = {
.type = CFL_VARIANT_STRING,
.data.as_string = "delete_label_value",
};
struct cfl_variant label_pair = {
.type = CFL_VARIANT_STRING,
.data.as_string = "name lib.0",
};
int got;
int n_metrics = 20;
int not_used = 0;
struct flb_lib_out_cb cb_data;

/* Prepare output callback with expected result */
cb_data.cb = cb_count_metrics_msgpack;
cb_data.data = &not_used;

ctx = flb_create();
flb_service_set(ctx,
"Flush", "0.200000000",
"Grace", "2",
NULL);

proc = flb_processor_create(ctx->config, "unit_test", NULL, 0);
TEST_CHECK(proc != NULL);

pu = flb_processor_unit_create(proc, FLB_PROCESSOR_METRICS, "metrics_selector");
TEST_CHECK(pu != NULL);
ret = flb_processor_unit_set_property(pu, "context", &var);
TEST_CHECK(ret == 0);
ret = flb_processor_unit_set_property(pu, "label", &label_pair);
TEST_CHECK(ret == 0);

/* Input */
in_ffd = flb_input(ctx, (char *) "fluentbit_metrics", NULL);
TEST_CHECK(in_ffd >= 0);
ret = flb_input_set(ctx, in_ffd, "tag", "test", NULL);
TEST_CHECK(ret == 0);
ret = flb_input_set(ctx, in_ffd, "scrape_on_start", "true", NULL);
TEST_CHECK(ret == 0);
ret = flb_input_set(ctx, in_ffd, "scrape_interval", "1", NULL);
TEST_CHECK(ret == 0);

/* set up processor */
ret = flb_input_set_processor(ctx, in_ffd, proc);
TEST_CHECK(ret == 0);

out_ffd = flb_output(ctx, (char *) "lib", &cb_data);
TEST_CHECK(out_ffd >= 0);
flb_output_set(ctx, out_ffd, "match", "test", NULL);

clear_output_num();

ret = flb_start(ctx);
TEST_CHECK(ret == 0);

flb_time_msleep(1500); /* waiting flush */

got = get_output_num();
if (!TEST_CHECK(got >= n_metrics)) {
TEST_MSG("expect: %d >= %d, got: %d < %d", got, n_metrics, got, n_metrics);
}

flb_stop(ctx);
flb_destroy(ctx);
}
#endif

/* Test list */
Expand All @@ -625,6 +701,7 @@ TEST_LIST = {
{"substring_include", flb_test_selector_substring_include},
{"substring_exclude", flb_test_selector_substring_exclude},
{"can_modify_output", flb_test_selector_can_modify_output},
{"context_delete_label_value", flb_test_selector_context_delete_label_value},
#endif
{NULL, NULL}
};
Loading