Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c6ece86
Refactor gRPC exporter to use general base class we can later reuse
AlexanderEllis Jun 19, 2023
b59764e
Update OpenTelemetryConfig with HTTP-related config
AlexanderEllis Jun 20, 2023
ad99eb0
Write and wire up HTTP trace exporter
AlexanderEllis Jun 20, 2023
15fa601
Code formatting
AlexanderEllis Jun 20, 2023
8feddf1
Proto format
AlexanderEllis Jun 20, 2023
0a4f183
Add basic tests
AlexanderEllis Jun 23, 2023
5e4f9a6
code format
AlexanderEllis Jun 23, 2023
c058475
Add additional counters for http exporter and test
AlexanderEllis Jul 18, 2023
1a6d2fc
Formatting
AlexanderEllis Jul 18, 2023
bf51b6e
Coverage improvements
AlexanderEllis Jul 18, 2023
40cd7fc
Formatting
AlexanderEllis Jul 18, 2023
0a20370
Add higher level Driver test for HTTP exporting
AlexanderEllis Jul 19, 2023
a498727
More formatting
AlexanderEllis Jul 19, 2023
ccf877c
Clang tidy
AlexanderEllis Jul 19, 2023
6793f2f
Refactor config and add HTTP headers
joaopgrassi Aug 16, 2023
ab935a7
Modify tests
joaopgrassi Aug 22, 2023
03edac8
Fix lint errors
joaopgrassi Aug 23, 2023
c3e8b81
Revert oneof in proto config
joaopgrassi Sep 4, 2023
f507a0f
PR suggestions
joaopgrassi Sep 6, 2023
6815fb5
Add HttpService config type
joaopgrassi Sep 13, 2023
ec2a0d5
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Sep 13, 2023
8d1d23a
Fix format issues
joaopgrassi Sep 13, 2023
f883976
Fix lint/format/docs issues
joaopgrassi Sep 14, 2023
0b5b8bf
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Sep 14, 2023
2da074d
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Sep 18, 2023
1389804
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Sep 21, 2023
2b6b267
Hostname -> Authority
joaopgrassi Sep 21, 2023
3be83f8
Use HttpUri type
joaopgrassi Sep 27, 2023
38adbf1
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Sep 27, 2023
2a5d544
PR suggestions
joaopgrassi Oct 2, 2023
935ad0c
Improve log messages
joaopgrassi Oct 2, 2023
9ec6806
Fix format
joaopgrassi Oct 2, 2023
9b5e47a
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 2, 2023
c0f39d7
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 4, 2023
f852967
PR suggestions
joaopgrassi Oct 4, 2023
7ea4d0b
PR suggestions
joaopgrassi Oct 4, 2023
ba5d943
Revert stats for http exporter
joaopgrassi Oct 4, 2023
38bd4ac
Fix spelling
joaopgrassi Oct 4, 2023
3d07358
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 6, 2023
ec3911b
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 10, 2023
8c7ca70
Add changelog
joaopgrassi Oct 10, 2023
efcd78a
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 12, 2023
e339153
Properly manage in-flight http requests in the exporter
joaopgrassi Oct 13, 2023
e7932fb
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 13, 2023
aacb3f4
Add proto migrate oneof annotation
joaopgrassi Oct 16, 2023
c8f74c3
Clarify http headers do not support formatting
joaopgrassi Oct 17, 2023
e00f32b
Merge remote-tracking branch 'upstream/main' into otlp-http-exporter-…
joaopgrassi Oct 17, 2023
cb08695
Prepare headers when creating the HTTP exporter
joaopgrassi Oct 17, 2023
97f6870
Revert test change
joaopgrassi Oct 18, 2023
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
43 changes: 39 additions & 4 deletions api/envoy/config/trace/v3/opentelemetry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ syntax = "proto3";

package envoy.config.trace.v3;

import "envoy/config/core/v3/base.proto";
import "envoy/config/core/v3/grpc_service.proto";

import "google/protobuf/duration.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.config.trace.v3";
option java_outer_classname = "OpentelemetryProto";
Expand All @@ -17,10 +21,41 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Configuration for the OpenTelemetry tracer.
// [#extension: envoy.tracers.opentelemetry]
message OpenTelemetryConfig {
// The upstream gRPC cluster that will receive OTLP traces.
// Note that the tracer drops traces if the server does not read data fast enough.
// This field can be left empty to disable reporting traces to the collector.
core.v3.GrpcService grpc_service = 1;
// Configuration for sending traces to the collector over HTTP. Note that
// this will only be used if the grpc_service is not set above.
message HttpConfig {

// The upstream cluster that will receive OTLP traces over HTTP.
string cluster_name = 1;

// The path to the trace ingest endpoint. The path is appended with the host name configured in the cluster.
// Optional: If omitted, "/v1/traces" will be used as default.
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
string traces_path = 2;

// Sets the maximum duration in milliseconds that a response can take to arrive upon request.
google.protobuf.Duration timeout = 3 [(validate.rules).duration = {
required: true
gte {}
}];

// Custom header values to be added to the OTLP HTTP request.
repeated config.core.v3.HeaderValue headers = 4;
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

// The hostname to include in the Host header of the OTLP HTTP request.
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
string hostname = 5;
}

oneof export_protocol {
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
option (validate.required) = true;

// The upstream gRPC cluster that will receive OTLP traces.
// Note that the tracer drops traces if the server does not read data fast enough.
// This field can be left empty to disable reporting traces to the collector.
core.v3.GrpcService grpc_service = 1;

// The configuration to export OTLP traces via HTTP.
HttpConfig http_config = 3;
}

// The name for the service. This will be populated in the ResourceSpan Resource attributes.
// If it is not provided, it will default to "unknown_service:envoy".
Expand Down
24 changes: 20 additions & 4 deletions source/extensions/tracers/opentelemetry/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ envoy_cc_library(
"span_context.h",
"span_context_extractor.h",
"tracer.h",
"tracer_stats.h",
],
deps = [
":grpc_trace_exporter",
":trace_exporter",
"//envoy/thread_local:thread_local_interface",
"//source/common/config:utility_lib",
"//source/common/tracing:http_tracer_lib",
Expand All @@ -47,13 +48,28 @@ envoy_cc_library(
)

envoy_cc_library(
name = "grpc_trace_exporter",
srcs = ["grpc_trace_exporter.cc"],
hdrs = ["grpc_trace_exporter.h"],
name = "trace_exporter",
srcs = [
"grpc_trace_exporter.cc",
"http_trace_exporter.cc",
],
hdrs = [
"grpc_trace_exporter.h",
"http_trace_exporter.h",
"trace_exporter.h",
"tracer_stats.h",
],
deps = [
"//envoy/grpc:async_client_manager_interface",
"//envoy/upstream:cluster_manager_interface",
"//source/common/grpc:typed_async_client_lib",
"//source/common/http:async_client_utility_lib",
"//source/common/http:header_map_lib",
"//source/common/http:message_lib",
"//source/common/http:utility_lib",
"//source/common/protobuf",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
"@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 @@ -6,6 +6,7 @@
#include "source/common/grpc/typed_async_client.h"

#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "trace_exporter.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

namespace Envoy {
namespace Extensions {
Expand Down Expand Up @@ -80,18 +81,16 @@ class OpenTelemetryGrpcTraceExporterClient : Logger::Loggable<Logger::Id::tracin
const Protobuf::MethodDescriptor& service_method_;
};

class OpenTelemetryGrpcTraceExporter : Logger::Loggable<Logger::Id::tracing> {
class OpenTelemetryGrpcTraceExporter : public OpenTelemetryTraceExporter {
public:
OpenTelemetryGrpcTraceExporter(const Grpc::RawAsyncClientSharedPtr& client);

bool log(const ExportTraceServiceRequest& request);
bool log(const ExportTraceServiceRequest& request) override;

private:
OpenTelemetryGrpcTraceExporterClient client_;
};

using OpenTelemetryGrpcTraceExporterPtr = std::unique_ptr<OpenTelemetryGrpcTraceExporter>;

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
Expand Down
86 changes: 86 additions & 0 deletions source/extensions/tracers/opentelemetry/http_trace_exporter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "http_trace_exporter.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

#include <chrono>
#include <memory>
#include <string>

#include "source/common/common/logger.h"
#include "source/common/protobuf/protobuf.h"

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

OpenTelemetryHttpTraceExporter::OpenTelemetryHttpTraceExporter(
Upstream::ClusterManager& cluster_manager,
envoy::config::trace::v3::OpenTelemetryConfig::HttpConfig http_config,
OpenTelemetryTracerStats& tracing_stats)
: cluster_manager_(cluster_manager), http_config_(http_config), tracing_stats_(tracing_stats) {}

bool OpenTelemetryHttpTraceExporter::log(const ExportTraceServiceRequest& request) {

Comment thread
joaopgrassi marked this conversation as resolved.
std::string request_body;

const auto ok = request.SerializeToString(&request_body);
if (!ok) {
Comment thread
joaopgrassi marked this conversation as resolved.
ENVOY_LOG(warn, "Error while serializing the binary proto ExportTraceServiceRequest.");
return false;
}

Http::RequestMessagePtr message = std::make_unique<Http::RequestMessageImpl>();
message->headers().setReferenceMethod(Http::Headers::get().MethodValues.Post);
Comment thread
joaopgrassi marked this conversation as resolved.
message->headers().setReferenceContentType(Http::Headers::get().ContentTypeValues.Protobuf);

// If traces_path is omitted, send to /v1/traces by default
if (http_config_.traces_path().empty()) {
message->headers().setPath(TRACES_PATH);
} else {
message->headers().setPath(http_config_.traces_path());
}
Comment thread
joaopgrassi marked this conversation as resolved.

// TODO: Can we get the hostname that is configured in the cluster "socker_address" field?
message->headers().setHost(http_config_.hostname());
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

// add all custom headers to the request
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
for (const envoy::config::core::v3::HeaderValue& header : http_config_.headers()) {
message->headers().setCopy(Http::LowerCaseString(header.key()), header.value());
}

message->body().add(request_body);

const auto thread_local_cluster =
cluster_manager_.getThreadLocalCluster(http_config_.cluster_name());
if (thread_local_cluster == nullptr) {
ENVOY_LOG(warn, "Thread local cluster not found for collector.");
return false;
}

std::chrono::milliseconds timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::nanoseconds(http_config_.timeout().nanos()));
Http::AsyncClient::Request* http_request = thread_local_cluster->httpAsyncClient().send(
std::move(message), *this, Http::AsyncClient::RequestOptions().setTimeout(timeout));
tracing_stats_.http_reports_sent_.inc();

return http_request;
Comment thread
wbpcode marked this conversation as resolved.
Outdated
}

void OpenTelemetryHttpTraceExporter::onSuccess(const Http::AsyncClient::Request&,
Http::ResponseMessagePtr&& message) {
tracing_stats_.http_reports_success_.inc();
const auto response_code = message->headers().Status()->value().getStringView();
if (response_code != "200") {
ENVOY_LOG(warn, "response code: {}", response_code);
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
}
}

void OpenTelemetryHttpTraceExporter::onFailure(const Http::AsyncClient::Request&,
Http::AsyncClient::FailureReason) {
ENVOY_LOG(debug, "Request failed.");
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
tracing_stats_.http_reports_failed_.inc();
}

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
54 changes: 54 additions & 0 deletions source/extensions/tracers/opentelemetry/http_trace_exporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

#pragma once

#include "envoy/config/core/v3/http_uri.pb.h"
#include "envoy/config/trace/v3/opentelemetry.pb.h"
#include "envoy/upstream/cluster_manager.h"

#include "source/common/common/logger.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 "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "trace_exporter.h"
#include "tracer_stats.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

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

/**
* Exporter for OTLP traces over HTTP.
*/
class OpenTelemetryHttpTraceExporter : public OpenTelemetryTraceExporter,
public Http::AsyncClient::Callbacks {
public:
OpenTelemetryHttpTraceExporter(
Upstream::ClusterManager& cluster_manager,
envoy::config::trace::v3::OpenTelemetryConfig::HttpConfig http_config,
OpenTelemetryTracerStats& tracing_stats);

// The default path to use when OpenTelemetryConfig::HttpConfig::traces_path is empty
const Http::LowerCaseString TRACES_PATH{"/v1/traces"};
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

bool log(const ExportTraceServiceRequest& request) override;

// Http::AsyncClient::Callbacks.
void onSuccess(const Http::AsyncClient::Request&, Http::ResponseMessagePtr&&) override;
void onFailure(const Http::AsyncClient::Request&, Http::AsyncClient::FailureReason) override;
void onBeforeFinalizeUpstreamSpan(Tracing::Span&, const Http::ResponseHeaderMap*) override {}

private:
Upstream::ClusterManager& cluster_manager_;
envoy::config::trace::v3::OpenTelemetryConfig::HttpConfig http_config_;
OpenTelemetryTracerStats& tracing_stats_;
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
};

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#include "source/common/config/utility.h"
#include "source/common/tracing/http_tracer_impl.h"

#include "grpc_trace_exporter.h"
#include "http_trace_exporter.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated
#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "opentelemetry/proto/trace/v1/trace.pb.h"
#include "span_context.h"
#include "span_context_extractor.h"
#include "trace_exporter.h"
#include "tracer.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

namespace Envoy {
Expand All @@ -28,14 +31,24 @@ Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetr
auto& factory_context = context.serverFactoryContext();
// Create the tracer in Thread Local Storage.
tls_slot_ptr_->set([opentelemetry_config, &factory_context, this](Event::Dispatcher& dispatcher) {
OpenTelemetryGrpcTraceExporterPtr exporter;
if (opentelemetry_config.has_grpc_service()) {
OpenTelemetryTraceExporterPtr exporter;
switch (opentelemetry_config.export_protocol_case()) {
case envoy::config::trace::v3::OpenTelemetryConfig::ExportProtocolCase::kGrpcService: {
Grpc::AsyncClientFactoryPtr&& factory =
factory_context.clusterManager().grpcAsyncClientManager().factoryForGrpcService(
opentelemetry_config.grpc_service(), factory_context.scope(), true);
const Grpc::RawAsyncClientSharedPtr& async_client_shared_ptr =
factory->createUncachedRawAsyncClient();
exporter = std::make_unique<OpenTelemetryGrpcTraceExporter>(async_client_shared_ptr);
break;
}
case envoy::config::trace::v3::OpenTelemetryConfig::ExportProtocolCase::kHttpConfig: {
exporter = std::make_unique<OpenTelemetryHttpTraceExporter>(
factory_context.clusterManager(), opentelemetry_config.http_config(), tracing_stats_);
break;
}
default:
break;
}
TracerPtr tracer = std::make_unique<Tracer>(
std::move(exporter), factory_context.timeSource(), factory_context.api().randomGenerator(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include "source/common/common/logger.h"
#include "source/common/singleton/const_singleton.h"
#include "source/extensions/tracers/common/factory_base.h"
#include "source/extensions/tracers/opentelemetry/grpc_trace_exporter.h"
#include "source/extensions/tracers/opentelemetry/tracer.h"

#include "tracer.h"
Comment thread
joaopgrassi marked this conversation as resolved.
Outdated

namespace Envoy {
namespace Extensions {
Expand Down
26 changes: 26 additions & 0 deletions source/extensions/tracers/opentelemetry/trace_exporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "source/common/common/logger.h"

#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"

using opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest;

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

class OpenTelemetryTraceExporter : public Logger::Loggable<Logger::Id::tracing> {
Comment thread
joaopgrassi marked this conversation as resolved.
public:
virtual ~OpenTelemetryTraceExporter() = default;

virtual bool log(const ExportTraceServiceRequest& request) = 0;
Comment thread
joaopgrassi marked this conversation as resolved.
};

using OpenTelemetryTraceExporterPtr = std::unique_ptr<OpenTelemetryTraceExporter>;

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
2 changes: 1 addition & 1 deletion source/extensions/tracers/opentelemetry/tracer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void Span::setTag(absl::string_view name, absl::string_view value) {
*span_.add_attributes() = key_value;
}

Tracer::Tracer(OpenTelemetryGrpcTraceExporterPtr exporter, Envoy::TimeSource& time_source,
Tracer::Tracer(OpenTelemetryTraceExporterPtr exporter, Envoy::TimeSource& time_source,
Random::RandomGenerator& random, Runtime::Loader& runtime,
Event::Dispatcher& dispatcher, OpenTelemetryTracerStats tracing_stats,
const std::string& service_name)
Expand Down
Loading