Skip to content

Commit

Permalink
opentelemetry tracer: add support for environment resource detector (#…
Browse files Browse the repository at this point in the history
…29547)

Commit Message: Allow specifying resource detectors for the OpenTelemetry tracer via a new configuration resource_detectors. The resource detector reads from the env variable OTEL_RESOURCE_ATTRIBUTES which is defined by the OTel specification. The detector returns a resource object populated with the detected attributes, which is sent as part of the OTLP request.

Additional Description: This PR adds the "foundation" for building other resource detectors in Envoy. It is based on the OTel collector implementation. Users can configure multiple resource detectors, and they work together to "merge" all the detected attributes into a single resource object, which is then part of the OTLP message exported.

Risk Level: Low

Testing: Multiple unit tests, that cover all new code/scenarios. I also did manual testing, running Envoy locally with the OTel tracer + env resource detector enabled. Resource attributes detected from my environment is successfully exported as seen in the Jaeger screenshot.
resource-detectors-env-jaeger

Docs Changes: Not sure if I should add/where. Happy to do it.
Release Notes: N/A
Platform Specific Features: N/A
[Optional Runtime guard:] N/A
[Optional Fixes #28929]

Here is how the new config is used:

tracing:
  provider:
    name: envoy.tracers.opentelemetry
    typed_config:
      "@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig
       grpc_service:
         envoy_grpc:
           cluster_name: opentelemetry_collector
         timeout: 0.250s
       service_name: envoy-gRPC-exporter
       resource_detectors: # --> NEW CONFIG
         - name: envoy.tracers.opentelemetry.resource_detectors.environment
           typed_config:
             "@type": type.googleapis.com/envoy.extensions.tracers.opentelemetry.resource_detectors.v3.EnvironmentResourceDetectorConfig


Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com>
  • Loading branch information
joaopgrassi authored Oct 27, 2023
1 parent a3d7440 commit 4eaa1f8
Show file tree
Hide file tree
Showing 32 changed files with 1,233 additions and 21 deletions.
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
"//envoy/extensions/transport_sockets/internal_upstream/v3:pkg",
Expand Down
5 changes: 5 additions & 0 deletions api/envoy/config/trace/v3/opentelemetry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";

package envoy.config.trace.v3;

import "envoy/config/core/v3/extension.proto";
import "envoy/config/core/v3/grpc_service.proto";
import "envoy/config/core/v3/http_service.proto";

Expand Down Expand Up @@ -43,4 +44,8 @@ message OpenTelemetryConfig {
// 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".
string service_name = 2;

// An ordered list of resource detectors
// [#extension-category: envoy.tracers.opentelemetry.resource_detectors]
repeated core.v3.TypedExtensionConfig resource_detectors = 4;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
syntax = "proto3";

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

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.resource_detectors.v3";
option java_outer_classname = "EnvironmentResourceDetectorProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/resource_detectors/v3;resource_detectorsv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Environment Resource Detector config]

// Configuration for the Environment Resource detector extension.
// The resource detector reads from the ``OTEL_RESOURCE_ATTRIBUTES``
// environment variable, as per the OpenTelemetry specification.
//
// See:
//
// `OpenTelemetry specification <https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/resource/sdk.md#detecting-resource-information-from-the-environment>`_
//
// [#extension: envoy.tracers.opentelemetry.resource_detectors.environment]
message EnvironmentResourceDetectorConfig {
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
"//envoy/extensions/transport_sockets/internal_upstream/v3:pkg",
Expand Down
4 changes: 3 additions & 1 deletion changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ new_features:
change: |
added :ref:`per_endpoint_stats <envoy_v3_api_field_config.cluster.v3.TrackClusterStats.per_endpoint_stats>` to get some metrics
for each endpoint in a cluster.
- area: jwt
change: |
The jwt filter can now serialize non-primitive custom claims when maping claims to headers.
Expand All @@ -90,5 +89,8 @@ new_features:
returns an error or cannot be reached with :ref:`status_on_error
<envoy_v3_api_field_extensions.filters.http.ratelimit.v3.RateLimit.status_on_error>`
configuration flag.
- area: tracing
change: |
Added support for configuring resource detectors on the OpenTelemetry tracer.
deprecated:
10 changes: 10 additions & 0 deletions docs/root/api-v3/config/trace/opentelemetry/resource_detectors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
OpenTelemetry Resource Detectors
================================

Resource detectors that can be configured with the OpenTelemetry Tracer:

.. toctree::
:glob:
:maxdepth: 3

../../../extensions/tracers/opentelemetry/resource_detectors/v3/*
1 change: 1 addition & 0 deletions docs/root/api-v3/config/trace/trace.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ HTTP tracers
:maxdepth: 2

v3/*
opentelemetry/resource_detectors
6 changes: 6 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ EXTENSIONS = {
"envoy.tracers.skywalking": "//source/extensions/tracers/skywalking:config",
"envoy.tracers.opentelemetry": "//source/extensions/tracers/opentelemetry:config",

#
# OpenTelemetry Resource Detectors
#

"envoy.tracers.opentelemetry.resource_detectors.environment": "//source/extensions/tracers/opentelemetry/resource_detectors/environment:config",

#
# Transport sockets
#
Expand Down
7 changes: 7 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1676,3 +1676,10 @@ envoy.filters.network.set_filter_state:
status: alpha
type_urls:
- envoy.extensions.filters.network.set_filter_state.v3.Config
envoy.tracers.opentelemetry.resource_detectors.environment:
categories:
- envoy.tracers.opentelemetry.resource_detectors
security_posture: unknown
status: wip
type_urls:
- envoy.extensions.tracers.opentelemetry.resource_detectors.v3.EnvironmentResourceDetectorConfig
1 change: 1 addition & 0 deletions source/extensions/tracers/opentelemetry/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ envoy_cc_library(
"//source/common/config:utility_lib",
"//source/common/tracing:http_tracer_lib",
"//source/extensions/tracers/common:factory_base_lib",
"//source/extensions/tracers/opentelemetry/resource_detectors:resource_detector_lib",
"@envoy_api//envoy/config/trace/v3:pkg_cc_proto",
"@opentelemetry_proto//:trace_cc_proto",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "source/common/tracing/http_tracer_impl.h"
#include "source/extensions/tracers/opentelemetry/grpc_trace_exporter.h"
#include "source/extensions/tracers/opentelemetry/http_trace_exporter.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_detector.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_provider.h"
#include "source/extensions/tracers/opentelemetry/span_context.h"
#include "source/extensions/tracers/opentelemetry/span_context_extractor.h"
#include "source/extensions/tracers/opentelemetry/trace_exporter.h"
Expand All @@ -25,19 +27,28 @@ namespace OpenTelemetry {

Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context)
: Driver(opentelemetry_config, context, ResourceProviderImpl{}) {}

Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context,
const ResourceProvider& resource_provider)
: tls_slot_ptr_(context.serverFactoryContext().threadLocal().allocateSlot()),
tracing_stats_{OPENTELEMETRY_TRACER_STATS(
POOL_COUNTER_PREFIX(context.serverFactoryContext().scope(), "tracing.opentelemetry"))} {
auto& factory_context = context.serverFactoryContext();

Resource resource = resource_provider.getResource(opentelemetry_config, context);
ResourceConstSharedPtr resource_ptr = std::make_shared<Resource>(std::move(resource));

if (opentelemetry_config.has_grpc_service() && opentelemetry_config.has_http_service()) {
throw EnvoyException(
"OpenTelemetry Tracer cannot have both gRPC and HTTP exporters configured. "
"OpenTelemetry tracer will be disabled.");
}

// Create the tracer in Thread Local Storage.
tls_slot_ptr_->set([opentelemetry_config, &factory_context, this](Event::Dispatcher& dispatcher) {
tls_slot_ptr_->set([opentelemetry_config, &factory_context, this,
resource_ptr](Event::Dispatcher& dispatcher) {
OpenTelemetryTraceExporterPtr exporter;
if (opentelemetry_config.has_grpc_service()) {
Grpc::AsyncClientFactoryPtr&& factory =
Expand All @@ -52,7 +63,7 @@ Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetr
}
TracerPtr tracer = std::make_unique<Tracer>(
std::move(exporter), factory_context.timeSource(), factory_context.api().randomGenerator(),
factory_context.runtime(), dispatcher, tracing_stats_, opentelemetry_config.service_name());
factory_context.runtime(), dispatcher, tracing_stats_, resource_ptr);

return std::make_shared<TlsTracer>(std::move(tracer));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +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/resource_detectors/resource_provider.h"
#include "source/extensions/tracers/opentelemetry/tracer.h"

namespace Envoy {
Expand All @@ -31,6 +33,10 @@ class Driver : Logger::Loggable<Logger::Id::tracing>, public Tracing::Driver {
Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context);

Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context,
const ResourceProvider& resource_provider);

// Tracing::Driver
Tracing::SpanPtr startSpan(const Tracing::Config& config, Tracing::TraceContext& trace_context,
const StreamInfo::StreamInfo& stream_info,
Expand Down
27 changes: 27 additions & 0 deletions source/extensions/tracers/opentelemetry/resource_detectors/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_library(
name = "resource_detector_lib",
srcs = [
"resource_provider.cc",
],
hdrs = [
"resource_detector.h",
"resource_provider.h",
],
deps = [
"//envoy/config:typed_config_interface",
"//envoy/server:tracer_config_interface",
"//source/common/common:logger_lib",
"//source/common/config:utility_lib",
"@envoy_api//envoy/config/trace/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_cc_library",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
deps = [
":environment_resource_detector_lib",
"//envoy/registry",
"//source/common/config:utility_lib",
"@envoy_api//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg_cc_proto",
],
)

envoy_cc_library(
name = "environment_resource_detector_lib",
srcs = ["environment_resource_detector.cc"],
hdrs = ["environment_resource_detector.h"],
deps = [
"//source/common/config:datasource_lib",
"//source/extensions/tracers/opentelemetry/resource_detectors:resource_detector_lib",
"@envoy_api//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "source/extensions/tracers/opentelemetry/resource_detectors/environment/config.h"

#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/environment_resource_detector.pb.h"
#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/environment_resource_detector.pb.validate.h"

#include "source/common/config/utility.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/environment/environment_resource_detector.h"

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

ResourceDetectorPtr EnvironmentResourceDetectorFactory::createResourceDetector(
const Protobuf::Message& message, Server::Configuration::TracerFactoryContext& context) {

auto mptr = Envoy::Config::Utility::translateAnyToFactoryConfig(
dynamic_cast<const ProtobufWkt::Any&>(message), context.messageValidationVisitor(), *this);

const auto& proto_config = MessageUtil::downcastAndValidate<
const envoy::extensions::tracers::opentelemetry::resource_detectors::v3::
EnvironmentResourceDetectorConfig&>(*mptr, context.messageValidationVisitor());

return std::make_unique<EnvironmentResourceDetector>(proto_config, context);
}

/**
* Static registration for the Env resource detector factory. @see RegisterFactory.
*/
REGISTER_FACTORY(EnvironmentResourceDetectorFactory, ResourceDetectorFactory);

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

#include <string>

#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/environment_resource_detector.pb.h"

#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_detector.h"

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

/**
* Config registration for the Environment resource detector. @see ResourceDetectorFactory.
*/
class EnvironmentResourceDetectorFactory : public ResourceDetectorFactory {
public:
/**
* @brief Create a Resource Detector that reads from the OTEL_RESOURCE_ATTRIBUTES
* environment variable.
*
* @param message The resource detector configuration.
* @param context The tracer factory context.
* @return ResourceDetectorPtr
*/
ResourceDetectorPtr
createResourceDetector(const Protobuf::Message& message,
Server::Configuration::TracerFactoryContext& context) override;

ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return std::make_unique<envoy::extensions::tracers::opentelemetry::resource_detectors::v3::
EnvironmentResourceDetectorConfig>();
}

std::string name() const override {
return "envoy.tracers.opentelemetry.resource_detectors.environment";
}
};

DECLARE_FACTORY(EnvironmentResourceDetectorFactory);

} // namespace OpenTelemetry
} // namespace Tracers
} // namespace Extensions
} // namespace Envoy
Loading

0 comments on commit 4eaa1f8

Please sign in to comment.