diff --git a/buildtools/el7/install-dependencies.sh b/buildtools/el7/install-dependencies.sh index 29344c4e5..f82d2c342 100755 --- a/buildtools/el7/install-dependencies.sh +++ b/buildtools/el7/install-dependencies.sh @@ -54,6 +54,7 @@ DEPS_BUILD=" DEPS_CIRC=" circonus-platform-lua-luasocket circonus-developer-mtevbusted + circonus-platform-library-fmt " echo "Installing buildenv and reconnoiter deps" diff --git a/buildtools/u2004/install-dependencies.sh b/buildtools/u2004/install-dependencies.sh index e9f7e24a7..27ffec180 100755 --- a/buildtools/u2004/install-dependencies.sh +++ b/buildtools/u2004/install-dependencies.sh @@ -41,6 +41,7 @@ DEPS_CIRC=" circonus-platform-library-apr-util circonus-platform-library-curl circonus-platform-library-flatcc + circonus-platform-library-fmt circonus-platform-library-grpc circonus-platform-library-jemalloc circonus-platform-library-jlog diff --git a/configure.in b/configure.in index b0eb443a1..bdc37d99e 100755 --- a/configure.in +++ b/configure.in @@ -400,6 +400,17 @@ AC_TRY_LINK([ [ AC_MSG_ERROR([failed]) ]) PTOOLSLIBS="$LIBS" LIBS="$old_LIBS" +AC_CHECK_HEADER(fmt/core.h, [], [AC_MSG_ERROR(*** fmtlib (headers) required ***)]) +SAVED_LIBS=$LIBS +LIBS="-lfmt" +AC_LINK_IFELSE( + [ AC_LANG_PROGRAM( + [ #include ], + [ auto cant_discard_this_da_na_na_na = fmt::format("{}", 10); ] + )], , + [ AC_MSG_ERROR([ "Could not find fmtlib" ]) ] +) +LIBS="$SAVED_LIBS" AC_LANG_POP([C++]) AC_CHECK_HEADERS(gcrypt.h) diff --git a/src/libnoit.h b/src/libnoit.h index 4f0523cdc..dc1bf3415 100644 --- a/src/libnoit.h +++ b/src/libnoit.h @@ -31,7 +31,15 @@ #ifndef LIBNOIT_H #define LIBNOIT_H +#ifdef __cplusplus +extern "C" { +#endif + API_EXPORT(void) libnoit_init_globals(void); + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/modules/histogram.c b/src/modules/histogram.c index a36e27673..d8f03dff9 100644 --- a/src/modules/histogram.c +++ b/src/modules/histogram.c @@ -231,7 +231,7 @@ log_histo(noit_check_t *check, uint64_t whence_s, mtevL(noit_error, "malloc(%d) failed\n", (int)est); goto cleanup; } - enc_est = ((est + 2)/3)*4; + enc_est = mtev_b64_encode_len(est); hist_encode = malloc(enc_est); if(!hist_encode) { mtevL(noit_error, "malloc(%d) failed\n", (int)enc_est); @@ -676,7 +676,7 @@ histogram_stats_populate_xml_impl(void *closure, xmlNodePtr doc, noit_check_t *c if(!hist_serial) { mtevL(noit_error, "malloc(%d) failed\n", (int)est); } else { - ssize_t enc_est = ((est + 2)/3)*4 + 1; + ssize_t enc_est = mtev_b64_encode_len(est) + 1; hist_encode = malloc(enc_est+1); if(!hist_encode) { mtevL(noit_error, "malloc(%d) failed\n", (int)enc_est); @@ -723,7 +723,7 @@ histogram_stats_populate_json_impl(void *closure, struct mtev_json_object *doc, if(!hist_serial) { mtevL(noit_error, "malloc(%d) failed\n", (int)est); } else { - ssize_t enc_est = ((est + 2)/3)*4; + ssize_t enc_est = mtev_b64_encode_len(est); hist_encode = malloc(enc_est); if(!hist_encode) { mtevL(noit_error, "malloc(%d) failed\n", (int)enc_est); diff --git a/src/noit_check_log_helpers.c b/src/noit_check_log_helpers.c index 4cd37d9ff..5220b7a0c 100644 --- a/src/noit_check_log_helpers.c +++ b/src/noit_check_log_helpers.c @@ -99,8 +99,7 @@ noit_check_log_bundle_compress_b64(noit_compression_type_t ctype, } /* Encode */ - // Problems with the calculation? - initial_dlen = ((dlen + 2) / 3 * 4); + initial_dlen = mtev_b64_encode_len(dlen); b64buff = malloc(initial_dlen); if (!b64buff) { free(compbuff); @@ -130,7 +129,7 @@ noit_check_log_bundle_decompress_b64(noit_compression_type_t ctype, char *compbuff, *rawbuff; /* Decode */ - initial_dlen = (((len_in + 3) / 4) * 3); + initial_dlen = mtev_b64_max_decode_len(len_in); compbuff = malloc(initial_dlen); if (!compbuff) return -1; dlen = mtev_b64_decode((char *)buf_in, len_in, diff --git a/src/noit_filters.c b/src/noit_filters.c index ba3b47396..6592eb0bf 100644 --- a/src/noit_filters.c +++ b/src/noit_filters.c @@ -39,11 +39,12 @@ #include -#include -#include -#include +#include #include #include +#include +#include +#include #include "noit_mtev_bridge.h" #include "noit_check.h" @@ -644,9 +645,9 @@ noit_apply_filterrule(mtev_hash_table *m, return mtev_false; } static mtev_boolean -noit_apply_filterrule_metric(filterrule_t *r, - const char *subj, int subj_len, - noit_metric_tagset_t *stset, noit_metric_tagset_t *mtset) { +noit_apply_filterrule_metric(filterrule_t *r, const char *subj, int subj_len, + noit_metric_tagset_t *stset, + noit_metric_tagset_t *mtset) { int rc, ovector[30]; char canonicalcheck[MAX_METRIC_TAGGED_NAME]; canonicalcheck[0] = '\0'; @@ -774,27 +775,32 @@ noit_apply_filterset(const char *filterset, const char *local_metric_name = noit_metric_get_full_metric_name(metric); mtev_gettimeofday(&now, NULL); - char encoded_nametag[NOIT_TAG_MAX_PAIR_LEN+1]; - char decoded_nametag[NOIT_TAG_MAX_PAIR_LEN+1]; - noit_metric_tag_t stags[MAX_TAGS], mtags[MAX_TAGS]; - noit_metric_tagset_t stset = { .tags = stags, .tag_count = MAX_TAGS }; - noit_metric_tagset_t mtset = { .tags = mtags, .tag_count = MAX_TAGS }; + noit_metric_tagset_t stset, mtset; + noit_metric_tagset_init(&stset, 0, 0); + stset.tags = calloc((MAX_TAGS + 1), sizeof(noit_metric_tag_t)); + stset.tag_count = MAX_TAGS + 1; + noit_metric_tagset_init(&mtset, 0, 0); + mtset.tags = calloc(MAX_TAGS, sizeof(noit_metric_tag_t)); + mtset.tag_count = MAX_TAGS; int mlen = noit_metric_parse_tags(local_metric_name, strlen(metric->metric_name), &stset, &mtset); if(mlen < 0) { stset.tag_count = mtset.tag_count = 0; mlen = strlen(local_metric_name); } - if(stset.tag_count < MAX_TAGS-1) { - /* add __name */ - snprintf(decoded_nametag, sizeof(decoded_nametag), "__name%c%.*s", - NOIT_TAG_DECODED_SEPARATOR, mlen, local_metric_name); - size_t nlen = noit_metric_tagset_encode_tag(encoded_nametag, sizeof(encoded_nametag), - decoded_nametag, strlen(decoded_nametag)); - stset.tags[stset.tag_count].category_size = 7; - stset.tags[stset.tag_count].total_size = nlen; - stset.tags[stset.tag_count].tag = encoded_nametag; - stset.tag_count++; - } + + // add __name tag to stream tags + mtev_dyn_buffer_t dbuff; + mtev_dyn_buffer_init(&dbuff); + const size_t max_encoded_len = mtev_b64_encode_len(NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); + mtev_dyn_buffer_ensure(&dbuff, max_encoded_len); + mtev_dyn_buffer_add_printf(&dbuff, "__name%c%.*s", NOIT_TAG_DECODED_SEPARATOR, + mlen, local_metric_name); + const size_t nlen = noit_metric_tagset_encode_tag( + (char *)mtev_dyn_buffer_data(&dbuff), max_encoded_len, + (char *)mtev_dyn_buffer_data(&dbuff), mtev_dyn_buffer_used(&dbuff)); + noit_metric_add_implicit_tags_to_tagset((char *)mtev_dyn_buffer_data(&dbuff), + nlen, &stset, NULL); + bool mt_modified = false; int mt_tag_start = mtset.tag_count; char *expanded_metric_name = NULL; @@ -819,7 +825,8 @@ noit_apply_filterset(const char *filterset, need_target = !MATCHES(target, check->target); need_module = !MATCHES(module, check->module); need_name = !MATCHES(name, check->name); - need_metric = !noit_apply_filterrule_metric(r, metric->metric_name, mlen, &stset, &mtset); + need_metric = !noit_apply_filterrule_metric(r, metric->metric_name, mlen, + &stset, &mtset); if(!need_target && !need_module && !need_name && !need_metric) { if(r->type == NOIT_FILTER_SKIPTO) { @@ -922,14 +929,20 @@ noit_apply_filterset(const char *filterset, break; } } + mtev_dyn_buffer_destroy(&dbuff); noit_filter_filterset_free(fs); if(!ret) ck_pr_inc_32(&fs->denies); + noit_metric_tagset_cleanup(&stset); + noit_metric_tagset_cleanup(&mtset); return ret; } UNLOCKFS(); if (mt_modified) { noit_update_metric_name(expanded_metric_name, &mtset, mt_tag_start, metric); } + mtev_dyn_buffer_destroy(&dbuff); + noit_metric_tagset_cleanup(&stset); + noit_metric_tagset_cleanup(&mtset); return mtev_false; } diff --git a/src/noit_message_decoder.c b/src/noit_message_decoder.c index 644bf1bb7..fe12a60d9 100644 --- a/src/noit_message_decoder.c +++ b/src/noit_message_decoder.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -421,9 +422,9 @@ noit_metric_tags_count(const char *str, size_t strlen) { return rval; } -const char * -noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, - noit_metric_tag_t *output, mtev_boolean *toolong) { +const char *parse_metric_tag(const char *const tagnm, const size_t tagnmlen, + noit_metric_tag_t *output, mtev_boolean *toolong, + const size_t max_tag_length) { size_t colon_pos = 0; size_t cur_size = 0; *toolong = mtev_false; @@ -456,8 +457,8 @@ noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, /* make sure we covered everything */ if(colon_pos == 0) return 0; output->total_size = cur_size; - /* tag category and name must combined be <= NOIT_TAG_MAX_PAIR_LEN */ - if(cur_size > NOIT_TAG_MAX_PAIR_LEN) { + /* tag category and name must combined be <= max_tag_length */ + if (cur_size > max_tag_length) { *toolong = mtev_true; return tagnm + cur_size; } @@ -466,15 +467,39 @@ noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, return tagnm + cur_size; } -static int -tag_canonical_size(noit_metric_tag_t *tag) { - int len; - char dbuff[NOIT_TAG_MAX_PAIR_LEN]; - len = noit_metric_tagset_decode_tag(dbuff, sizeof(dbuff), tag->tag, tag->total_size); - if(len < 0) return 0; - len = noit_metric_tagset_encode_tag(dbuff, sizeof(dbuff), dbuff, len); - if(len < 0) return 0; - return len; +const char *noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, + noit_metric_tag_t *output, + mtev_boolean *toolong) { + return parse_metric_tag(tagnm, tagnmlen, output, toolong, + NOIT_TAG_MAX_PAIR_LEN); +} + +const char *noit_metric_tags_parse_one_implicit(const char *const tagnm, const size_t tagnmlen, + noit_metric_tag_t *output, + mtev_boolean *toolong) { + return parse_metric_tag(tagnm, tagnmlen, output, toolong, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); +} + +static int tag_canonical_size(noit_metric_tag_t *tag) { + mtev_dyn_buffer_t dbuff; + mtev_dyn_buffer_init(&dbuff); + const size_t max_ensured_len = tag->total_size + 1; //+1 for colon added to cat-only tags + mtev_dyn_buffer_ensure(&dbuff, max_ensured_len); + int len = + noit_metric_tagset_decode_tag((char *)mtev_dyn_buffer_data(&dbuff), + max_ensured_len, tag->tag, tag->total_size); + if (len >= 0) { + len = noit_metric_tagset_encode_tag( + (char *)mtev_dyn_buffer_data(&dbuff), max_ensured_len, + (char *)mtev_dyn_buffer_data(&dbuff), len); + if (len >= 0) { + mtev_dyn_buffer_destroy(&dbuff); + return len; + } + } + mtev_dyn_buffer_destroy(&dbuff); + return 0; } size_t @@ -586,46 +611,61 @@ noit_metric_tags_parse(const char *tagnm, size_t tagnmlen, return noit_metric_tags_parse_with_context(tagnm, tagnmlen, tags, tag_count, canonical_size_out, NULL); } -ssize_t -noit_metric_tags_canonical(const noit_metric_tag_t *tags, - size_t tag_count, char *tagnm, size_t tagnmlen, - mtev_boolean already_decoded) { - char dbuff[NOIT_TAG_MAX_PAIR_LEN]; +ssize_t noit_metric_tags_canonical(const noit_metric_tag_t *tags, + size_t tag_count, char *tagnm, + size_t tagnmlen, + mtev_boolean already_decoded) { if(!tag_count) return 0; + mtev_dyn_buffer_t dbuff; + mtev_dyn_buffer_init(&dbuff); + const size_t max_decode_len = + already_decoded ? tagnmlen : mtev_b64_max_decode_len(tagnmlen) + 1; + const size_t max_ensured_len = mtev_b64_encode_len(max_decode_len); + mtev_dyn_buffer_ensure(&dbuff, max_ensured_len); + size_t rval = 0; while(tag_count > 0) { int dlen; if(already_decoded) { - dlen = noit_metric_tagset_encode_tag(dbuff, sizeof(dbuff), tags->tag, tags->total_size); - if(dlen < 0) return -1; + dlen = noit_metric_tagset_encode_tag((char *)mtev_dyn_buffer_data(&dbuff), + max_ensured_len, tags->tag, + tags->total_size); } else { - dlen = noit_metric_tagset_decode_tag(dbuff, sizeof(dbuff), tags->tag, tags->total_size); - if(dlen < 0) return -1; - dlen = noit_metric_tagset_encode_tag(dbuff, sizeof(dbuff), dbuff, dlen); - if(dlen < 0) return -1; + dlen = noit_metric_tagset_decode_tag((char *)mtev_dyn_buffer_data(&dbuff), + max_ensured_len, tags->tag, + tags->total_size); + if (dlen >= 0) { + dlen = noit_metric_tagset_encode_tag( + (char *)mtev_dyn_buffer_data(&dbuff), max_ensured_len, + (char *)mtev_dyn_buffer_data(&dbuff), dlen); + } } - if(tagnmlen < dlen) return -1; - memcpy(tagnm, dbuff, dlen); + if (dlen < 0 || tagnmlen < dlen) { + mtev_dyn_buffer_destroy(&dbuff); + return -1; + } + memcpy(tagnm, (char *)mtev_dyn_buffer_data(&dbuff), dlen); tagnm += dlen; tagnmlen -= dlen; rval += dlen; tags++; tag_count--; if(tag_count > 0) { - if (tagnmlen <= 0) return -1; + if (tagnmlen <= 0) { + mtev_dyn_buffer_destroy(&dbuff); + return -1; + } *tagnm++ = ','; rval++; tagnmlen--; } } + mtev_dyn_buffer_destroy(&dbuff); return rval; } -char * -noit_metric_tagset_from_tags(noit_metric_tagset_t *lookup, - noit_metric_tag_t *tags, - size_t tag_count, - size_t canonical_size) { +char *get_canonical_name(noit_metric_tag_t *tags, size_t tag_count, + size_t canonical_size) { /* the canonical representation does not include a trailing NULL, but we make room for one * anyway... helps our display logic. */ char *canonical = malloc(canonical_size + 1); @@ -660,8 +700,8 @@ noit_metric_tagset_init_with_context(noit_metric_tagset_t *lookup, free((void *) tags); return -1; } - lookup->tags = realloc(tags, tag_count * sizeof(noit_metric_tag_t)); - lookup->tag_count = tag_count; + lookup->tags = realloc(tags, parsed_tag_count * sizeof(noit_metric_tag_t)); + lookup->tag_count = parsed_tag_count; lookup->canonical_size = canonical_size; return 0; } @@ -702,14 +742,14 @@ noit_metric_tagset_builder_clean(noit_metric_tagset_builder_t *builder) { builder->tag_count = 0; } -mtev_boolean -noit_metric_tagset_builder_add_many(noit_metric_tagset_builder_t *builder, - const char *tagstr, size_t tagstr_len) { +mtev_boolean add_tags_to_tagset_builder(noit_metric_tagset_builder_t *builder, + const char *tagstr, size_t tagstr_len, + const size_t max_tag_length) { if(builder->tag_count < 0) return mtev_false; noit_metric_tag_t tag; while(tagstr_len > 0) { mtev_boolean toolong = mtev_false; - const char *next = noit_metric_tags_parse_one(tagstr, tagstr_len, &tag, &toolong); + const char *next = parse_metric_tag(tagstr, tagstr_len, &tag, &toolong, max_tag_length); if(toolong) { /* do nothing at all, the tag must be dropped */ } else if(next && (tag.total_size == tagstr_len || *next == ',')) { @@ -735,26 +775,33 @@ noit_metric_tagset_builder_add_many(noit_metric_tagset_builder_t *builder, return mtev_true; } +mtev_boolean +noit_metric_tagset_builder_add_many(noit_metric_tagset_builder_t *builder, + const char *tagstr, size_t tagstr_len) { + return add_tags_to_tagset_builder(builder, tagstr, tagstr_len, + NOIT_TAG_MAX_PAIR_LEN); +} + +mtev_boolean +noit_metric_tagset_builder_add_many_implicit( + noit_metric_tagset_builder_t *builder, const char *tagstr, + size_t tagstr_len) { + return add_tags_to_tagset_builder(builder, tagstr, tagstr_len, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); +} + mtev_boolean noit_metric_tagset_builder_add_one(noit_metric_tagset_builder_t *builder, const char *tagstr, size_t tagstr_len) { - if(builder->tag_count < 0) return mtev_false; - noit_metric_tag_t tag; - mtev_boolean toolong = mtev_false; - if(!noit_metric_tags_parse_one(tagstr, tagstr_len, &tag, &toolong) || tag.total_size != tagstr_len) { - noit_metric_tagset_builder_clean(builder); - builder->tag_count = -1; - return mtev_false; - } - if(toolong) return mtev_true; - noit_metric_tagset_builder_el_t *el = - (noit_metric_tagset_builder_el_t *) calloc(1, sizeof(noit_metric_tagset_builder_el_t)); - el->tag = tag; - el->next = builder->list; - builder->list = el; - builder->sum_tag_size += tag.total_size; - builder->tag_count++; - return mtev_true; + return add_tags_to_tagset_builder(builder, tagstr, tagstr_len, + NOIT_TAG_MAX_PAIR_LEN); +} + +mtev_boolean +noit_metric_tagset_builder_add_one_implicit( + noit_metric_tagset_builder_t *builder, const char *tagstr, size_t tagstr_len) { + return add_tags_to_tagset_builder(builder, tagstr, tagstr_len, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); } mtev_boolean @@ -765,8 +812,15 @@ noit_metric_tagset_builder_end(noit_metric_tagset_builder_t *builder, } mtev_boolean success = mtev_true; - if(out) { - out->tags = (noit_metric_tag_t *) realloc(out->tags, (out->tag_count + builder->tag_count) * sizeof(noit_metric_tag_t)); + if (out && builder) { + if (out->tags) { + out->tags = (noit_metric_tag_t *)realloc( + out->tags, + (out->tag_count + builder->tag_count) * sizeof(noit_metric_tag_t)); + } else { + out->tags = (noit_metric_tag_t *)calloc( + out->tag_count + builder->tag_count, sizeof(noit_metric_tag_t)); + } size_t tag_index = out->tag_count; noit_metric_tagset_builder_el_t *iter = builder->list; while (iter) { @@ -780,7 +834,7 @@ noit_metric_tagset_builder_end(noit_metric_tagset_builder_t *builder, if(builder->tag_count != tag_index) out->tags = (noit_metric_tag_t *) realloc((void *)out->tags, out->tag_count * sizeof(noit_metric_tag_t)); if(canon) { - *canon = noit_metric_tagset_from_tags(out, out->tags, out->tag_count, canonical_size); + *canon = get_canonical_name(out->tags, out->tag_count, canonical_size); if(*canon == NULL) success = mtev_false; } } diff --git a/src/noit_metric.c b/src/noit_metric.c index 523e87501..847483ad1 100644 --- a/src/noit_metric.c +++ b/src/noit_metric.c @@ -344,15 +344,10 @@ noit_metric_tagset_is_taggable_value(const char *val, size_t len) noit_metric_tagset_is_taggable_part(val, len, noit_metric_tagset_is_taggable_value_char); } -static inline ssize_t -noit_metric_tagset_encode_tag_ex(char *encoded_tag, size_t max_len, - const char *decoded_tag, size_t decoded_len, - mtev_boolean for_search, - noit_metric_encode_type_t left, - noit_metric_encode_type_t right) -{ - char scratch[NOIT_TAG_MAX_PAIR_LEN+1]; - if(max_len > sizeof(scratch)) return -1; +static inline ssize_t noit_metric_tagset_encode_tag_ex( + char *encoded_tag, const size_t max_len, const char *decoded_tag, + size_t decoded_len, mtev_boolean for_search, noit_metric_encode_type_t left, + noit_metric_encode_type_t right) { int i = 0, sepcnt = -1; if(decoded_len < 1) return -2; for(i=0; i max_len) { + if (first_part_len + second_part_len + 1 > max_len) return -4; - } - char *cp = scratch; + + mtev_dyn_buffer_t scratch; + mtev_dyn_buffer_init(&scratch); + mtev_dyn_buffer_ensure(&scratch, max_len); + char *scratch_front = (char *)mtev_dyn_buffer_data(&scratch); + char *cp = scratch_front; if(first_part_needs_b64) { *cp++ = 'b'; *cp++ = left; - int len = mtev_b64_encode((unsigned char *)decoded_tag, sepcnt, - cp, sizeof(scratch) - (cp - scratch)); + int len = mtev_b64_encode((unsigned char *)decoded_tag, sepcnt, cp, + max_len - (cp - scratch_front)); if(len <= 0) { + mtev_dyn_buffer_destroy(&scratch); return -5; } cp += len; @@ -408,8 +408,10 @@ noit_metric_tagset_encode_tag_ex(char *encoded_tag, size_t max_len, *cp++ = 'b'; *cp++ = right; int len = mtev_b64_encode((unsigned char *)decoded_tag + sepcnt + 1, - decoded_len - sepcnt - 1, cp, sizeof(scratch) - (cp - scratch)); - if(len <= 0) { + decoded_len - sepcnt - 1, cp, + max_len - (cp - scratch_front)); + if (len <= 0) { + mtev_dyn_buffer_destroy(&scratch); return -6; } cp += len; @@ -418,11 +420,12 @@ noit_metric_tagset_encode_tag_ex(char *encoded_tag, size_t max_len, memcpy(cp, decoded_tag + sepcnt + 1, decoded_len - sepcnt - 1); cp += decoded_len - sepcnt - 1; } - memcpy(encoded_tag, scratch, cp - scratch); - if(cp-scratch < max_len) { - encoded_tag[cp-scratch] = '\0'; + memcpy(encoded_tag, scratch_front, cp - scratch_front); + if (cp - scratch_front < max_len) { + encoded_tag[cp - scratch_front] = '\0'; } - return cp - scratch; + mtev_dyn_buffer_destroy(&scratch); + return cp - scratch_front; } ssize_t noit_metric_tagset_encode_tag(char *encoded_tag, size_t max_len, const char *decoded_tag, size_t decoded_len) @@ -769,7 +772,7 @@ noit_metric_canonicalize_ex(const char *input, size_t input_len, char *output, s struct tag_replacements repl = { .used = 0 }; noit_metric_tag_t stags[MAX_TAGS], mtags[MAX_TAGS]; int n_stags = 0, n_mtags = 0; - char buff[MAX_METRIC_TAGGED_NAME]; + char buff[MAX_METRIC_TAGGED_NAME] = {'\0'}; if(output_len < input_len) return -1; if(input != output) memcpy(output, input, input_len); @@ -850,6 +853,15 @@ noit_metric_get_full_metric_name(metric_t *m) { return m->expanded_metric_name ? m->expanded_metric_name : m->metric_name; } +bool noit_metric_add_implicit_tags_to_tagset(const char *value, size_t length, + noit_metric_tagset_t *out, + char **canonical) { + noit_metric_tagset_builder_t builder; + noit_metric_tagset_builder_start(&builder); + noit_metric_tagset_builder_add_many_implicit(&builder, value, length); + return noit_metric_tagset_builder_end(&builder, out, canonical); +} + noit_metric_tagset_context_t * noit_metric_tagset_context_alloc(void) { noit_metric_tagset_context_t *ctx = (noit_metric_tagset_context_t *)malloc(sizeof(*ctx)); diff --git a/src/noit_metric.h b/src/noit_metric.h index 32dbdb394..b8512561a 100644 --- a/src/noit_metric.h +++ b/src/noit_metric.h @@ -105,6 +105,9 @@ typedef enum { #define NOIT_TAG_MAX_CAT_LEN 254 #define NOIT_TAG_DECODED_SEPARATOR 0x1f +static const size_t NOIT_IMPLICIT_TAG_MAX_PAIR_LEN = + MAX_METRIC_TAGGED_NAME + sizeof("__name:") - 1; + typedef struct { uint16_t total_size; uint8_t category_size; @@ -233,12 +236,19 @@ API_EXPORT(mtev_boolean) const char *tagset, size_t tagstr_len); API_EXPORT(mtev_boolean) - noit_metric_tagset_builder_add_one(noit_metric_tagset_builder_t *builder, - const char *tagset, - size_t tagstr_len); + noit_metric_tagset_builder_add_many_implicit(noit_metric_tagset_builder_t *builder, + const char *tagset, + size_t tagstr_len); +API_EXPORT(mtev_boolean) +noit_metric_tagset_builder_add_one(noit_metric_tagset_builder_t *builder, + const char *tagset, size_t tagstr_len); API_EXPORT(mtev_boolean) - noit_metric_tagset_builder_end(noit_metric_tagset_builder_t *builder, noit_metric_tagset_t *out, - char **canonical); +noit_metric_tagset_builder_add_one_implicit( + noit_metric_tagset_builder_t *builder, const char *tagset, + size_t tagstr_len); +API_EXPORT(mtev_boolean) +noit_metric_tagset_builder_end(noit_metric_tagset_builder_t *builder, + noit_metric_tagset_t *out, char **canonical); API_EXPORT(ssize_t) noit_metric_tags_canonical(const noit_metric_tag_t *tags, @@ -271,15 +281,26 @@ MTEV_HOOK_PROTO(noit_metric_tagset_fixup, (void *closure, noit_metric_tagset_class_t cls, noit_metric_tagset_t *tagset)) API_EXPORT(const char *) - noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, - noit_metric_tag_t *output, mtev_boolean *toolong); +noit_metric_tags_parse_one(const char *tagnm, size_t tagnmlen, + noit_metric_tag_t *output, mtev_boolean *toolong); + +API_EXPORT(const char *) +noit_metric_tags_parse_one_implicit(const char *const tagnm, + const size_t tagnmlen, + noit_metric_tag_t *output, + mtev_boolean *toolong); API_EXPORT(metric_t *) noit_metric_alloc(void); API_EXPORT(const char *) noit_metric_get_full_metric_name(metric_t *m); -API_EXPORT(noit_metric_tagset_context_t *) + API_EXPORT(bool) + noit_metric_add_implicit_tags_to_tagset(const char *value, size_t length, + noit_metric_tagset_t *out, + char **canonical); + + API_EXPORT(noit_metric_tagset_context_t *) noit_metric_tagset_context_alloc(void); API_EXPORT(void) diff --git a/src/noit_metric_tag_search.c b/src/noit_metric_tag_search.c index da3ab29df..0e465e240 100644 --- a/src/noit_metric_tag_search.c +++ b/src/noit_metric_tag_search.c @@ -1325,24 +1325,21 @@ noit_metric_tag_search_evaluate_against_metric_id(const noit_metric_tag_search_a const noit_metric_id_t *id) { mtev_memory_begin(); -#define MKTAGSETCOPY(name) \ - noit_metric_tag_t name##_tags[MAX_TAGS]; \ - memcpy(&name##_tags, name.tags, name.tag_count * sizeof(noit_metric_tag_t)); \ +#define MKTAGSETCOPY(name) \ + noit_metric_tag_t *name##_tags = (noit_metric_tag_t *)calloc(name.tag_count + 1, sizeof(noit_metric_tag_t)); \ + memcpy(name##_tags, name.tags, name.tag_count * sizeof(noit_metric_tag_t)); \ name.tags = name##_tags // setup check tags noit_metric_tagset_t tagset_check = id->check; - // Add in extra tags: __uuid - if (tagset_check.tag_count > MAX_TAGS - 1) { - mtev_memory_end(); - return 0; - } MKTAGSETCOPY(tagset_check); - char uuid_str[13 + UUID_STR_LEN + 1]; - strcpy(uuid_str, "__check_uuid:"); - mtev_uuid_unparse_lower(id->id, uuid_str + 13); - noit_metric_tag_t uuid_tag = { .tag = uuid_str, .total_size = strlen(uuid_str), .category_size = 13 }; - tagset_check.tags[tagset_check.tag_count++] = uuid_tag; + char check_uuid_str[sizeof("__check_uuid:") + UUID_PRINTABLE_STRING_LENGTH]; + const size_t uuid_index = + snprintf(check_uuid_str, sizeof(check_uuid_str), "__check_uuid:"); + mtev_uuid_unparse_lower(id->id, check_uuid_str + uuid_index); + noit_metric_add_implicit_tags_to_tagset( + check_uuid_str, sizeof(check_uuid_str), &tagset_check, + NULL); if(noit_metric_tagset_fixup_hook_invoke(NOIT_METRIC_TAGSET_CHECK, &tagset_check) == MTEV_HOOK_ABORT) { mtev_memory_end(); return mtev_false; @@ -1350,16 +1347,12 @@ noit_metric_tag_search_evaluate_against_metric_id(const noit_metric_tag_search_a // setup stream tags noit_metric_tagset_t tagset_stream = id->stream; - // Add in extra tags: __name - if (tagset_stream.tag_count > MAX_TAGS - 1) { - mtev_memory_end(); - return 0; - } MKTAGSETCOPY(tagset_stream); - char name_str[NOIT_TAG_MAX_PAIR_LEN + 1]; + char name_str[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN]; snprintf(name_str, sizeof(name_str), "__name:%.*s", id->name_len, id->name); - noit_metric_tag_t name_tag = { .tag = name_str, .total_size = strlen(name_str), .category_size = 7 }; - tagset_stream.tags[tagset_stream.tag_count++] = name_tag; + noit_metric_add_implicit_tags_to_tagset( + name_str, strlen(name_str), &tagset_stream, + NULL); if(noit_metric_tagset_fixup_hook_invoke(NOIT_METRIC_TAGSET_STREAM, &tagset_stream) == MTEV_HOOK_ABORT) { mtev_memory_end(); return mtev_false; @@ -1373,8 +1366,13 @@ noit_metric_tag_search_evaluate_against_metric_id(const noit_metric_tag_search_a return mtev_false; } - const noit_metric_tagset_t *tagsets[3] = { &tagset_check, &tagset_stream, &tagset_measurement }; - mtev_boolean ok = noit_metric_tag_search_evaluate_against_tags_multi(search, tagsets, 3); + const noit_metric_tagset_t *tagsets[3] = {&tagset_check, &tagset_stream, + &tagset_measurement}; + const mtev_boolean ok = + noit_metric_tag_search_evaluate_against_tags_multi(search, tagsets, 3); + free(tagset_check.tags); + free(tagset_stream.tags); + free(tagset_measurement.tags); mtev_memory_end(); return ok; } diff --git a/test/Makefile.in b/test/Makefile.in index f17b87f8b..67483e076 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -46,8 +46,8 @@ check-lmdb: all # This stuff if all cert stuff to make testing the daemons easier -test_tags: test_tags.c - $(CC) -g -o test_tags -I../src $(CPPFLAGS) $(CFLAGS) -I$(MTEV_INCLUDEDIR) test_tags.c -L../src -lnoit $(LDFLAGS) $(LMTEV) +test_tags: test_tags.cpp + $(CXX) -g -o test_tags -I../src $(CPPFLAGS) $(CXXFLAGS) -I$(MTEV_INCLUDEDIR) test_tags.cpp -L../src -lnoit -lfmt $(LDFLAGS) $(LMTEV) others: $(MAKE) -C ../src tests diff --git a/test/test_tags.c b/test/test_tags.cpp similarity index 79% rename from test/test_tags.c rename to test/test_tags.cpp index c0de1b729..c8a0dad06 100644 --- a/test/test_tags.c +++ b/test/test_tags.cpp @@ -1,13 +1,15 @@ -#include -#include +#include "noit_message_decoder.h" #include "noit_metric.h" #include "noit_metric_tag_search.h" -#include "noit_message_decoder.h" +#include #include "libnoit.h" -#include +#include #include +#include #include -#include +#include +#include +#include #include bool benchmark = false; @@ -110,7 +112,6 @@ const char *testtags[][2] = { struct Matches { const char *tagstring; - mtev_boolean tagstring_is_valid; struct { const char *query; mtev_boolean match; @@ -118,10 +119,25 @@ struct Matches { } queries[14]; }; +// the substring "123" is included at the end so the test can ensure the tag is not truncated +std::string max_length_tag_pair = + fmt::format("max_length_tag:max_length{}123", + std::string(NOIT_TAG_MAX_PAIR_LEN - + (sizeof("max_length_tag:max_length123") - 1), + '0')); +std::string too_long_tag_pair = + fmt::format("too_long_tag:too_long{}", + std::string(NOIT_TAG_MAX_PAIR_LEN + 1 - + (sizeof("too_long_tag:too_long") - 1), + '0')); +std::string max_length_test = + fmt::format("tag1:value1,tag2:value2,{},tag4:value4", max_length_tag_pair); +std::string too_long_test = + fmt::format("tag1:value1,tag2:value2,{},tag4:value4", too_long_tag_pair); + struct Matches testmatches[] = { { "__name:f1.f2.f3.f4.f5.f6", - mtev_true, { // f1.{f2,foo}.f{3,4,5}.*.*.f6 (encoded on next line) { "and(__name:b[graphite]\"ZjEue2YyLGZvb30uZnszLDQsNX0uKi4qLmY2\")", mtev_true }, @@ -131,12 +147,11 @@ struct Matches testmatches[] = { { "and(__name:[graphite]f1.**)", mtev_true }, { "and(__name:[graphite]f1.f2.*.f4.f5.f6)", mtev_true }, { "and(__name:[graphite]f1.f2.f3.f4.f5.f6)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "foo:bar,b\"c29tZTpzdHVmZltoZXJlXQ==\":/value,empty:", - mtev_true, { { "and(foo:bar)", mtev_true }, { "and(foo:/)", mtev_false }, @@ -151,12 +166,11 @@ struct Matches testmatches[] = { { "not(empty:/^$/)", mtev_false }, { "not(empty:)", mtev_false }, { "not(empty)", mtev_false }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"KGZvbyk=\":bar", - mtev_true, { { "and(*:*)", mtev_true }, { "and(*:bar)", mtev_true }, @@ -164,63 +178,106 @@ struct Matches testmatches[] = { { "and(*:/ba(.?)r/)", mtev_true }, { "and(b\"KGZvbyk=\":bar)", mtev_true }, { "and(b/XChm/:bar)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"W2Jhcl0=\":b\"Kipmb28qKg==\"", - mtev_true, { { "and(b\"W2Jhcl0=\":*)", mtev_true }, { "and(*:b!Kipmb28qKg==!)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"Kipmb28qKg==\":b\"W2Jhcl0=\"", - mtev_true, { { "and(*:b\"W2Jhcl0=\")", mtev_true }, { "and(b\"Kipmb28qKg==\":*)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"P2Zvbz8=\":b\"W2Jhcl0=\"", - mtev_true, { { "and(*:b\"W2Jhcl0=\")", mtev_true }, { "and(b\"P2Yq\":*)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"Lz9oaXN0b2dyYW0vKC4rKSQp\":quux", - mtev_true, { { "and(*:*)", mtev_true }, { "and(hint(*:*))", mtev_true }, { "and(hint(*:*,index:none))", mtev_true }, { "hint(and(b!Lz9oaXN0b2dyYW0vKC4rKSQp!:quux),foo:bar)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } } }, { "b\"L2Zvby8oXig/OlswLTldezJ9LSkvKC4rKSQp\":bar", - mtev_true, { { "and(*:bar)", mtev_true }, { "and(b\"L2Zvby8oXig/OlswLTldezJ9LSkvKC4rKSQp\":bar)", mtev_false }, { "and(b!L2Zvby8oXig/OlswLTldezJ9LSkvKC4rKSQp!:bar)", mtev_true }, - { NULL, 0 } + { NULL, mtev_false } + } + }, + { + too_long_tag_pair.c_str(), + { + { "and(too_long_tag:too_long*)", mtev_false }, + { NULL, mtev_false } } }, { - "tag:this_tag_pair_is_too_long_0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000257", - mtev_false, + max_length_test.c_str(), + { + { "and(tag1:value1)", mtev_true }, + { "and(tag2:value2)", mtev_true }, + { "and(max_length_tag:max_length*)", mtev_true }, + { "and(max_length_tag:*123)", mtev_true }, + { "and(tag4:value4)", mtev_true }, + { NULL, mtev_false } + } + }, + { + too_long_test.c_str(), + { + { "and(tag1:value1)", mtev_true }, + { "and(tag2:value2)", mtev_true }, + { "and(too_long_tag:too_long*)", mtev_false }, + { "and(tag4:value4)", mtev_true }, + { NULL, mtev_false } + } + } +}; + +std::string max_length_implicit_tag_pair = + fmt::format("__name:max_length{}123", + std::string(NOIT_IMPLICIT_TAG_MAX_PAIR_LEN - + (sizeof("__name:max_length123") - 1), + '0')); +std::string too_long_implicit_tag_pair = + fmt::format("__name:too_long{}", + std::string(NOIT_IMPLICIT_TAG_MAX_PAIR_LEN + 1 - + (sizeof("__name:too_long") - 1), + '0')); +std::string check_uuid_tag_pair = "__check_uuid:b946274b-183d-4553-814a-ada8130c560d"; +std::string implicit_testmatch = max_length_implicit_tag_pair + "," + too_long_implicit_tag_pair + "," + check_uuid_tag_pair; + +struct Matches implicit_testmatches[] = { + + { + implicit_testmatch.c_str(), { - { NULL, 0 } + { "and(__name:max_length*)", mtev_true }, + { "and(__name:*123)", mtev_true }, + { "and(__name:*value_not_in_name*)", mtev_false }, + { "and(__name:too_long*)", mtev_false }, + { "and(__check_uuid:*b946274b*)", mtev_true }, + { NULL, mtev_false } } } }; @@ -265,7 +322,7 @@ void test_tag_decode() { char decoded[512] = {0}; - for(int i = 0; i < sizeof(testtags) / sizeof(*testtags); i++) { + for(size_t i = 0; i < sizeof(testtags) / sizeof(*testtags); i++) { const char *encoded = testtags[i][0]; int rval = noit_metric_tagset_decode_tag(decoded, sizeof(decoded), encoded, strlen(encoded)); @@ -279,7 +336,7 @@ void test_tag_decode() void test_ast_decode() { int erroroffset; - noit_metric_tag_search_ast_t *ast, *not; + noit_metric_tag_search_ast_t *ast, *arg; const char *query; char *unparse; @@ -370,10 +427,10 @@ void test_ast_decode() test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(noit_metric_tag_search_get_arg(ast,0))),"foo") == 0); test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(noit_metric_tag_search_get_arg(ast,0))),"bar") == 0); test_assert(noit_metric_tag_search_get_op(noit_metric_tag_search_get_arg(ast,1)) == OP_NOT_ARGS); - not = noit_metric_tag_search_get_arg(noit_metric_tag_search_get_arg(ast,1),0); - test_assert(not != NULL); - test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(not)),"some:stuff[here]") == 0); - test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(not)),"value") == 0); + arg = noit_metric_tag_search_get_arg(noit_metric_tag_search_get_arg(ast,1),0); + test_assert(arg != NULL); + test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(arg)),"some:stuff[here]") == 0); + test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(arg)),"value") == 0); noit_metric_tag_search_free(ast); } else test_assert_namef(ast != NULL, "parsing error at %d in '%s'", erroroffset, query); @@ -390,11 +447,11 @@ void test_ast_decode() test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(noit_metric_tag_search_get_arg(ast,0))),"foo") == 0); test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(noit_metric_tag_search_get_arg(ast,0))),"bar") == 0); test_assert(noit_metric_tag_search_get_op(noit_metric_tag_search_get_arg(ast,1)) == OP_NOT_ARGS); - not = noit_metric_tag_search_get_arg(noit_metric_tag_search_get_arg(ast,1),0); - test_assert(not != NULL); - test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(not)),"some.*") == 0); - test_assert(strcmp(noit_var_impl_name(noit_metric_tag_search_get_cat(not)),"re") == 0); - test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(not)),"value") == 0); + arg = noit_metric_tag_search_get_arg(noit_metric_tag_search_get_arg(ast,1),0); + test_assert(arg != NULL); + test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_cat(arg)),"some.*") == 0); + test_assert(strcmp(noit_var_impl_name(noit_metric_tag_search_get_cat(arg)),"re") == 0); + test_assert(strcmp(noit_var_val(noit_metric_tag_search_get_name(arg)),"value") == 0); noit_metric_tag_search_free(ast); } else test_assert_namef(ast != NULL, "parsing error at %d in '%s'", erroroffset, query); @@ -453,18 +510,17 @@ void test_tag_match() noit_metric_tagset_builder_t builder; noit_metric_tag_search_ast_t *ast; mtev_boolean match; - char *canonical; - for(int i = 0; i < sizeof(testmatches) / sizeof(*testmatches); i++) { + test_assert(max_length_tag_pair.length() == NOIT_TAG_MAX_PAIR_LEN); + test_assert(too_long_tag_pair.length() > NOIT_TAG_MAX_PAIR_LEN); + + for(size_t i = 0; i < sizeof(testmatches) / sizeof(*testmatches); i++) { + char *canonical = NULL; + test_assert_namef(true, "testing tagset '%s'", testmatches[i].tagstring); noit_metric_tagset_builder_start(&builder); - mtev_boolean tagset_add = noit_metric_tagset_builder_add_many(&builder, testmatches[i].tagstring, strlen(testmatches[i].tagstring)); - memset(&tagset, 0, sizeof(tagset)); - mtev_boolean tagset_end = noit_metric_tagset_builder_end(&builder, &tagset, &canonical); - if (tagset.tag_count == 0){ - assert(testmatches[i].tagstring_is_valid == mtev_false); - continue; - } - test_assert_namef(tagset_add && tagset_end, "'%s' is valid tagset", testmatches[i].tagstring); + noit_metric_tagset_builder_add_many(&builder, testmatches[i].tagstring, strlen(testmatches[i].tagstring)); + noit_metric_tagset_init(&tagset, 0, 0); + noit_metric_tagset_builder_end(&builder, &tagset, &canonical); for(int j = 0; testmatches[i].queries[j].query != NULL; j++) { ast = noit_metric_tag_search_parse_lazy(testmatches[i].queries[j].query, &erroroffset); @@ -487,7 +543,59 @@ void test_tag_match() test_assert_namef(ast != NULL, "parsing error at %d in '%s'", erroroffset, testmatches[i].queries[j].query); } } - free(tagset.tags); + noit_metric_tagset_cleanup(&tagset); + free(canonical); + } +} + +void test_implicit_tag_match() { + int erroroffset; + noit_metric_tagset_t tagset = {}; + noit_metric_tag_search_ast_t *ast; + mtev_boolean match; + + test_assert(max_length_implicit_tag_pair.length() == NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); + test_assert(too_long_implicit_tag_pair.length() > NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); + test_assert(check_uuid_tag_pair.length() == sizeof("__check_uuid:") - 1 + UUID_STR_LEN); + + for (size_t i = 0; + i < sizeof(implicit_testmatches) / sizeof(*implicit_testmatches); i++) { + char *canonical = NULL; + test_assert_namef(true, "testing tagset '%s'", + implicit_testmatches[i].tagstring); + noit_metric_tagset_init(&tagset, 0, 0); + noit_metric_add_implicit_tags_to_tagset( + implicit_testmatches[i].tagstring, + strlen(implicit_testmatches[i].tagstring), &tagset, &canonical); + + for (int j = 0; implicit_testmatches[i].queries[j].query != NULL; j++) { + ast = noit_metric_tag_search_parse_lazy( + implicit_testmatches[i].queries[j].query, &erroroffset); + if (ast) { + if (benchmark) { + mtev_perftimer_t btimer; + mtev_perftimer_start(&btimer); + for (int b = 0; b < BENCH_ITERS; b++) { + match = noit_metric_tag_search_evaluate_against_tags(ast, &tagset); + } + implicit_testmatches[i].queries[j].bench_ns = + mtev_perftimer_elapsed(&btimer); + } else { + match = noit_metric_tag_search_evaluate_against_tags(ast, &tagset); + } + test_assert_namef(match == implicit_testmatches[i].queries[j].match, + "'%s' %s", implicit_testmatches[i].queries[j].query, + match ? "matches" : "doesn't match"); + /* clone if only to test cloning */ + noit_metric_tag_search_free(noit_metric_tag_search_clone(ast)); + noit_metric_tag_search_free(ast); + } else { + test_assert_namef(ast != NULL, "parsing error at %d in '%s'", + erroroffset, + implicit_testmatches[i].queries[j].query); + } + } + noit_metric_tagset_cleanup(&tagset); free(canonical); } } @@ -552,7 +660,7 @@ void test_fuzz_canon() { /* We can only operate on metric names up to sizeof(out), so just elide the testing * from longer names. */ if(strlen(_obuff) <= sizeof(out)) { - char *copy = malloc(strlen(_obuff)); + char *copy = (char *)malloc(strlen(_obuff)); memcpy(copy, _obuff, strlen(_obuff)); int len = noit_metric_canonicalize(copy, strlen(_obuff), out, sizeof(out), mtev_true); free(copy); @@ -620,13 +728,12 @@ void test_line(const char *name, const char *in, const char *expect, int rval_ex test_assert_namef(allocd != (message.id.alloc_name == NULL), "test_line(%s) allocd", name); test_assert_namef(rval == rval_expect, "test_line(%s) rval [%d should be %d]", name, rval, rval_expect); if(expect != NULL) { - int v = strlen(expect) == message.id.name_len_with_tags && - !memcmp(message.id.name, expect, message.id.name_len_with_tags); - test_assert_namef(v, - "test_line(%s) metric match", name); - if(v == 0) { - printf("\nFAILURE:\nRESULT: '%.*s'\nEXPECT: '%s'\n\n", - (int)message.id.name_len_with_tags, message.id.name, expect); + int v = strlen(expect) == (size_t)message.id.name_len_with_tags && + !memcmp(message.id.name, expect, message.id.name_len_with_tags); + test_assert_namef(v, "test_line(%s) metric match", name); + if (v == 0) { + printf("\nFAILURE:\nRESULT: '%.*s'\nEXPECT: '%s'\n\n", + (int)message.id.name_len_with_tags, message.id.name, expect); } } else { @@ -654,13 +761,11 @@ void metric_parsing(void) { test_assert_namef(len > 0, "'%s' -> '%s'", dbuff, ebuff); test_assert_namef(strcmp("foo:http://12.3.3.4:80/this?is=it", ebuff) == 0, "'%s' equals 'foo:http://12.3.3.4:80/this?is=it'", ebuff); - int i; - - for(i=0; i %f ns/op\n", str, (elapsed * 1000000000.0) / (double)nloop); + printf("canonicalize('%s') -> %f ns/op\n", str.c_str(), (elapsed * 1000000000.0) / (double)nloop); } void test_tag_at_limit(void) { @@ -772,6 +877,43 @@ void test_tag_at_limit(void) { assert(memcmp(tag_name, dbuff + NOIT_TAG_MAX_PAIR_LEN, NOIT_TAG_MAX_PAIR_LEN) == 0); } +void test_implicit_tag_at_limit(void) { + mtev_boolean too_long = mtev_false; + noit_metric_tag_t tag; + ssize_t len; + char dbuff[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN * 3]; + + assert(max_length_implicit_tag_pair.size() == NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); + + noit_metric_tags_parse_one_implicit(max_length_implicit_tag_pair.c_str(), max_length_implicit_tag_pair.size(), &tag, + &too_long); + assert(too_long == mtev_false); + + memset(dbuff, 0xff, NOIT_IMPLICIT_TAG_MAX_PAIR_LEN * 3); + len = noit_metric_tagset_decode_tag(dbuff + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, tag.tag, + tag.total_size); + + assert(len >= 0); + assert((uint8_t)dbuff[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN - 1] == 0xff); + assert( + (uint8_t)dbuff[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN] == + 0xff); + assert(memcmp(max_length_implicit_tag_pair.c_str(), dbuff + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN) != 0); + assert((uint8_t)dbuff[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN] == '_'); + assert( + (uint8_t)dbuff[NOIT_IMPLICIT_TAG_MAX_PAIR_LEN + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN] == + 0xff); + + len = noit_metric_tagset_encode_tag( + dbuff + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, + dbuff + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, NOIT_IMPLICIT_TAG_MAX_PAIR_LEN); + assert(len >= 0); + assert(memcmp(max_length_implicit_tag_pair.c_str(), dbuff + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN, + NOIT_IMPLICIT_TAG_MAX_PAIR_LEN) == 0); +} + int main(int argc, char * const *argv) { int opt; @@ -802,7 +944,9 @@ int main(int argc, char * const *argv) test_tag_decode(); test_ast_decode(); test_tag_match(); + test_implicit_tag_match(); test_tag_at_limit(); + test_implicit_tag_at_limit(); metric_parsing(); query_parsing(); query_argument_swapping(); @@ -812,7 +956,7 @@ int main(int argc, char * const *argv) loop("testing_this_long_untagged_metric"); printf("\n%d tests failed.\n", failures); if(benchmark) { - for(int i=0; i < sizeof(testmatches) / sizeof(*testmatches); i++) { + for(size_t i=0; i < sizeof(testmatches) / sizeof(*testmatches); i++) { for(int j = 0; testmatches[i].queries[j].query != NULL; j++) { printf("%s on %s -> %f ns/op\n", testmatches[i].queries[j].query, testmatches[i].tagstring, (double)testmatches[i].queries[j].bench_ns / (double)BENCH_ITERS);