From 2f7fd156e92952dc478d3735e79af7d344a1eba1 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Mon, 6 Nov 2017 21:26:08 +0100 Subject: [PATCH 1/1] Rename write_gcm to write_stackdriver. --- Makefile.am | 42 +++--- configure.ac | 6 +- src/collectd.conf.in | 22 +-- src/collectd.conf.pod | 160 ++++++++++----------- src/utils_format_gcm.h | 78 ---------- ...ils_format_gcm.c => utils_format_stackdriver.c} | 107 +++++++------- src/utils_format_stackdriver.h | 79 ++++++++++ ..._gcm_test.c => utils_format_stackdriver_test.c} | 12 +- src/{write_gcm.c => write_stackdriver.c} | 129 +++++++++-------- 9 files changed, 324 insertions(+), 311 deletions(-) delete mode 100644 src/utils_format_gcm.h rename src/{utils_format_gcm.c => utils_format_stackdriver.c} (86%) create mode 100644 src/utils_format_stackdriver.h rename src/{utils_format_gcm_test.c => utils_format_stackdriver_test.c} (88%) rename src/{write_gcm.c => write_stackdriver.c} (80%) diff --git a/Makefile.am b/Makefile.am index 93a4ca89..266ff10c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -616,25 +616,25 @@ libgce_la_LIBADD = \ endif if BUILD_WITH_LIBYAJL2 -noinst_LTLIBRARIES += libformat_gcm.la -libformat_gcm_la_SOURCES = \ - src/utils_format_gcm.c \ - src/utils_format_gcm.h -libformat_gcm_la_CPPFLAGS = \ +noinst_LTLIBRARIES += libformat_stackdriver.la +libformat_stackdriver_la_SOURCES = \ + src/utils_format_stackdriver.c \ + src/utils_format_stackdriver.h +libformat_stackdriver_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(BUILD_WITH_LIBYAJL_CPPFLAGS) -libformat_gcm_la_LIBADD = \ +libformat_stackdriver_la_LIBADD = \ libavltree.la \ $(BUILD_WITH_LIBSSL_LIBS) \ $(BUILD_WITH_LIBYAJL_LIBS) -check_PROGRAMS += test_format_gcm -TESTS += test_format_gcm -test_format_gcm_SOURCES = \ - src/utils_format_gcm_test.c \ +check_PROGRAMS += test_format_stackdriver +TESTS += test_format_stackdriver +test_format_stackdriver_SOURCES = \ + src/utils_format_stackdriver_test.c \ src/testing.h -test_format_gcm_LDADD = \ - libformat_gcm.la \ +test_format_stackdriver_LDADD = \ + libformat_stackdriver.la \ libplugin_mock.la \ -lm endif @@ -1980,15 +1980,6 @@ write_http_la_LDFLAGS = $(PLUGIN_LDFLAGS) write_http_la_LIBADD = libformat_json.la $(BUILD_WITH_LIBCURL_LIBS) endif -if BUILD_PLUGIN_WRITE_GCM -pkglib_LTLIBRARIES += write_gcm.la -write_gcm_la_SOURCES = src/write_gcm.c -write_gcm_la_LDFLAGS = $(PLUGIN_LDFLAGS) -write_gcm_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS) -write_gcm_la_LIBADD = libformat_gcm.la libgce.la liboauth.la \ - $(BUILD_WITH_LIBCURL_LIBS) -endif - if BUILD_PLUGIN_WRITE_KAFKA pkglib_LTLIBRARIES += write_kafka.la write_kafka_la_SOURCES = src/write_kafka.c @@ -2050,6 +2041,15 @@ write_sensu_la_SOURCES = src/write_sensu.c write_sensu_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif +if BUILD_PLUGIN_WRITE_STACKDRIVER +pkglib_LTLIBRARIES += write_stackdriver.la +write_stackdriver_la_SOURCES = src/write_stackdriver.c +write_stackdriver_la_LDFLAGS = $(PLUGIN_LDFLAGS) +write_stackdriver_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS) +write_stackdriver_la_LIBADD = libformat_stackdriver.la libgce.la liboauth.la \ + $(BUILD_WITH_LIBCURL_LIBS) +endif + if BUILD_PLUGIN_WRITE_TSDB pkglib_LTLIBRARIES += write_tsdb.la write_tsdb_la_SOURCES = src/write_tsdb.c diff --git a/configure.ac b/configure.ac index 92c81eeb..5333c423 100644 --- a/configure.ac +++ b/configure.ac @@ -6565,7 +6565,7 @@ if test "x$with_libcurl" = "xyes" && test "x$with_libyajl" = "xyes"; then fi if test "x$with_libcurl" = "xyes" && test "x$with_libssl" = "xyes" && test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then - plugin_write_gcm="yes" + plugin_write_stackdriver="yes" fi if test "x$with_libcurl" = "xyes" && test "x$with_libxml2" = "xyes"; then @@ -6900,7 +6900,7 @@ AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer stati AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics]) AC_PLUGIN([write_graphite], [yes], [Graphite / Carbon output plugin]) AC_PLUGIN([write_http], [$with_libcurl], [HTTP output plugin]) -AC_PLUGIN([write_gcm], [$plugin_write_gcm], [Google cloud monitoring output plugin]) +AC_PLUGIN([write_stackdriver], [$plugin_write_stackdriver], [Google Stackdriver Monitoring output plugin]) AC_PLUGIN([write_kafka], [$with_librdkafka], [Kafka output plugin]) AC_PLUGIN([write_log], [yes], [Log output plugin]) AC_PLUGIN([write_mongodb], [$with_libmongoc], [MongoDB output plugin]) @@ -7323,7 +7323,6 @@ AC_MSG_RESULT([ vserver . . . . . . . $enable_vserver]) AC_MSG_RESULT([ wireless . . . . . . $enable_wireless]) AC_MSG_RESULT([ write_graphite . . . $enable_write_graphite]) AC_MSG_RESULT([ write_http . . . . . $enable_write_http]) -AC_MSG_RESULT([ write_gcm . . . . . . $enable_write_gcm]) AC_MSG_RESULT([ write_kafka . . . . . $enable_write_kafka]) AC_MSG_RESULT([ write_log . . . . . . $enable_write_log]) AC_MSG_RESULT([ write_mongodb . . . . $enable_write_mongodb]) @@ -7331,6 +7330,7 @@ AC_MSG_RESULT([ write_prometheus. . . $enable_write_prometheus]) AC_MSG_RESULT([ write_redis . . . . . $enable_write_redis]) AC_MSG_RESULT([ write_riemann . . . . $enable_write_riemann]) AC_MSG_RESULT([ write_sensu . . . . . $enable_write_sensu]) +AC_MSG_RESULT([ write_stackdriver . . $enable_write_stackdriver]) AC_MSG_RESULT([ write_tsdb . . . . . $enable_write_tsdb]) AC_MSG_RESULT([ xencpu . . . . . . . $enable_xencpu]) AC_MSG_RESULT([ xmms . . . . . . . . $enable_xmms]) diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 6a096430..184d0b93 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -213,7 +213,6 @@ #@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem #@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver #@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless -#@BUILD_PLUGIN_WRITE_GCM_TRUE@LoadPlugin write_gcm #@BUILD_PLUGIN_WRITE_GRAPHITE_TRUE@LoadPlugin write_graphite #@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http #@BUILD_PLUGIN_WRITE_KAFKA_TRUE@LoadPlugin write_kafka @@ -223,6 +222,7 @@ #@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann #@BUILD_PLUGIN_WRITE_SENSU_TRUE@LoadPlugin write_sensu +#@BUILD_PLUGIN_WRITE_STACKDRIVER_TRUE@LoadPlugin write_stackdriver #@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb #@BUILD_PLUGIN_XENCPU_TRUE@LoadPlugin xencpu #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms @@ -1675,16 +1675,6 @@ # Verbose false # -# -# Project "stackdriver-account" -# CredentialFile "/path/to/gcp-project-id-12345.json" -# Email "123456789012@developer.gserviceaccount.com" -# -# project_id "gcp-project-id" -# -# Url "https://monitoring.googleapis.com/v3" -# - # # # Host "localhost" @@ -1798,6 +1788,16 @@ # Attribute "foo" "bar" # +# +# Project "stackdriver-account" +# CredentialFile "/path/to/gcp-project-id-12345.json" +# Email "123456789012@developer.gserviceaccount.com" +# +# project_id "gcp-project-id" +# +# Url "https://monitoring.googleapis.com/v3" +# + # # # Host "localhost" diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index e293d495..7ff36b2c 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -9337,86 +9337,6 @@ traffic (e.Eg. due to headers and retransmission). If you want to collect on-wire traffic you could, for example, use the logging facilities of iptables to feed data for the guest IPs into the iptables plugin. -=head2 Plugin C - -The C plugin writes metrics to the I (GCM) -service. - -This plugin supports two authentication methods: When configured, credentials -are read from the JSON credentials file specified with B. -Alternatively, when running on -I (GCE), an I token is retrieved from the -I and used to authenticate to GCM. - -B - - - CredentialFile "/path/to/service_account.json" - - project_id "monitored_project" - - - -=over 4 - -=item B I - -Path to a JSON credentials file holding the credentials for a GCP service -account. - -If not specified, I. If running on GCE, -B may be set to chose a different service account associated with the -instance. - -=item B I - -The I or the I of the I. The -I is a string identifying the GCP project, which you can chose -freely when creating a new project. The I is a 12-digit decimal -number. You can look up both on the I. - -This setting is optional. If not set, the project ID is read from the -credentials file or determined from the GCE's metadata service. - -=item B I - -Email address of an GCE I. This setting is only effective when -running on GCE and using I (see -B above). - -=item B I - -Configures the I to use when storing metrics. This option -takes a I and arbitrary string options which are used as labels. - -On GCE, defaults to the equivalent of this config: - - - project_id "${meta/project/project-id}" - instance_id "${meta/instance/id}" - zone "${meta/instance/zone}" - - -Where C<${meta/...}> are values read from the meta data service. - -When not running on GCE, defaults to the equivalent of this config: - - - project_id "${Project}" - - -Where C<${Project}> refers to the B option. - -See L for more information -on I. - -=item B I - -URL of the I API. Defaults to -C. - -=back - =head2 Plugin C The C plugin writes data to I, an open-source metrics @@ -10387,6 +10307,86 @@ attribute for each metric being sent out to I. =back +=head2 Plugin C + +The C plugin writes metrics to the +I service. + +This plugin supports two authentication methods: When configured, credentials +are read from the JSON credentials file specified with B. +Alternatively, when running on +I (GCE), an I token is retrieved from the +I and used to authenticate to GCM. + +B + + + CredentialFile "/path/to/service_account.json" + + project_id "monitored_project" + + + +=over 4 + +=item B I + +Path to a JSON credentials file holding the credentials for a GCP service +account. + +If not specified, I. If running on GCE, +B may be set to chose a different service account associated with the +instance. + +=item B I + +The I or the I of the I. The +I is a string identifying the GCP project, which you can chose +freely when creating a new project. The I is a 12-digit decimal +number. You can look up both on the I. + +This setting is optional. If not set, the project ID is read from the +credentials file or determined from the GCE's metadata service. + +=item B I + +Email address of an GCE I. This setting is only effective when +running on GCE and using I (see +B above). + +=item B I + +Configures the I to use when storing metrics. This option +takes a I and arbitrary string options which are used as labels. + +On GCE, defaults to the equivalent of this config: + + + project_id "${meta/project/project-id}" + instance_id "${meta/instance/id}" + zone "${meta/instance/zone}" + + +Where C<${meta/...}> are values read from the meta data service. + +When not running on GCE, defaults to the equivalent of this config: + + + project_id "${Project}" + + +Where C<${Project}> refers to the B option. + +See L for more information +on I. + +=item B I + +URL of the I API. Defaults to +C. + +=back + =head2 Plugin C This plugin collects metrics of hardware CPU load for machine running Xen diff --git a/src/utils_format_gcm.h b/src/utils_format_gcm.h deleted file mode 100644 index a43812c5..00000000 --- a/src/utils_format_gcm.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * collectd - src/utils_format_gcm.h - * ISC license - * - * Copyright (C) 2017 Florian Forster - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Authors: - * Florian Forster - **/ - -#ifndef UTILS_FORMAT_GCM_H -#define UTILS_FORMAT_GCM_H 1 - -#include "collectd.h" -#include "plugin.h" - -/* gcm_output_t is a buffer to which value_list_t* can be added and from which - * an appropriately formatted char* can be read. */ -struct gcm_output_s; -typedef struct gcm_output_s gcm_output_t; - -/* gcm_resource_t represents a MonitoredResource. */ -struct gcm_resource_s; -typedef struct gcm_resource_s gcm_resource_t; - -gcm_output_t *gcm_output_create(gcm_resource_t *res); - -/* gcm_output_destroy frees all memory used by out, including the - * gcm_resource_t* passed to gcm_output_create. */ -void gcm_output_destroy(gcm_output_t *out); - -/* gcm_output_add adds a value_list_t* to "out". - * - * Return values: - * - 0 Success - * - ENOBUFS Success, but the buffer should be flushed soon. - * - EEXIST The value list is already encoded in the buffer. - * Flush the buffer, then call gcm_output_add again. - * - ENOENT First time we encounter this metric. Create a metric descriptor - * using the GCM API and then call gcm_output_register_metric. - */ -int gcm_output_add(gcm_output_t *out, data_set_t const *ds, - value_list_t const *vl); - -/* gcm_output_register_metric adds the metric descriptor which vl maps to, to - * the list of known metric descriptors. */ -int gcm_output_register_metric(gcm_output_t *out, data_set_t const *ds, - value_list_t const *vl); - -/* gcm_output_reset resets the output and returns the previous content of the - * buffer. It is the caller's responsibility to call free() with the returned - * pointer. */ -char *gcm_output_reset(gcm_output_t *out); - -gcm_resource_t *gcm_resource_create(char const *type); -void gcm_resource_destroy(gcm_resource_t *res); -int gcm_resource_add_label(gcm_resource_t *res, char const *key, - char const *value); - -/* gcm_format_metric_descriptor creates the payload for a - * projects.metricDescriptors.create() request. */ -int gcm_format_metric_descriptor(char *buffer, size_t buffer_size, - data_set_t const *ds, value_list_t const *vl, - int ds_index); - -#endif /* UTILS_FORMAT_GCM_H */ diff --git a/src/utils_format_gcm.c b/src/utils_format_stackdriver.c similarity index 86% rename from src/utils_format_gcm.c rename to src/utils_format_stackdriver.c index 0c60ef0c..fda049c8 100644 --- a/src/utils_format_gcm.c +++ b/src/utils_format_stackdriver.c @@ -1,5 +1,5 @@ /** - * collectd - src/utils_format_gcm.c + * collectd - src/utils_format_stackdriver.c * ISC license * * Copyright (C) 2017 Florian Forster @@ -22,7 +22,7 @@ #include "collectd.h" -#include "utils_format_gcm.h" +#include "utils_format_stackdriver.h" #include "common.h" #include "plugin.h" @@ -36,23 +36,23 @@ #include #endif -struct gcm_output_s { - gcm_resource_t *res; +struct sd_output_s { + sd_resource_t *res; yajl_gen gen; c_avl_tree_t *staged; c_avl_tree_t *metric_descriptors; }; -struct gcm_label_s { +struct sd_label_s { char *key; char *value; }; -typedef struct gcm_label_s gcm_label_t; +typedef struct sd_label_s sd_label_t; -struct gcm_resource_s { +struct sd_resource_s { char *type; - gcm_label_t *labels; + sd_label_t *labels; size_t labels_num; }; @@ -89,7 +89,7 @@ static int json_time(yajl_gen gen, cdtime_t t) { * } * } */ -static int format_gcm_resource(yajl_gen gen, gcm_resource_t *res) /* {{{ */ +static int format_gcm_resource(yajl_gen gen, sd_resource_t *res) /* {{{ */ { int status; @@ -348,7 +348,7 @@ static int format_metric(yajl_gen gen, data_set_t const *ds, */ static int format_time_series(yajl_gen gen, data_set_t const *ds, value_list_t const *vl, int ds_index, - gcm_resource_t *res) { + sd_resource_t *res) { /* {{{ */ yajl_gen_map_open(gen); @@ -383,7 +383,7 @@ static int format_time_series(yajl_gen gen, data_set_t const *ds, * ], * } */ -static int gcm_output_initialize(gcm_output_t *out) /* {{{ */ +static int sd_output_initialize(sd_output_t *out) /* {{{ */ { yajl_gen_map_open(out->gen); @@ -394,27 +394,27 @@ static int gcm_output_initialize(gcm_output_t *out) /* {{{ */ yajl_gen_array_open(out->gen); return 0; -} /* }}} int gcm_output_initialize */ +} /* }}} int sd_output_initialize */ -static int gcm_output_finalize(gcm_output_t *out) /* {{{ */ +static int sd_output_finalize(sd_output_t *out) /* {{{ */ { yajl_gen_array_close(out->gen); yajl_gen_map_close(out->gen); return 0; -} /* }}} int gcm_output_finalize */ +} /* }}} int sd_output_finalize */ -static void gcm_output_reset_staged(gcm_output_t *out) /* {{{ */ +static void sd_output_reset_staged(sd_output_t *out) /* {{{ */ { void *key = NULL; while (c_avl_pick(out->staged, &key, &(void *){NULL}) == 0) sfree(key); -} /* }}} void gcm_output_reset_staged */ +} /* }}} void sd_output_reset_staged */ -gcm_output_t *gcm_output_create(gcm_resource_t *res) /* {{{ */ +sd_output_t *sd_output_create(sd_resource_t *res) /* {{{ */ { - gcm_output_t *out = calloc(1, sizeof(*out)); + sd_output_t *out = calloc(1, sizeof(*out)); if (out == NULL) return NULL; @@ -422,28 +422,28 @@ gcm_output_t *gcm_output_create(gcm_resource_t *res) /* {{{ */ out->gen = yajl_gen_alloc(/* funcs = */ NULL); if (out->gen == NULL) { - gcm_output_destroy(out); + sd_output_destroy(out); return NULL; } out->staged = c_avl_create((void *)strcmp); if (out->staged == NULL) { - gcm_output_destroy(out); + sd_output_destroy(out); return NULL; } out->metric_descriptors = c_avl_create((void *)strcmp); if (out->metric_descriptors == NULL) { - gcm_output_destroy(out); + sd_output_destroy(out); return NULL; } - gcm_output_initialize(out); + sd_output_initialize(out); return out; -} /* }}} gcm_output_t *gcm_output_create */ +} /* }}} sd_output_t *sd_output_create */ -void gcm_output_destroy(gcm_output_t *out) /* {{{ */ +void sd_output_destroy(sd_output_t *out) /* {{{ */ { if (out == NULL) return; @@ -458,7 +458,7 @@ void gcm_output_destroy(gcm_output_t *out) /* {{{ */ } if (out->staged != NULL) { - gcm_output_reset_staged(out); + sd_output_reset_staged(out); c_avl_destroy(out->staged); out->staged = NULL; } @@ -469,15 +469,15 @@ void gcm_output_destroy(gcm_output_t *out) /* {{{ */ } if (out->res != NULL) { - gcm_resource_destroy(out->res); + sd_resource_destroy(out->res); out->res = NULL; } sfree(out); -} /* }}} void gcm_output_destroy */ +} /* }}} void sd_output_destroy */ -int gcm_output_add(gcm_output_t *out, data_set_t const *ds, - value_list_t const *vl) /* {{{ */ +int sd_output_add(sd_output_t *out, data_set_t const *ds, + value_list_t const *vl) /* {{{ */ { char key[6 * DATA_MAX_NAME_LEN]; int status; @@ -494,7 +494,7 @@ int gcm_output_add(gcm_output_t *out, data_set_t const *ds, status = FORMAT_VL(key, sizeof(key), vl); if (status != 0) { - ERROR("gcm_output_add: FORMAT_VL failed with status %d.", status); + ERROR("sd_output_add: FORMAT_VL failed with status %d.", status); return status; } @@ -505,8 +505,7 @@ int gcm_output_add(gcm_output_t *out, data_set_t const *ds, for (size_t i = 0; i < ds->ds_num; i++) { int status = format_time_series(out->gen, ds, vl, i, out->res); if (status != 0) { - ERROR("gcm_output_add: format_time_series failed with status %d.", - status); + ERROR("sd_output_add: format_time_series failed with status %d.", status); return status; } } @@ -519,10 +518,10 @@ int gcm_output_add(gcm_output_t *out, data_set_t const *ds, return ENOBUFS; return 0; -} /* }}} int gcm_output_add */ +} /* }}} int sd_output_add */ -int gcm_output_register_metric(gcm_output_t *out, data_set_t const *ds, - value_list_t const *vl) { +int sd_output_register_metric(sd_output_t *out, data_set_t const *ds, + value_list_t const *vl) { /* {{{ */ for (size_t i = 0; i < ds->ds_num; i++) { char buffer[4 * DATA_MAX_NAME_LEN]; @@ -537,31 +536,31 @@ int gcm_output_register_metric(gcm_output_t *out, data_set_t const *ds, } return 0; -} /* }}} int gcm_output_register_metric */ +} /* }}} int sd_output_register_metric */ -char *gcm_output_reset(gcm_output_t *out) /* {{{ */ +char *sd_output_reset(sd_output_t *out) /* {{{ */ { unsigned char const *json_buffer = NULL; char *ret; - gcm_output_finalize(out); + sd_output_finalize(out); yajl_gen_get_buf(out->gen, &json_buffer, &(size_t){0}); ret = strdup((void const *)json_buffer); - gcm_output_reset_staged(out); + sd_output_reset_staged(out); yajl_gen_free(out->gen); out->gen = yajl_gen_alloc(/* funcs = */ NULL); - gcm_output_initialize(out); + sd_output_initialize(out); return ret; -} /* }}} char *gcm_output_reset */ +} /* }}} char *sd_output_reset */ -gcm_resource_t *gcm_resource_create(char const *type) /* {{{ */ +sd_resource_t *sd_resource_create(char const *type) /* {{{ */ { - gcm_resource_t *res; + sd_resource_t *res; res = malloc(sizeof(*res)); if (res == NULL) @@ -578,9 +577,9 @@ gcm_resource_t *gcm_resource_create(char const *type) /* {{{ */ res->labels_num = 0; return res; -} /* }}} gcm_resource_t *gcm_resource_create */ +} /* }}} sd_resource_t *sd_resource_create */ -void gcm_resource_destroy(gcm_resource_t *res) /* {{{ */ +void sd_resource_destroy(sd_resource_t *res) /* {{{ */ { size_t i; @@ -594,12 +593,12 @@ void gcm_resource_destroy(gcm_resource_t *res) /* {{{ */ sfree(res->labels); sfree(res->type); sfree(res); -} /* }}} void gcm_resource_destroy */ +} /* }}} void sd_resource_destroy */ -int gcm_resource_add_label(gcm_resource_t *res, char const *key, - char const *value) /* {{{ */ +int sd_resource_add_label(sd_resource_t *res, char const *key, + char const *value) /* {{{ */ { - gcm_label_t *l; + sd_label_t *l; if ((res == NULL) || (key == NULL) || (value == NULL)) return EINVAL; @@ -621,7 +620,7 @@ int gcm_resource_add_label(gcm_resource_t *res, char const *key, res->labels_num++; return 0; -} /* }}} int gcm_resource_add_label */ +} /* }}} int sd_resource_add_label */ /* LabelDescriptor * @@ -662,9 +661,9 @@ static int format_label_descriptor(yajl_gen gen, char const *key) { * "displayName": string, * } */ -int gcm_format_metric_descriptor(char *buffer, size_t buffer_size, - data_set_t const *ds, value_list_t const *vl, - int ds_index) { +int sd_format_metric_descriptor(char *buffer, size_t buffer_size, + data_set_t const *ds, value_list_t const *vl, + int ds_index) { /* {{{ */ yajl_gen gen = yajl_gen_alloc(/* funcs = */ NULL); if (gen == NULL) { @@ -705,6 +704,6 @@ int gcm_format_metric_descriptor(char *buffer, size_t buffer_size, yajl_gen_free(gen); return 0; -} /* }}} int gcm_format_metric_descriptor */ +} /* }}} int sd_format_metric_descriptor */ /* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/src/utils_format_stackdriver.h b/src/utils_format_stackdriver.h new file mode 100644 index 00000000..fee260e3 --- /dev/null +++ b/src/utils_format_stackdriver.h @@ -0,0 +1,79 @@ +/** + * collectd - src/utils_format_stackdriver.h + * ISC license + * + * Copyright (C) 2017 Florian Forster + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Florian Forster + **/ + +#ifndef UTILS_FORMAT_STACKDRIVER_H +#define UTILS_FORMAT_STACKDRIVER_H 1 + +#include "collectd.h" +#include "plugin.h" + +/* sd_output_t is a buffer to which value_list_t* can be added and from which + * an appropriately formatted char* can be read. */ +struct sd_output_s; +typedef struct sd_output_s sd_output_t; + +/* sd_resource_t represents a MonitoredResource. */ +struct sd_resource_s; +typedef struct sd_resource_s sd_resource_t; + +sd_output_t *sd_output_create(sd_resource_t *res); + +/* sd_output_destroy frees all memory used by out, including the + * sd_resource_t* passed to sd_output_create. */ +void sd_output_destroy(sd_output_t *out); + +/* sd_output_add adds a value_list_t* to "out". + * + * Return values: + * - 0 Success + * - ENOBUFS Success, but the buffer should be flushed soon. + * - EEXIST The value list is already encoded in the buffer. + * Flush the buffer, then call sd_output_add again. + * - ENOENT First time we encounter this metric. Create a metric descriptor + * using the Stackdriver API and then call + * sd_output_register_metric. + */ +int sd_output_add(sd_output_t *out, data_set_t const *ds, + value_list_t const *vl); + +/* sd_output_register_metric adds the metric descriptor which vl maps to, to + * the list of known metric descriptors. */ +int sd_output_register_metric(sd_output_t *out, data_set_t const *ds, + value_list_t const *vl); + +/* sd_output_reset resets the output and returns the previous content of the + * buffer. It is the caller's responsibility to call free() with the returned + * pointer. */ +char *sd_output_reset(sd_output_t *out); + +sd_resource_t *sd_resource_create(char const *type); +void sd_resource_destroy(sd_resource_t *res); +int sd_resource_add_label(sd_resource_t *res, char const *key, + char const *value); + +/* sd_format_metric_descriptor creates the payload for a + * projects.metricDescriptors.create() request. */ +int sd_format_metric_descriptor(char *buffer, size_t buffer_size, + data_set_t const *ds, value_list_t const *vl, + int ds_index); + +#endif /* UTILS_FORMAT_STACKDRIVER_H */ diff --git a/src/utils_format_gcm_test.c b/src/utils_format_stackdriver_test.c similarity index 88% rename from src/utils_format_gcm_test.c rename to src/utils_format_stackdriver_test.c index 52d6dc9b..fa43866b 100644 --- a/src/utils_format_gcm_test.c +++ b/src/utils_format_stackdriver_test.c @@ -1,5 +1,5 @@ /** - * collectd - src/utils_format_gcm_test.c + * collectd - src/utils_format_stackdriver_test.c * ISC license * * Copyright (C) 2017 Florian Forster @@ -20,10 +20,10 @@ * Florian Forster **/ -#include "utils_format_gcm.h" #include "testing.h" +#include "utils_format_stackdriver.h" -DEF_TEST(gcm_format_metric_descriptor) { +DEF_TEST(sd_format_metric_descriptor) { value_list_t vl = { .host = "example.com", .plugin = "unit-test", .type = "example", }; @@ -38,7 +38,7 @@ DEF_TEST(gcm_format_metric_descriptor) { }, }; EXPECT_EQ_INT( - 0, gcm_format_metric_descriptor(got, sizeof(got), &ds_single, &vl, 0)); + 0, sd_format_metric_descriptor(got, sizeof(got), &ds_single, &vl, 0)); char const *want_single = "{\"type\":\"custom.googleapis.com/collectd/unit_test/" "example\",\"metricKind\":\"GAUGE\",\"valueType\":\"DOUBLE\",\"labels\":[" @@ -57,7 +57,7 @@ DEF_TEST(gcm_format_metric_descriptor) { }, }; EXPECT_EQ_INT( - 0, gcm_format_metric_descriptor(got, sizeof(got), &ds_double, &vl, 0)); + 0, sd_format_metric_descriptor(got, sizeof(got), &ds_double, &vl, 0)); char const *want_double = "{\"type\":\"custom.googleapis.com/collectd/unit_test/" "example_one\",\"metricKind\":\"CUMULATIVE\",\"valueType\":\"INT64\"," @@ -69,7 +69,7 @@ DEF_TEST(gcm_format_metric_descriptor) { } int main(int argc, char **argv) { - RUN_TEST(gcm_format_metric_descriptor); + RUN_TEST(sd_format_metric_descriptor); END_TEST; } diff --git a/src/write_gcm.c b/src/write_stackdriver.c similarity index 80% rename from src/write_gcm.c rename to src/write_stackdriver.c index 8ab1eec4..e6d3b74a 100644 --- a/src/write_gcm.c +++ b/src/write_stackdriver.c @@ -1,5 +1,5 @@ /** - * collectd - src/write_gcm.c + * collectd - src/write_stackdriver.c * ISC license * * Copyright (C) 2017 Florian Forster @@ -25,7 +25,7 @@ #include "common.h" #include "configfile.h" #include "plugin.h" -#include "utils_format_gcm.h" +#include "utils_format_stackdriver.h" #include "utils_gce.h" #include "utils_oauth.h" @@ -48,11 +48,11 @@ struct wg_callback_s { char *email; char *project; char *url; - gcm_resource_t *resource; + sd_resource_t *resource; /* runtime */ oauth_t *auth; - gcm_output_t *formatter; + sd_output_t *formatter; CURL *curl; char curl_errbuf[CURL_ERROR_SIZE]; /* used by flush */ @@ -104,7 +104,7 @@ static char *wg_get_authorization_header(wg_callback_t *cb) { /* {{{ */ else status = gce_access_token(cb->email, access_token, sizeof(access_token)); if (status != 0) { - ERROR("write_gcm plugin: Failed to get access token"); + ERROR("write_stackdriver plugin: Failed to get access token"); return NULL; } @@ -136,7 +136,7 @@ static int wg_call_metricdescriptor_create(wg_callback_t *cb, CURL *curl = curl_easy_init(); if (!curl) { - ERROR("write_gcm plugin: curl_easy_init failed."); + ERROR("write_stackdriver plugin: curl_easy_init failed."); curl_slist_free_all(headers); sfree(authorization_header); return -1; @@ -160,8 +160,9 @@ static int wg_call_metricdescriptor_create(wg_callback_t *cb, status = curl_easy_perform(curl); if (status != CURLE_OK) { - ERROR("write_gcm plugin: curl_easy_perform failed with status %d: %s", - status, curl_errbuf); + ERROR( + "write_stackdriver plugin: curl_easy_perform failed with status %d: %s", + status, curl_errbuf); sfree(res.memory); curl_easy_cleanup(curl); curl_slist_free_all(headers); @@ -172,9 +173,9 @@ static int wg_call_metricdescriptor_create(wg_callback_t *cb, long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if ((http_code < 200) || (http_code >= 300)) { - ERROR("write_gcm plugin: POST request to %s failed: HTTP error %ld", + ERROR("write_stackdriver plugin: POST request to %s failed: HTTP error %ld", final_url, http_code); - INFO("write_gcm plugin: Server replied: %s", res.memory); + INFO("write_stackdriver plugin: Server replied: %s", res.memory); sfree(res.memory); curl_easy_cleanup(curl); curl_slist_free_all(headers); @@ -225,8 +226,9 @@ static int wg_call_timeseries_write(wg_callback_t *cb, status = curl_easy_perform(cb->curl); if (status != CURLE_OK) { - ERROR("write_gcm plugin: curl_easy_perform failed with status %d: %s", - status, cb->curl_errbuf); + ERROR( + "write_stackdriver plugin: curl_easy_perform failed with status %d: %s", + status, cb->curl_errbuf); sfree(res.memory); curl_slist_free_all(headers); sfree(authorization_header); @@ -236,9 +238,9 @@ static int wg_call_timeseries_write(wg_callback_t *cb, long http_code = 0; curl_easy_getinfo(cb->curl, CURLINFO_RESPONSE_CODE, &http_code); if ((http_code < 200) || (http_code >= 300)) { - ERROR("write_gcm plugin: POST request to %s failed: HTTP error %ld", + ERROR("write_stackdriver plugin: POST request to %s failed: HTTP error %ld", final_url, http_code); - INFO("write_gcm plugin: Server replied: %s", res.memory); + INFO("write_stackdriver plugin: Server replied: %s", res.memory); sfree(res.memory); curl_slist_free_all(headers); sfree(authorization_header); @@ -256,15 +258,15 @@ static int wg_callback_init(wg_callback_t *cb) /* {{{ */ if (cb->curl != NULL) return 0; - cb->formatter = gcm_output_create(cb->resource); + cb->formatter = sd_output_create(cb->resource); if (cb->formatter == NULL) { - ERROR("write_gcm plugin: gcm_output_create failed."); + ERROR("write_stackdriver plugin: sd_output_create failed."); return -1; } cb->curl = curl_easy_init(); if (cb->curl == NULL) { - ERROR("write_gcm plugin: curl_easy_init failed."); + ERROR("write_stackdriver plugin: curl_easy_init failed."); return -1; } @@ -292,10 +294,11 @@ static int wg_flush_nolock(cdtime_t timeout, wg_callback_t *cb) /* {{{ */ return 0; } - char *payload = gcm_output_reset(cb->formatter); + char *payload = sd_output_reset(cb->formatter); int status = wg_call_timeseries_write(cb, payload); if (status != 0) { - ERROR("write_gcm plugin: Sending buffer failed with status %d.", status); + ERROR("write_stackdriver plugin: Sending buffer failed with status %d.", + status); } wg_reset_buffer(cb); @@ -318,7 +321,7 @@ static int wg_flush(cdtime_t timeout, /* {{{ */ if (cb->curl == NULL) { status = wg_callback_init(cb); if (status != 0) { - ERROR("write_gcm plugin: wg_callback_init failed."); + ERROR("write_stackdriver plugin: wg_callback_init failed."); pthread_mutex_unlock(&cb->lock); return -1; } @@ -336,7 +339,7 @@ static void wg_callback_free(void *data) /* {{{ */ if (cb == NULL) return; - gcm_output_destroy(cb->formatter); + sd_output_destroy(cb->formatter); cb->formatter = NULL; sfree(cb->email); @@ -357,10 +360,10 @@ static int wg_metric_descriptors_create(wg_callback_t *cb, const data_set_t *ds, for (size_t i = 0; i < ds->ds_num; i++) { char buffer[4096]; - int status = - gcm_format_metric_descriptor(buffer, sizeof(buffer), ds, vl, i); + int status = sd_format_metric_descriptor(buffer, sizeof(buffer), ds, vl, i); if (status != 0) { - ERROR("write_gcm plugin: gcm_format_metric_descriptor failed with status " + ERROR("write_stackdriver plugin: sd_format_metric_descriptor failed " + "with status " "%d", status); return status; @@ -368,14 +371,15 @@ static int wg_metric_descriptors_create(wg_callback_t *cb, const data_set_t *ds, status = wg_call_metricdescriptor_create(cb, buffer); if (status != 0) { - ERROR("write_gcm plugin: wg_call_metricdescriptor_create failed with " + ERROR("write_stackdriver plugin: wg_call_metricdescriptor_create failed " + "with " "status %d", status); return status; } } - return gcm_output_register_metric(cb->formatter, ds, vl); + return sd_output_register_metric(cb->formatter, ds, vl); } /* }}} int wg_metric_descriptors_create */ static int wg_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */ @@ -389,7 +393,7 @@ static int wg_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */ if (cb->curl == NULL) { int status = wg_callback_init(cb); if (status != 0) { - ERROR("write_gcm plugin: wg_callback_init failed."); + ERROR("write_stackdriver plugin: wg_callback_init failed."); pthread_mutex_unlock(&cb->lock); return status; } @@ -397,7 +401,7 @@ static int wg_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */ int status; while (42) { - status = gcm_output_add(cb->formatter, ds, vl); + status = sd_output_add(cb->formatter, ds, vl); if (status == 0) { /* success */ break; } else if (status == ENOBUFS) { /* success, flush */ @@ -432,7 +436,8 @@ static void wg_check_scope(char const *email) /* {{{ */ { char *scope = gce_scope(email); if (scope == NULL) { - WARNING("write_gcm plugin: Unable to determine scope of this instance."); + WARNING("write_stackdriver plugin: Unable to determine scope of this " + "instance."); return; } @@ -444,7 +449,7 @@ static void wg_check_scope(char const *email) /* {{{ */ while ((scope_len > 0) && (iscntrl((int)scope[scope_len - 1]))) scope[--scope_len] = 0; - WARNING("write_gcm plugin: The determined scope of this instance " + WARNING("write_stackdriver plugin: The determined scope of this instance " "(\"%s\") does not contain the monitoring scope (\"%s\"). You need " "to add this scope to the list of scopes passed to gcutil with " "--service_account_scopes when creating the instance. " @@ -459,7 +464,8 @@ static void wg_check_scope(char const *email) /* {{{ */ static int wg_config_resource(oconfig_item_t *ci, wg_callback_t *cb) /* {{{ */ { if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { - ERROR("write_gcm plugin: The \"%s\" option requires exactly one string " + ERROR("write_stackdriver plugin: The \"%s\" option requires exactly one " + "string " "argument.", ci->key); return EINVAL; @@ -467,12 +473,12 @@ static int wg_config_resource(oconfig_item_t *ci, wg_callback_t *cb) /* {{{ */ char *resource_type = ci->values[0].value.string; if (cb->resource != NULL) { - gcm_resource_destroy(cb->resource); + sd_resource_destroy(cb->resource); } - cb->resource = gcm_resource_create(resource_type); + cb->resource = sd_resource_create(resource_type); if (cb->resource == NULL) { - ERROR("write_gcm plugin: gcm_resource_create(\"%s\") failed.", + ERROR("write_stackdriver plugin: sd_resource_create(\"%s\") failed.", resource_type); return ENOMEM; } @@ -482,14 +488,15 @@ static int wg_config_resource(oconfig_item_t *ci, wg_callback_t *cb) /* {{{ */ if ((child->values_num != 1) || (child->values[0].type != OCONFIG_TYPE_STRING)) { - ERROR("write_gcm plugin: Resource labels must have exactly one string " + ERROR("write_stackdriver plugin: Resource labels must have exactly one " + "string " "value. Ignoring label \"%s\".", child->key); continue; } - gcm_resource_add_label(cb->resource, child->key, - child->values[0].value.string); + sd_resource_add_label(cb->resource, child->key, + child->values[0].value.string); } return 0; @@ -503,7 +510,7 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ wg_callback_t *cb = calloc(1, sizeof(*cb)); if (cb == NULL) { - ERROR("write_gcm plugin: calloc failed."); + ERROR("write_stackdriver plugin: calloc failed."); return ENOMEM; } cb->url = strdup(GCM_API_URL); @@ -524,7 +531,8 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ else if (strcasecmp("Resource", child->key) == 0) wg_config_resource(child, cb); else { - ERROR("write_gcm plugin: Invalid configuration option: %s.", child->key); + ERROR("write_stackdriver plugin: Invalid configuration option: %s.", + child->key); wg_callback_free(cb); return EINVAL; } @@ -536,7 +544,7 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ oauth_google_t cfg = oauth_create_google_file(credential_file, MONITORING_SCOPE); if (cfg.oauth == NULL) { - ERROR("write_gcm plugin: oauth_create_google_file failed"); + ERROR("write_stackdriver plugin: oauth_create_google_file failed"); wg_callback_free(cb); return EINVAL; } @@ -544,8 +552,9 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ if (cb->project == NULL) { cb->project = cfg.project_id; - INFO("write_gcm plugin: Automatically detected project ID: \"%s\"", - cb->project); + INFO( + "write_stackdriver plugin: Automatically detected project ID: \"%s\"", + cb->project); } else { sfree(cfg.project_id); } @@ -557,15 +566,17 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ if (cb->project == NULL) { cb->project = cfg.project_id; - INFO("write_gcm plugin: Automatically detected project ID: \"%s\"", - cb->project); + INFO( + "write_stackdriver plugin: Automatically detected project ID: \"%s\"", + cb->project); } else { sfree(cfg.project_id); } } if ((cb->auth != NULL) && (cb->email != NULL)) { - NOTICE("write_gcm plugin: A service account email was configured but is " + NOTICE("write_stackdriver plugin: A service account email was configured " + "but is " "not used for authentication because %s used instead.", (credential_file != NULL) ? "a credential file was" : "application default credentials were"); @@ -575,7 +586,8 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ if ((cb->auth == NULL) && gce_check()) { wg_check_scope(cb->email); } else if (cb->auth == NULL) { - ERROR("write_gcm plugin: Unable to determine credentials. Please either " + ERROR("write_stackdriver plugin: Unable to determine credentials. Please " + "either " "specify the \"Credentials\" option or set up Application Default " "Credentials."); wg_callback_free(cb); @@ -586,7 +598,7 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ cb->project = gce_project_id(); } if (cb->project == NULL) { - ERROR("write_gcm plugin: Unable to determine the project number. " + ERROR("write_stackdriver plugin: Unable to determine the project number. " "Please specify the \"Project\" option manually."); wg_callback_free(cb); return EINVAL; @@ -594,27 +606,28 @@ static int wg_config(oconfig_item_t *ci) /* {{{ */ if ((cb->resource == NULL) && gce_check()) { /* TODO(octo): add error handling */ - cb->resource = gcm_resource_create("gce_instance"); - gcm_resource_add_label(cb->resource, "project_id", gce_project_id()); - gcm_resource_add_label(cb->resource, "instance_id", gce_instance_id()); - gcm_resource_add_label(cb->resource, "zone", gce_zone()); + cb->resource = sd_resource_create("gce_instance"); + sd_resource_add_label(cb->resource, "project_id", gce_project_id()); + sd_resource_add_label(cb->resource, "instance_id", gce_instance_id()); + sd_resource_add_label(cb->resource, "zone", gce_zone()); } if (cb->resource == NULL) { /* TODO(octo): add error handling */ - cb->resource = gcm_resource_create("global"); - gcm_resource_add_label(cb->resource, "project_id", cb->project); + cb->resource = sd_resource_create("global"); + sd_resource_add_label(cb->resource, "project_id", cb->project); } - DEBUG("write_gcm plugin: Registering write callback with URL %s", cb->url); + DEBUG("write_stackdriver plugin: Registering write callback with URL %s", + cb->url); assert((cb->auth != NULL) || gce_check()); user_data_t user_data = { .data = cb, }; - plugin_register_flush("write_gcm", wg_flush, &user_data); + plugin_register_flush("write_stackdriver", wg_flush, &user_data); user_data.free_func = wg_callback_free; - plugin_register_write("write_gcm", wg_write, &user_data); + plugin_register_write("write_stackdriver", wg_write, &user_data); return 0; } /* }}} int wg_config */ @@ -630,8 +643,8 @@ static int wg_init(void) { void module_register(void) /* {{{ */ { - plugin_register_complex_config("write_gcm", wg_config); - plugin_register_init("write_gcm", wg_init); + plugin_register_complex_config("write_stackdriver", wg_config); + plugin_register_init("write_stackdriver", wg_init); } /* }}} void module_register */ /* vim: set sw=2 sts=2 et fdm=marker : */ -- 2.11.0