subdir('meson' / 'tm-gmtoff') # Check for tm_gmtoff field in struct tm
subdir('meson' / 'mmap') # Check for mmap
subdir('meson' / 'libcap') # Libcap to drop capabilities
+subdir('meson' / 'libcurl') # Libcurl for OTLPLogger
subdir('meson' / 'libedit') # Libedit
subdir('meson' / 'libsodium') # Libsodium
subdir('meson' / 'libcrypto') # OpenSSL libcrypto
src_dir / 'libssl.cc',
src_dir / 'logging.cc',
src_dir / 'misc.cc',
+ src_dir / 'otlp_logger.cc',
src_dir / 'protozero.cc',
src_dir / 'protozero-trace.cc',
src_dir / 'proxy-protocol.cc',
],
'condition': dep_cdb.found(),
},
+ 'minicurl': {
+ 'sources': [
+ src_dir / 'minicurl.cc',
+ ],
+ 'condition': get_option('otlp').allowed() and dep_libcurl.found(),
+ },
'doq': {
'sources': [
src_dir / 'doq.cc',
dep_ipcrypt2,
dep_libcap,
dep_libcrypto,
+ dep_libcurl,
dep_gnutls,
dep_libedit,
dep_json11,
--- /dev/null
+opt_otlp = get_option('otlp')
+opt_libcurl = get_option('libcurl')
+
+if opt_otlp.allowed() and opt_libcurl.allowed()
+ dep_libcurl = dependency('libcurl', version: '>= 7.21.3', required: false)
+else
+ dep_libcurl = dependency('', required: false)
+endif
+
+conf.set('HAVE_LIBCURL', dep_libcurl.found(), description: 'Whether we have libcurl')
+summary('cURL', dep_libcurl.found(), bool_yn: true, section: 'Configuration')
+summary('OTLP remote logger', dep_libcurl.found() and opt_otlp.allowed(), bool_yn: true, section: 'Configuration')
option('libcap', type: 'feature', value: 'auto', description: 'Enable libcap for capabilities handling')
option('libedit', type: 'feature', value: 'enabled', description: 'Enable libedit')
option('libsodium', type: 'feature', value: 'auto', description: 'Enable libsodium')
+option('libcurl', type: 'feature', value: 'auto', description: 'Enable libcurl (for the OTLP remote logger)')
option('libcrypto', type: 'feature', value: 'auto', description: 'Enable OpenSSL libcrypto)')
option('libcrypto-path', type: 'string', value: '', description: 'Custom path to find OpenSSL libcrypto')
option('tls-gnutls', type: 'feature', value: 'auto', description: 'GnuTLS-based TLS')
option('auto-var-init', type: 'combo', value: 'disabled', choices: ['zero', 'pattern', 'disabled'], description: 'Enable initialization of automatic variables')
option('snmp', type: 'feature', value: 'disabled', description: 'Enable SNMP')
option('dnstap', type: 'feature', value: 'auto', description: 'Enable DNSTAP support through libfstrm')
+option('otlp', type: 'feature', value: 'auto', description: 'Enable OTLP support')
option('nghttp2', type: 'feature', value: 'auto', description: 'Enable nghttp2 library support for DNS over HTTP/2')
option('cdb', type: 'feature', value: 'auto', description: 'CDB key-value store support')
option('lmdb', type: 'feature', value: 'auto', description: 'LMDB key-value store support')
--- /dev/null
+../minicurl.cc
\ No newline at end of file
--- /dev/null
+../minicurl.hh
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <memory>
+#include <stdexcept>
+
+#include "otlp_logger.hh"
+#include "remote_logger.hh"
+
+#if !defined(DISABLE_PROTOBUF) && defined(HAVE_LIBCURL)
+#include "minicurl.hh"
+#include "protozero-trace.hh"
+#include "protozero-otlp.hh"
+
+OTLPLogger::OTLPLogger(std::string address) :
+ d_address(std::move(address))
+{
+ LoggerType loggerType;
+ if (d_address.find("http://") == 0 || d_address.find("https://") == 0) {
+ loggerType = LoggerType::HTTP;
+ }
+ else if (d_address.find("grpc://") == 0 || d_address.find("grpcs://") == 0) {
+ // XXX: this is not the actual scheme, see https://github.com/grpc/grpc/blob/master/doc/naming.md
+ loggerType = LoggerType::gRPC;
+ }
+ else {
+ throw std::runtime_error("Can not determine OTLP logger type from address " + address);
+ }
+ d_type = loggerType;
+
+ switch (d_type) {
+ case LoggerType::HTTP:
+ d_httpConn = std::make_unique<MiniCurl>("dnsdist/" + std::string(PACKAGE_VERSION));
+ break;
+ case LoggerType::gRPC:
+ throw std::runtime_error("gRPC support is not implemented");
+ }
+}
+
+RemoteLoggerInterface::Result OTLPLogger::queueData(const pdns::trace::TracesData& data)
+{
+ pdns::trace::ExportTraceServiceRequest req = {
+ .resource_spans = data.resource_spans
+ };
+ std::string buf;
+ protozero::pbf_writer writer(buf);
+ req.encode(writer);
+ return queueData(buf);
+}
+
+RemoteLoggerInterface::Result OTLPLogger::queueData(const std::string& data)
+{
+ // TODO: Proper queuing, batching, and retries
+ switch (d_type) {
+ case LoggerType::HTTP:
+ return queueHttpData(data);
+ case LoggerType::gRPC:
+ // Should never get here
+ throw std::runtime_error("gRPC support is not implemented");
+ }
+}
+
+RemoteLoggerInterface::Result OTLPLogger::queueHttpData(const std::string& data)
+{
+ auto response = d_httpConn->postURL(d_address, data, d_httpHeaders);
+ std::cout<<response<<std::endl;
+ protozero::pbf_reader reader(response);
+ auto exportTraceServiceResponse = pdns::trace::ExportTraceServiceResponse::decode(reader);
+ if (exportTraceServiceResponse.partial_success.rejected_spans == 0) {
+ return RemoteLoggerInterface::Result::Queued;
+ }
+ return RemoteLoggerInterface::Result::OtherError;
+}
+#endif /* !defined(DISABLE_PROTOBUF) && defined(HAVE_LIBCURL) */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "remote_logger.hh"
+#include <memory>
+
+#if !defined(DISABLE_PROTOBUF) && defined(HAVE_LIBCURL)
+#include <memory>
+
+#include "logr.hh"
+#include "minicurl.hh"
+class OTLPLogger : public RemoteLoggerInterface
+{
+public:
+ enum class LoggerType : uint8_t
+ {
+ HTTP,
+ gRPC,
+ };
+
+ OTLPLogger(std::string address);
+ OTLPLogger(const OTLPLogger&) = delete;
+ OTLPLogger(OTLPLogger&&) = delete;
+ OTLPLogger& operator=(const OTLPLogger&) = delete;
+ OTLPLogger& operator=(OTLPLogger&&) = delete;
+ ~OTLPLogger() override {};
+
+ [[nodiscard]] RemoteLoggerInterface::Result queueData(const std::string& data) override;
+ [[nodiscard]] RemoteLoggerInterface::Result queueData(const pdns::trace::TracesData& data);
+
+ [[nodiscard]] std::string address() const override
+ {
+ return d_address;
+ }
+
+ [[nodiscard]] std::string name() const override
+ {
+ return "OTLP";
+ }
+
+ [[nodiscard]] std::string toString() override
+ {
+ return "OTLPLogger to " + d_address;
+ }
+
+ [[nodiscard]] RemoteLoggerInterface::Stats getStats() override
+ {
+ return Stats{.d_queued = 0,
+ .d_pipeFull = 0,
+ .d_tooLarge = 0,
+ .d_otherError = 0};
+ }
+
+private:
+ LoggerType d_type;
+ std::string d_address;
+
+ std::unique_ptr<MiniCurl> d_httpConn{nullptr};
+ MiniCurl::MiniCurlHeaders d_httpHeaders{{"Content-Type", "application/x-protobuf"}};
+ [[nodiscard]] RemoteLoggerInterface::Result queueHttpData(const std::string& data);
+};
+#else
+class OTLPLogger : public RemoteLoggerInterface
+{
+ OTLPLogger(const OTLPLogger&) = delete;
+ OTLPLogger(OTLPLogger&&) = delete;
+ OTLPLogger& operator=(const OTLPLogger&) = delete;
+ OTLPLogger& operator=(OTLPLogger&&) = delete;
+
+public:
+ [[nodiscard]] RemoteLoggerInterface::Result queueData([[maybe_unused]] const std::string& data) override
+ {
+ return RemoteLogger::Result::Queued;
+ }
+ RemoteLoggerInterface::Result queueData([[maybe_unused]] const TracesData& data)
+ {
+ return RemoteLogger::Result::Queued;
+ }
+};
+#endif /* !defined(DISABLE_PROTOBUF) && defined(HAVE_LIBCURL) */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include <protozero/pbf_reader.hpp>
+#include <protozero/pbf_writer.hpp>
+#include <vector>
+
+#include "protozero-trace.hh"
+
+namespace pdns::trace
+{
+// https://github.com/open-telemetry/opentelemetry-proto/blob/v1.10.0/opentelemetry/proto/collector/trace/v1/trace_service.proto
+
+struct ExportTraceServiceRequest
+{
+ // This message is the same as TracesData
+ std::vector<ResourceSpans> resource_spans; // = 1
+
+ void encode(protozero::pbf_writer& writer) const
+ {
+ pdns::trace::encode(writer, 1, resource_spans);
+ }
+
+ static ExportTraceServiceRequest decode(protozero::pbf_reader& reader);
+};
+
+struct ExportTracePartialSuccess
+{
+ int64_t rejected_spans; // = 1
+ std::string error_message; // = 2
+
+ void encode(protozero::pbf_writer& writer) const;
+ static ExportTracePartialSuccess decode(protozero::pbf_reader& reader) {
+ ExportTracePartialSuccess ret;
+ while (reader.next()) {
+ switch (reader.tag()) {
+ case 1:
+ ret.rejected_spans = reader.get_int64();
+ case 2:
+ ret.error_message = reader.get_string();
+ }
+ }
+ return ret;
+ };
+};
+
+struct ExportTraceServiceResponse
+{
+ ExportTracePartialSuccess partial_success; // = 1
+
+ void encode(protozero::pbf_writer& writer) const;
+ static ExportTraceServiceResponse decode(protozero::pbf_reader& reader)
+ {
+ ExportTraceServiceResponse ret;
+ while (reader.next()) {
+ switch (reader.tag()) {
+ case 1:
+ auto sub = reader.get_message();
+ ret.partial_success = ExportTracePartialSuccess::decode(sub);
+ }
+ }
+ return ret;
+ }
+};
+
+} // namespace pdns::trace
"libcap-dev",
"catch2",
"libcdb-dev",
+ "libcurl4",
"libedit-dev",
"libfstrm-dev",
"libgnutls28-dev",
"-D ebpf=enabled",
"-D ipcipher=enabled",
"-D ipcrypt2=enabled",
+ "-D libcurl=enabled",
"-D libedit=enabled",
"-D libsodium=enabled",
"-D lmdb=enabled",
"-D reproducible=true",
"-D snmp=enabled",
"-D yaml=enabled",
+ "-D otlp=enabled",
]
)
"-D ebpf=disabled",
"-D ipcipher=disabled",
"-D ipcrypt2=disabled",
+ "-D libcurl=disabled",
"-D libedit=disabled",
"-D libsodium=disabled",
"-D lmdb=disabled",
"-D reproducible=false",
"-D snmp=disabled",
"-D yaml=disabled",
+ "-D otlp=disabled",
]
)