Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion api/envoy/extensions/tracers/opentelemetry/samplers/v3/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")
licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_xds//udpa/annotations:pkg"],
deps = [
"//envoy/config/core/v3:pkg",
"@com_github_cncf_xds//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ syntax = "proto3";

package envoy.extensions.tracers.opentelemetry.samplers.v3;

import "envoy/config/core/v3/http_uri.proto";

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.samplers.v3";
Expand All @@ -17,4 +19,8 @@ message DynatraceSamplerConfig {
string tenant_id = 1;

string cluster_id = 2;

config.core.v3.HttpUri http_uri = 3;

string token = 4;
}
1 change: 1 addition & 0 deletions source/extensions/tracers/opentelemetry/samplers/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ envoy_cc_library(
"//envoy/server:tracer_config_interface",
"//source/common/common:logger_lib",
"//source/common/config:utility_lib",
"@envoy_api//envoy/config/trace/v3:pkg_cc_proto",
"@opentelemetry_proto//:trace_cc_proto",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,21 @@ envoy_cc_library(
srcs = [
"dynatrace_sampler.cc",
"dynatrace_tracestate.cc",
"sampler_config_fetcher.cc",
"tracestate.cc",
],
hdrs = [
"dynatrace_sampler.h",
"dynatrace_tracestate.h",
"sampler_config.h",
"sampler_config_fetcher.h",
"tracestate.h",
],
deps = [
"//source/common/config:datasource_lib",
"//source/extensions/tracers/opentelemetry:opentelemetry_tracer_lib",
"//source/extensions/tracers/opentelemetry/samplers:sampler_lib",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ FW4Tag DynatraceSampler::getFW4Tag(const Tracestate& tracestate) {

DynatraceSampler::DynatraceSampler(
const envoy::extensions::tracers::opentelemetry::samplers::v3::DynatraceSamplerConfig& config,
Server::Configuration::TracerFactoryContext& /*context*/)
Server::Configuration::TracerFactoryContext& context)
: tenant_id_(config.tenant_id()), cluster_id_(config.cluster_id()),
dt_tracestate_entry_(tenant_id_, cluster_id_), counter_(0) {}
dt_tracestate_entry_(tenant_id_, cluster_id_),
sampler_config_fetcher_(context, config.http_uri(), config.token()), counter_(0) {}

SamplingResult DynatraceSampler::shouldSample(const absl::optional<SpanContext> parent_context,
const std::string& /*trace_id*/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "source/common/common/logger.h"
#include "source/common/config/datasource.h"
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/dynatrace_tracestate.h"
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher.h"
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/tracestate.h"
#include "source/extensions/tracers/opentelemetry/samplers/sampler.h"

Expand Down Expand Up @@ -35,6 +36,7 @@ class DynatraceSampler : public Sampler, Logger::Loggable<Logger::Id::tracing> {
std::string tenant_id_;
std::string cluster_id_;
DtTracestateEntry dt_tracestate_entry_;
SamplerConfigFetcher sampler_config_fetcher_;
std::atomic<uint32_t> counter_; // request counter for dummy sampling
FW4Tag getFW4Tag(const Tracestate& tracestate);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <atomic>
#include <cstdint>
#include <string>
#include <utility>

#include "source/common/json/json_loader.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

class SamplerConfig {
public:
static constexpr uint64_t ROOT_SPANS_PER_MINUTE_DEFAULT = 1000;

void parse(const std::string& json) {
root_spans_per_minute_.store(ROOT_SPANS_PER_MINUTE_DEFAULT); // reset to default
auto result = Envoy::Json::Factory::loadFromStringNoThrow(json);
if (result.ok()) {
auto obj = result.value();
if (obj->hasObject("rootSpansPerMinute")) {
auto value = obj->getInteger("rootSpansPerMinute", ROOT_SPANS_PER_MINUTE_DEFAULT);
root_spans_per_minute_.store(value);
}
(void)obj;
}
}

uint64_t getRootSpansPerMinute() const { return root_spans_per_minute_.load(); }

private:
std::atomic<uint64_t> root_spans_per_minute_ = ROOT_SPANS_PER_MINUTE_DEFAULT;
};

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config_fetcher.h"

#include "source/common/common/enum_to_int.h"
#include "source/common/http/utility.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

static constexpr std::chrono::seconds INITIAL_TIMER_DURATION{10};
static constexpr std::chrono::minutes TIMER_INTERVAL{5};

SamplerConfigFetcher::SamplerConfigFetcher(Server::Configuration::TracerFactoryContext& context,
const envoy::config::core::v3::HttpUri& http_uri,
const std::string& token)
: cluster_manager_(context.serverFactoryContext().clusterManager()), http_uri_(http_uri),
parsed_authorization_header_to_add_(
{Http::LowerCaseString("authorization"), absl::StrCat("Api-Token ", token)}),
sampler_config_() {

timer_ = context.serverFactoryContext().mainThreadDispatcher().createTimer([this]() -> void {
const auto thread_local_cluster = cluster_manager_.getThreadLocalCluster(http_uri_.cluster());
if (thread_local_cluster == nullptr) {
ENVOY_LOG(error, "SamplerConfigFetcher failed: [cluster = {}] is not configured",
http_uri_.cluster());
} else {
Http::RequestMessagePtr message = Http::Utility::prepareHeaders(http_uri_);
// TODO: set path once it is finalized in TI-8742
// message->headers().setPath("path/to/sampler/service");
message->headers().setReferenceMethod(Http::Headers::get().MethodValues.Get);
message->headers().setReference(parsed_authorization_header_to_add_.first,
parsed_authorization_header_to_add_.second);
active_request_ = thread_local_cluster->httpAsyncClient().send(
Comment thread
joaopgrassi marked this conversation as resolved.
std::move(message), *this,
Http::AsyncClient::RequestOptions().setTimeout(std::chrono::milliseconds(6000)));
}
});

timer_->enableTimer(std::chrono::seconds(INITIAL_TIMER_DURATION));
}

SamplerConfigFetcher::~SamplerConfigFetcher() {
if (active_request_) {
active_request_->cancel();
}
}

void SamplerConfigFetcher::onSuccess(const Http::AsyncClient::Request& /*request*/,
Http::ResponseMessagePtr&& http_response) {
onRequestDone();
const auto response_code = Http::Utility::getResponseStatus(http_response->headers());
if (response_code != enumToInt(Http::Code::OK)) {
ENVOY_LOG(error, "SamplerConfigFetcher received a non-success status code: {}", response_code);
} else {
ENVOY_LOG(info, "SamplerConfigFetcher received success status code: {}", response_code);
sampler_config_.parse(http_response->bodyAsString());
}
}

void SamplerConfigFetcher::onFailure(const Http::AsyncClient::Request& /*request*/,
Http::AsyncClient::FailureReason reason) {
onRequestDone();
ENVOY_LOG(info, "The OTLP export request failed. Reason {}", enumToInt(reason));
}

void SamplerConfigFetcher::onRequestDone() {
// TODO: should we re-enable timer after send() to avoid having the request duration added to the
// timer? If so, we would need a list containing the active requests (not a single pointer)
active_request_ = nullptr;
timer_->enableTimer(std::chrono::seconds(TIMER_INTERVAL));
}

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

#include <utility>
#include <vector>

#include "envoy/config/core/v3/http_service.pb.h"
#include "envoy/config/core/v3/http_uri.pb.h"
#include "envoy/extensions/tracers/opentelemetry/samplers/v3/dynatrace_sampler.pb.h"
#include "envoy/http/async_client.h"
#include "envoy/http/message.h"
#include "envoy/server/tracer_config.h"

#include "source/common/http/async_client_impl.h"
#include "source/common/http/async_client_utility.h"
#include "source/common/http/headers.h"
#include "source/common/http/message_impl.h"
#include "source/common/http/utility.h"
#include "source/extensions/tracers/opentelemetry/samplers/dynatrace/sampler_config.h"

namespace Envoy {
namespace Extensions {
namespace Tracers {
namespace OpenTelemetry {

class SamplerConfigFetcher : public Logger::Loggable<Logger::Id::tracing>,
public Http::AsyncClient::Callbacks {
public:
SamplerConfigFetcher(Server::Configuration::TracerFactoryContext& context,
const envoy::config::core::v3::HttpUri& http_uri, const std::string& token);

void onSuccess(const Http::AsyncClient::Request& request,
Http::ResponseMessagePtr&& response) override;

void onFailure(const Http::AsyncClient::Request& request,
Http::AsyncClient::FailureReason reason) override;
void onBeforeFinalizeUpstreamSpan(Envoy::Tracing::Span& /*span*/,
const Http::ResponseHeaderMap* /*response_headers*/) override{};

const SamplerConfig& getSamplerConfig() const { return sampler_config_; }

~SamplerConfigFetcher() override;

private:
Event::TimerPtr timer_;
Upstream::ClusterManager& cluster_manager_;
envoy::config::core::v3::HttpUri http_uri_;
std::pair<const Http::LowerCaseString, const std::string> parsed_authorization_header_to_add_;
Http::AsyncClient::Request* active_request_{};
SamplerConfig sampler_config_;

void onRequestDone();
};

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
1 change: 1 addition & 0 deletions source/extensions/tracers/opentelemetry/samplers/sampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>

#include "envoy/common/optref.h"
#include "envoy/config/trace/v3/opentelemetry.pb.h"
#include "envoy/config/typed_config.h"
#include "envoy/server/tracer_config.h"
#include "envoy/tracing/trace_context.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ envoy_extension_cc_test(
srcs = [
"dynatrace_sampler_test.cc",
"dynatrace_tracestate_test.cc",
"sampler_config_fetcher_test.cc",
"sampler_config_test.cc",
"tracestate_test.cc",
],
extension_names = ["envoy.tracers.opentelemetry.samplers.dynatrace"],
deps = [
"//source/extensions/tracers/opentelemetry/samplers/dynatrace:dynatrace_sampler_lib",
"//test/mocks/server:tracer_factory_context_mocks",
"//test/test_common:utility_lib",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@envoy_api//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg_cc_proto",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ TEST(DynatraceSamplerFactoryTest, Test) {
EXPECT_NE(factory->createEmptyConfigProto(), nullptr);

envoy::config::core::v3::TypedExtensionConfig typed_config;
const std::string yaml = R"EOF(
const std::string sampler_yaml = R"EOF(
name: envoy.tracers.opentelemetry.samplers.dynatrace
typed_config:
"@type": type.googleapis.com/envoy.extensions.tracers.opentelemetry.samplers.v3.DynatraceSamplerConfig
)EOF";
TestUtility::loadFromYaml(yaml, typed_config);
TestUtility::loadFromYaml(sampler_yaml, typed_config);

NiceMock<Server::Configuration::MockTracerFactoryContext> context;
EXPECT_NE(factory->createSampler(typed_config.typed_config(), context), nullptr);
EXPECT_STREQ(factory->name().c_str(), "envoy.tracers.opentelemetry.samplers.dynatrace");
Expand Down
Loading