]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
New utility: format OpenTelemetry.
authorFlorian Forster <octo@collectd.org>
Sat, 2 Dec 2023 06:52:10 +0000 (07:52 +0100)
committerFlorian Forster <octo@collectd.org>
Wed, 3 Jan 2024 16:16:28 +0000 (17:16 +0100)
This new utility formats a metric family as an OpenTelemetry
"ResourceMetric" and writes the serialized protocol buffer to the provided
string buffer.

Makefile.am
build.sh
src/utils/format_open_telemetry/format_open_telemetry.cc [new file with mode: 0644]
src/utils/format_open_telemetry/format_open_telemetry.h [new file with mode: 0644]

index 18fdc3e332dbaa53a1239198bdc49e8c0cb679b2..02f942fe5b0c0a1ac63488dcea03e8f747975bb7 100644 (file)
@@ -132,6 +132,7 @@ noinst_LTLIBRARIES = \
        libcommon.la \
        libformat_graphite.la \
        libformat_influxdb.la \
+       libformat_open_telemetry.la \
        libheap.la \
        libignorelist.la \
        liblatency.la \
@@ -454,10 +455,6 @@ libplugin_mock_la_SOURCES = \
 libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME
 libplugin_mock_la_LIBADD = libmetric.la liboconfig.la libcommon.la libignorelist.la $(COMMON_LIBS)
 
-libformat_influxdb_la_SOURCES = \
-       src/utils/format_influxdb/format_influxdb.c \
-       src/utils/format_influxdb/format_influxdb.h
-
 libformat_graphite_la_SOURCES = \
        src/utils/format_graphite/format_graphite.c \
        src/utils/format_graphite/format_graphite.h
@@ -472,6 +469,28 @@ test_format_graphite_LDADD = \
        libstrbuf.la \
        -lm
 
+libformat_influxdb_la_SOURCES = \
+       src/utils/format_influxdb/format_influxdb.c \
+       src/utils/format_influxdb/format_influxdb.h
+
+BUILT_SOURCES += \
+       src/opentelemetry/proto/common/v1/common.pb.cc \
+       src/opentelemetry/proto/common/v1/common.pb.h \
+       src/opentelemetry/proto/metrics/v1/metrics.pb.cc \
+       src/opentelemetry/proto/metrics/v1/metrics.pb.h \
+       src/opentelemetry/proto/resource/v1/resource.pb.cc \
+       src/opentelemetry/proto/resource/v1/resource.pb.h
+libformat_open_telemetry_la_SOURCES = \
+       src/utils/format_open_telemetry/format_open_telemetry.cc \
+       src/utils/format_open_telemetry/format_open_telemetry.h \
+       src/opentelemetry/proto/common/v1/common.pb.cc \
+       src/opentelemetry/proto/common/v1/common.pb.h \
+       src/opentelemetry/proto/metrics/v1/metrics.pb.cc \
+       src/opentelemetry/proto/metrics/v1/metrics.pb.h \
+       src/opentelemetry/proto/resource/v1/resource.pb.cc \
+       src/opentelemetry/proto/resource/v1/resource.pb.h
+libformat_open_telemetry_la_CPPFLAGS = $(AM_CPPFLAGS)
+
 if BUILD_WITH_LIBYAJL
 noinst_LTLIBRARIES += libformat_json.la
 libformat_json_la_SOURCES = \
index c0ccce3a5919dbdde3888c9bd8244bcc41040693..0fe9142dad643788245ca1fd052d6fb989a682bb 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -55,6 +55,10 @@ build()
     && $libtoolize --copy --force \
     && automake --add-missing --copy \
     && autoconf
+
+    for f in common/v1/common.proto metrics/v1/metrics.proto resource/v1/resource.proto; do
+      protoc -Iopentelemetry-proto --cpp_out src/ "opentelemetry-proto/opentelemetry/proto/${f}"
+    done
 }
 
 build_cygwin()
diff --git a/src/utils/format_open_telemetry/format_open_telemetry.cc b/src/utils/format_open_telemetry/format_open_telemetry.cc
new file mode 100644 (file)
index 0000000..771332a
--- /dev/null
@@ -0,0 +1,142 @@
+/**
+ * collectd - src/utils_format_open_telemetry.c
+ * Copyright (C) 2023       Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+extern "C" {
+#include "collectd.h"
+#include "metric.h"
+
+#include "utils/format_open_telemetry/format_open_telemetry.h"
+}
+
+#include "opentelemetry/proto/common/v1/common.pb.h"
+#include "opentelemetry/proto/metrics/v1/metrics.pb.h"
+#include "opentelemetry/proto/resource/v1/resource.pb.h"
+
+using opentelemetry::proto::common::v1::AnyValue;
+using opentelemetry::proto::common::v1::InstrumentationScope;
+using opentelemetry::proto::common::v1::KeyValue;
+using opentelemetry::proto::metrics::v1::AGGREGATION_TEMPORALITY_CUMULATIVE;
+using opentelemetry::proto::metrics::v1::Gauge;
+using opentelemetry::proto::metrics::v1::Metric;
+using opentelemetry::proto::metrics::v1::NumberDataPoint;
+using opentelemetry::proto::metrics::v1::ResourceMetrics;
+using opentelemetry::proto::metrics::v1::ScopeMetrics;
+using opentelemetry::proto::metrics::v1::Sum;
+
+static void metric_to_number_data_point(NumberDataPoint *dp, metric_t const *m) {
+  for (size_t i = 0; i < m->label.num; i++) {
+    label_pair_t *l = m->label.ptr + i;
+
+    KeyValue *kv = dp->add_attributes();
+    kv->set_key(l->name);
+    AnyValue *v = kv->mutable_value();
+    v->set_string_value(l->value);
+  }
+
+  dp->set_time_unix_nano(CDTIME_T_TO_NS(m->time));
+  // TODO(): also set "start time". We may need to use the cache to determine
+  // when we've seen a metric for the first time.
+
+  switch (m->family->type) {
+    case METRIC_TYPE_COUNTER:
+      dp->set_as_int(m->value.derive);
+    case METRIC_TYPE_GAUGE:
+      dp->set_as_double(m->value.gauge);
+    case METRIC_TYPE_UNTYPED:
+      // TODO
+      assert(0);
+  }
+}
+
+static void set_sum(Metric *m, metric_family_t const *fam) {
+  Sum *s = m->mutable_sum();
+  for (size_t i = 0; i < fam->metric.num; i++) {
+    NumberDataPoint *dp = s->add_data_points();
+    metric_to_number_data_point(dp, fam->metric.ptr + i);
+  }
+
+  s->set_aggregation_temporality(AGGREGATION_TEMPORALITY_CUMULATIVE);
+  s->set_is_monotonic(true);
+}
+
+static void set_gauge(Metric *m, metric_family_t const *fam) {
+  Gauge *g = m->mutable_gauge();
+  for (size_t i = 0; i < fam->metric.num; i++) {
+    NumberDataPoint *dp = g->add_data_points();
+    metric_to_number_data_point(dp, fam->metric.ptr + i);
+  }
+}
+
+static void add_metric(ScopeMetrics *sm, metric_family_t const *fam) {
+  Metric *m = sm->add_metrics();
+
+  m->set_name(fam->name);
+  if (fam->help != NULL) {
+    m->set_description(fam->help);
+  }
+
+  switch (fam->type) {
+    case METRIC_TYPE_COUNTER:
+      set_sum(m, fam);
+      return;
+    case METRIC_TYPE_GAUGE:
+      set_gauge(m, fam);
+      return;
+    case METRIC_TYPE_UNTYPED:
+      // TODO
+      assert(0);
+  }
+}
+
+static void set_instrumentation_scope(ScopeMetrics *sm) {
+  InstrumentationScope *is = sm->mutable_scope();
+  is->set_name(PACKAGE_NAME);
+  is->set_version(PACKAGE_VERSION);
+}
+
+static void set_scope_metrics(ResourceMetrics *rm, metric_family_t const *fam) {
+  ScopeMetrics *sm = rm->add_scope_metrics();
+
+  set_instrumentation_scope(sm);
+
+  add_metric(sm, fam);
+}
+
+int format_open_telemetry(strbuf_t *sb, metric_family_t const *fam) {
+  ResourceMetrics rm;
+
+  set_scope_metrics(&rm, fam);
+
+  std::string serialization;
+  bool ok = rm.SerializeToString(&serialization);
+  if (!ok) {
+    return -1;
+  }
+
+  strbuf_print(sb, serialization.c_str());
+  return 0;
+}
+
diff --git a/src/utils/format_open_telemetry/format_open_telemetry.h b/src/utils/format_open_telemetry/format_open_telemetry.h
new file mode 100644 (file)
index 0000000..4120dc9
--- /dev/null
@@ -0,0 +1,35 @@
+/**
+ * collectd - src/utils_format_open_telemetry.h
+ * Copyright (C) 2023       Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_FORMAT_OPEN_TELEMETRY_H
+#define UTILS_FORMAT_OPEN_TELEMETRY_H 1
+
+#include "collectd.h"
+#include "metric.h"
+
+int format_open_telemetry(strbuf_t *sb, metric_family_t const *fam); // TODO: lacks return value
+
+#endif /* UTILS_FORMAT_OPEN_TELEMETRY_H */