X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fwrite_kafka.c;h=37b3e14f25ef821aea4b93332007b26173473253;hb=41288c6a9ed050b41ad47184aa1b53668c3588cc;hp=a5977aba786770e1e29489b9590a26ed21561c0c;hpb=eff52149778a4ae3cbd5c0088633b9cef9ade7d9;p=collectd.git diff --git a/src/write_kafka.c b/src/write_kafka.c index a5977aba..6018fea0 100644 --- a/src/write_kafka.c +++ b/src/write_kafka.c @@ -25,19 +25,15 @@ */ #include "collectd.h" + #include "plugin.h" #include "common.h" -#include "configfile.h" -#include "utils_cache.h" #include "utils_cmd_putval.h" #include "utils_format_graphite.h" #include "utils_format_json.h" -#include "utils_crc32.h" #include #include -#include -#include #include struct kafka_topic_context { @@ -51,8 +47,7 @@ struct kafka_topic_context { rd_kafka_topic_t *topic; rd_kafka_conf_t *kafka_conf; rd_kafka_t *kafka; - int has_key; - uint32_t key; + char *key; char *prefix; char *postfix; char escape_char; @@ -65,7 +60,14 @@ static int kafka_write(const data_set_t *, const value_list_t *, user_data_t *); static int32_t kafka_partition(const rd_kafka_topic_t *, const void *, size_t, int32_t, void *, void *); -#if defined HAVE_LIBRDKAFKA_LOGGER || defined HAVE_LIBRDKAFKA_LOG_CB +/* Version 0.9.0 of librdkafka deprecates rd_kafka_set_logger() in favor of + * rd_kafka_conf_set_log_cb(). This is to make sure we're not using the + * deprecated function. */ +#ifdef HAVE_LIBRDKAFKA_LOG_CB +# undef HAVE_LIBRDKAFKA_LOGGER +#endif + +#if defined(HAVE_LIBRDKAFKA_LOGGER) || defined(HAVE_LIBRDKAFKA_LOG_CB) static void kafka_log(const rd_kafka_t *, int, const char *, const char *); static void kafka_log(const rd_kafka_t *rkt, int level, @@ -75,11 +77,28 @@ static void kafka_log(const rd_kafka_t *rkt, int level, } #endif +static uint32_t kafka_hash(const char *keydata, size_t keylen) +{ + uint32_t hash = 5381; + for (; keylen > 0; keylen--) + hash = ((hash << 5) + hash) + keydata[keylen - 1]; + return hash; +} + +/* 31 bit -> 4 byte -> 8 byte hex string + null byte */ +#define KAFKA_RANDOM_KEY_SIZE 9 +#define KAFKA_RANDOM_KEY_BUFFER (char[KAFKA_RANDOM_KEY_SIZE]) {""} +static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) +{ + ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08lX", (unsigned long) mrand48()); + return buffer; +} + static int32_t kafka_partition(const rd_kafka_topic_t *rkt, const void *keydata, size_t keylen, int32_t partition_cnt, void *p, void *m) { - uint32_t key = *((uint32_t *)keydata ); + uint32_t key = kafka_hash(keydata, keylen); uint32_t target = key % partition_cnt; int32_t i = partition_cnt; @@ -115,7 +134,7 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */ INFO ("write_kafka plugin: created KAFKA handle : %s", rd_kafka_name(ctx->kafka)); -#ifdef HAVE_LIBRDKAFKA_LOGGER +#if defined(HAVE_LIBRDKAFKA_LOGGER) && !defined(HAVE_LIBRDKAFKA_LOG_CB) rd_kafka_set_logger(ctx->kafka, kafka_log); #endif } @@ -148,7 +167,8 @@ static int kafka_write(const data_set_t *ds, /* {{{ */ user_data_t *ud) { int status = 0; - uint32_t key; + void *key; + size_t keylen = 0; char buffer[8192]; size_t bfree = sizeof(buffer); size_t bfill = 0; @@ -168,9 +188,9 @@ static int kafka_write(const data_set_t *ds, /* {{{ */ switch (ctx->format) { case KAFKA_FORMAT_COMMAND: - status = create_putval(buffer, sizeof(buffer), ds, vl); + status = cmd_create_putval(buffer, sizeof(buffer), ds, vl); if (status != 0) { - ERROR("write_kafka plugin: create_putval failed with status %i.", + ERROR("write_kafka plugin: cmd_create_putval failed with status %i.", status); return status; } @@ -199,17 +219,14 @@ static int kafka_write(const data_set_t *ds, /* {{{ */ return -1; } - /* - * We partition our stream by metric name - */ - if (ctx->has_key) - key = ctx->key; - else - key = rand(); + key = (ctx->key != NULL) + ? ctx->key + : kafka_random_key(KAFKA_RANDOM_KEY_BUFFER); + keylen = strlen (key); rd_kafka_produce(ctx->topic, RD_KAFKA_PARTITION_UA, RD_KAFKA_MSG_F_COPY, buffer, blen, - &key, sizeof(key), NULL); + key, keylen, NULL); return status; } /* }}} int kafka_write */ @@ -238,13 +255,11 @@ static void kafka_topic_context_free(void *p) /* {{{ */ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ */ { int status; - int i; struct kafka_topic_context *tctx; char *key = NULL; char *val; char callback_name[DATA_MAX_NAME_LEN]; char errbuf[1024]; - user_data_t ud; oconfig_item_t *child; rd_kafka_conf_res_t ret; @@ -256,6 +271,7 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ tctx->escape_char = '.'; tctx->store_rates = 1; tctx->format = KAFKA_FORMAT_JSON; + tctx->key = NULL; if ((tctx->kafka_conf = rd_kafka_conf_dup(conf)) == NULL) { sfree(tctx); @@ -289,7 +305,7 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ goto errout; } - for (i = 0; i < ci->children_num; i++) { + for (int i = 0; i < ci->children_num; i++) { /* * The code here could be simplified but makes room * for easy adding of new options later on. @@ -318,19 +334,12 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ } } else if (strcasecmp ("Key", child->key) == 0) { - char *tmp_buf = NULL; - status = cf_util_get_string(child, &tmp_buf); - if (status != 0) { - WARNING("write_kafka plugin: invalid key supplied"); - break; - } - - if (strcasecmp(tmp_buf, "Random") != 0) { - tctx->has_key = 1; - tctx->key = crc32_buffer((u_char *)tmp_buf, strlen(tmp_buf)); + if (cf_util_get_string (child, &tctx->key) != 0) + continue; + if (strcasecmp ("Random", tctx->key) == 0) { + sfree(tctx->key); + tctx->key = strdup (kafka_random_key (KAFKA_RANDOM_KEY_BUFFER)); } - sfree(tmp_buf); - } else if (strcasecmp ("Format", child->key) == 0) { status = cf_util_get_string(child, &key); if (status != 0) @@ -393,10 +402,11 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s", tctx->topic_name); - ud.data = tctx; - ud.free_func = kafka_topic_context_free; - - status = plugin_register_write (callback_name, kafka_write, &ud); + status = plugin_register_write (callback_name, kafka_write, + &(user_data_t) { + .data = tctx, + .free_func = kafka_topic_context_free, + }); if (status != 0) { WARNING ("write_kafka plugin: plugin_register_write (\"%s\") " "failed with status %i.", @@ -419,7 +429,6 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{ static int kafka_config(oconfig_item_t *ci) /* {{{ */ { - int i; oconfig_item_t *child; rd_kafka_conf_t *conf; rd_kafka_conf_res_t ret; @@ -429,7 +438,7 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */ WARNING("cannot allocate kafka configuration."); return -1; } - for (i = 0; i < ci->children_num; i++) { + for (int i = 0; i < ci->children_num; i++) { child = &ci->children[i]; if (strcasecmp("Topic", child->key) == 0) { @@ -453,12 +462,15 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */ } if ((val = strdup(child->values[1].value.string)) == NULL) { WARNING("cannot allocate memory for attribute value."); + sfree(key); goto errout; } ret = rd_kafka_conf_set(conf, key, val, errbuf, sizeof(errbuf)); if (ret != RD_KAFKA_CONF_OK) { WARNING("cannot set kafka property %s to %s: %s", key, val, errbuf); + sfree(key); + sfree(val); goto errout; } sfree(key); @@ -482,4 +494,3 @@ void module_register(void) { plugin_register_complex_config ("write_kafka", kafka_config); } -