Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opentelemetry tracer: add support for environment resource detector #29547

Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
808577f
Add resource detector extension
joaopgrassi Aug 29, 2023
8c2fdc4
Use detectors to build the OTel resource
joaopgrassi Aug 29, 2023
197942d
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Sep 12, 2023
277d9ce
Refactor to use core.v3.TypedExtensionConfig
joaopgrassi Sep 12, 2023
995c4b6
Refactor to use core.v3.TypedExtensionConfig - fix unit tests
joaopgrassi Sep 12, 2023
687a0f7
Manually add res detectors proto package to build file
joaopgrassi Sep 13, 2023
40c4373
PR suggestions
joaopgrassi Sep 13, 2023
e3b92cb
Reduce scope of try-catch to minimum
joaopgrassi Sep 14, 2023
0febb7c
Avoid copying the resource to all threads/tracers
joaopgrassi Sep 14, 2023
a340411
Fix format issues
joaopgrassi Sep 14, 2023
ae8b16a
Fix spelling mistakes and add OTEL to dictionary
joaopgrassi Sep 14, 2023
a8bf06b
Fix proto lint issues
joaopgrassi Sep 14, 2023
62365cf
Refactor passing resource provider to Driver
joaopgrassi Sep 14, 2023
0183959
Add docs
joaopgrassi Sep 14, 2023
3144798
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Sep 14, 2023
7a8ae5a
Fix doc lint
joaopgrassi Sep 14, 2023
e2de7aa
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Sep 18, 2023
23e7b2b
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Sep 28, 2023
c71695b
Fix imports
joaopgrassi Sep 28, 2023
ca96947
Fix pointers
joaopgrassi Sep 28, 2023
96d2bc6
adapt env var parsing
joaopgrassi Sep 29, 2023
1690cdd
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 2, 2023
512e692
Set schema url regardless of resource being empty or not
joaopgrassi Oct 2, 2023
d79e015
PR suggestions
joaopgrassi Oct 4, 2023
04e0480
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 4, 2023
bed0ab8
Add comments to tests
joaopgrassi Oct 4, 2023
a5923fc
Fix lint issues
joaopgrassi Oct 4, 2023
e1c31c9
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 16, 2023
5dbb2ea
Add changelog
joaopgrassi Oct 16, 2023
b6171be
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 18, 2023
d20885e
Prevent start up when failing to detect resource from the environment
joaopgrassi Oct 18, 2023
8c79eaa
Remove left over todo
joaopgrassi Oct 18, 2023
4dfa9d5
Fix proto docs
joaopgrassi Oct 18, 2023
8835647
Improve test env var cleanup
joaopgrassi Oct 19, 2023
7cdfe98
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 19, 2023
c7b38b5
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 23, 2023
a374106
Add docs to resource struct
joaopgrassi Oct 24, 2023
4d2fa4a
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 24, 2023
6efb398
Fix spelling
joaopgrassi Oct 24, 2023
0020e55
Merge branch 'main' into feat/otel-resource-detectors-env
joaopgrassi Oct 25, 2023
e678e48
Use cleanup class to clean up env variables after each test
joaopgrassi Oct 25, 2023
dcb52f8
Handle empty env var on windows
joaopgrassi Oct 25, 2023
f278a46
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 27, 2023
f43274e
Merge remote-tracking branch 'upstream/main' into feat/otel-resource-…
joaopgrassi Oct 27, 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
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``
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
// environment variable, as per the OpenTelemetry specification.
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
//
// 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
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ removed_config_or_runtime:
runtime flag and legacy code path.

new_features:
- 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
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(
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
"//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(
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "environment_resource_detector.h"

#include <sstream>
#include <string>

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

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

constexpr absl::string_view kOtelResourceAttributesEnv = "OTEL_RESOURCE_ATTRIBUTES";

/**
* @brief Detects a resource from the OTEL_RESOURCE_ATTRIBUTES environment variable
* Based on the OTel C++ SDK:
* https://github.com/open-telemetry/opentelemetry-cpp/blob/v1.11.0/sdk/src/resource/resource_detector.cc
*
* @return Resource A resource with the attributes from the OTEL_RESOURCE_ATTRIBUTES environment
* variable.
*/
Resource EnvironmentResourceDetector::detect() {
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
envoy::config::core::v3::DataSource ds;
ds.set_environment_variable(kOtelResourceAttributesEnv);

Resource resource;
resource.schemaUrl_ = "";
std::string attributes_str = "";

attributes_str = Config::DataSource::read(ds, true, context_.serverFactoryContext().api());

if (attributes_str.empty()) {
throw EnvoyException(
fmt::format("The OpenTelemetry environment resource detector is configured but the '{}'"
" environment variable is empty.",
kOtelResourceAttributesEnv));
}

for (const auto& pair : StringUtil::splitToken(attributes_str, ",")) {
const auto keyValue = StringUtil::splitToken(pair, "=");
if (keyValue.size() != 2) {
throw EnvoyException(
fmt::format("The OpenTelemetry environment resource detector is configured but the '{}'"
" environment variable has an invalid format.",
kOtelResourceAttributesEnv));
}

const std::string key = std::string(keyValue[0]);
const std::string value = std::string(keyValue[1]);
resource.attributes_[key] = value;
}
return resource;
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
}

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