]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
resource: Add an option to configure resource attributes.
authorFlorian Forster <octo@collectd.org>
Tue, 19 Dec 2023 13:04:44 +0000 (14:04 +0100)
committerFlorian Forster <octo@collectd.org>
Thu, 28 Dec 2023 08:08:20 +0000 (09:08 +0100)
src/collectd.conf.in
src/collectd.conf.pod
src/daemon/configfile.c
src/daemon/resource.c
src/daemon/resource.h

index 15bb7cffd6387500bf378bfb7c737e438c6aae95..8b7fa7987d0bc8a131759d5147aff17a831e03e5 100644 (file)
 #PluginDir   "@libdir@/@PACKAGE_NAME@"
 #TypesDB     "@prefix@/share/@PACKAGE_NAME@/types.db"
 
+#<Resource "host">
+#      Attribute "custom.key" "custom.value"
+#</Resource>
+
 #----------------------------------------------------------------------------#
 # When enabled, plugins are loaded automatically with the default options    #
 # when an appropriate <Plugin ...> block is encountered.                     #
index e9f6a5ac4c4f49fcea86e1427f95c7450981c83e..737acb2829ae6f913656d55135dc6a6dc7cf59a1 100644 (file)
@@ -328,6 +328,51 @@ the daemon should try to figure out the "fully qualified domain name", FQDN.
 This is done using a lookup of the name returned by C<gethostname>. This option
 is enabled by default.
 
+=item B<Resource> I<Type>
+
+The B<Resource> block defined the I<Resource Attributes> to use for local
+metrics such as CPU usage, i.e. metrics that were not received from a remote
+system or service.
+
+The recommended way to configure resource attributes is by following the
+OpenTelemetry Semantic Conventions,
+L<https://opentelemetry.io/docs/specs/semconv/resource/>.
+
+The I<Type> argument determines which default attributes are automatically
+populated. B<Attribute> options inside the block can be used to add additional
+attributes or overwrite existing ones.
+
+Valid values for I<Type> are:
+
+=over 4
+
+=item B<Host> (default)
+
+For use with computing instances (e.g. physical and virtual machines). Will
+automatically populate the C<service.name>, C<host.name>, and C<host.id>
+attributes.
+
+For more information, refer to
+L<https://opentelemetry.io/docs/specs/semconv/resource/host/>.
+
+=item B<Generic>
+
+Minimal defaults for maximum flexibility. Only the C<service.name> attribute is
+populated.
+
+=back
+
+Inside the B<Resource> block, the following configuration options are valid:
+
+=over 4
+
+=item B<Attribute> I<Name> I<Value>
+
+Adds a resource attribute or updates an existing one. If I<Value> is the empty
+string, the attribute is deleted.
+
+=back
+
 =item B<PreCacheChain> I<ChainName>
 
 =item B<PostCacheChain> I<ChainName>
index b36c69eff83bb6736713a25b3da7b47113ad3222..b9bf8d63717d960c2f201bbc0c3e8cc532b7436a 100644 (file)
 
 #include "liboconfig/oconfig.h"
 
-#include "configfile.h"
-#include "filter_chain.h"
-#include "plugin.h"
-#include "types_list.h"
+#include "daemon/configfile.h"
+#include "daemon/filter_chain.h"
+#include "daemon/plugin.h"
+#include "daemon/resource.h"
+#include "daemon/types_list.h"
 #include "utils/common/common.h"
+#include "utils/strbuf/strbuf.h"
 
 #if HAVE_WORDEXP_H
 #include <wordexp.h>
@@ -87,6 +89,7 @@ static int dispatch_value_typesdb(oconfig_item_t *ci);
 static int dispatch_value_plugindir(oconfig_item_t *ci);
 static int dispatch_loadplugin(oconfig_item_t *ci);
 static int dispatch_block_plugin(oconfig_item_t *ci);
+static int dispatch_resource(oconfig_item_t *ci);
 
 /*
  * Private variables
@@ -94,10 +97,13 @@ static int dispatch_block_plugin(oconfig_item_t *ci);
 static cf_callback_t *first_callback;
 static cf_complex_callback_t *complex_callback_head;
 
-static cf_value_map_t cf_value_map[] = {{"TypesDB", dispatch_value_typesdb},
-                                        {"PluginDir", dispatch_value_plugindir},
-                                        {"LoadPlugin", dispatch_loadplugin},
-                                        {"Plugin", dispatch_block_plugin}};
+static cf_value_map_t cf_value_map[] = {
+    {"TypesDB", dispatch_value_typesdb},
+    {"PluginDir", dispatch_value_plugindir},
+    {"LoadPlugin", dispatch_loadplugin},
+    {"Plugin", dispatch_block_plugin},
+    {"Resource", dispatch_resource},
+};
 static int cf_value_map_num = STATIC_ARRAY_SIZE(cf_value_map);
 
 static cf_global_option_t cf_global_options[] = {
@@ -316,6 +322,74 @@ static int dispatch_loadplugin(oconfig_item_t *ci) {
   return ret_val;
 } /* int dispatch_value_loadplugin */
 
+static int format_config_value(strbuf_t *buf, oconfig_value_t v) {
+  switch (v.type) {
+  case OCONFIG_TYPE_STRING:
+    return strbuf_print(buf, v.value.string);
+  case OCONFIG_TYPE_NUMBER:
+    return strbuf_printf(buf, "%g", v.value.number);
+  case OCONFIG_TYPE_BOOLEAN:
+    return strbuf_print(buf, v.value.boolean ? "true" : "false");
+  default:
+    ERROR("configfile: Unexpected value type: %d", v.type);
+    return -1;
+  }
+}
+
+static int dispatch_resource(oconfig_item_t *ci) {
+  char type[128] = {0};
+  int status = cf_util_get_string_buffer(ci, type, sizeof(type));
+  if (status != 0) {
+    return status;
+  }
+
+  status = resource_attributes_init(type);
+  if (status != 0) {
+    return status;
+  }
+
+  for (int i = 0; i < ci->children_num; ++i) {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp("Attribute", child->key) == 0) {
+      if (child->values_num != 2) {
+        ERROR("configfile: The \"%s\" option requires two values, got %d.",
+              child->key, child->values_num);
+        return EINVAL;
+      }
+      if (child->values[0].type != OCONFIG_TYPE_STRING) {
+        ERROR("configfile: The first value of the \"%s\" option (the attribute "
+              "name) must be a string.",
+              child->key);
+        return EINVAL;
+      }
+      char const *key = child->values[0].value.string;
+
+      strbuf_t value = STRBUF_CREATE;
+      int status = format_config_value(&value, ci->values[1]);
+      if (status != 0) {
+        STRBUF_DESTROY(value);
+        return status;
+      }
+
+      status = resource_attribute_update(key, value.ptr);
+      if (status != 0) {
+        ERROR("configfile: default_resource_attributes_update failed: %s",
+              STRERROR(status));
+        STRBUF_DESTROY(value);
+        return status;
+      }
+
+      STRBUF_DESTROY(value);
+    } else {
+      ERROR("configfile: The option \"%s\" is not valid within \"%s\" blocks.",
+            child->key, ci->key);
+      return EINVAL;
+    }
+  }
+  return 0;
+} /* int dispatch_resource */
+
 static int dispatch_value(oconfig_item_t *ci) {
   int ret = 0;
 
index 6a132bd3eb890ea6e473672ef1f6eebe16c1751d..eebb98b3fed2fcb0cc32193b89977ed224457613 100644 (file)
@@ -104,7 +104,7 @@ static int machine_id(void) {
   return ENOENT;
 }
 
-static void init_default_resource(void) {
+static void resource_host_init(void) {
   if (default_resource.num != 0) {
     return;
   }
@@ -115,8 +115,34 @@ static void init_default_resource(void) {
   machine_id();
 }
 
+static void resource_generic_init(void) {
+  if (default_resource.num != 0) {
+    return;
+  }
+
+  otel_service_name();
+  otel_resource_attributes();
+}
+
+int resource_attributes_init(char const *type) {
+  if (strcasecmp("Host", type) == 0) {
+    resource_host_init();
+    return 0;
+  } else if (strcasecmp("Generic", type) == 0) {
+    resource_generic_init();
+    return 0;
+  }
+  ERROR("resource: The resource type \"%s\" is unknown.", type);
+  return ENOENT;
+}
+
+int resource_attribute_update(char const *key, char const *value) {
+  resource_host_init();
+  return label_set_add(&default_resource, key, value);
+}
+
 label_set_t default_resource_attributes(void) {
-  init_default_resource();
+  resource_host_init();
 
   return default_resource;
 }
index fb94153ef8503770aae6bef0b07e5e8a36bce3d7..179a74d0a420e84f18d582b476361f76d6a147db 100644 (file)
 #include "collectd.h"
 #include "daemon/metric.h"
 
+/* resource_attributes_init sets default resource attributes depending on
+ * "type". Returns ENOENT if type is not known. */
+int resource_attributes_init(char const *type);
+
+/* resource_attribute_update adds a gobal resource attribute. If an
+ * attribute of the same name already exists, it is overwritten. */
+int resource_attribute_update(char const *key, char const *value);
+
 label_set_t default_resource_attributes(void);
 
 #endif