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 2 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
17 changes: 17 additions & 0 deletions api/envoy/config/trace/v3/opentelemetry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ package envoy.config.trace.v3;

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

import "google/protobuf/any.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 @@ -14,6 +17,16 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: OpenTelemetry tracer]

message ResourceDetector {
// The name of the resource detector to instantiate.
string name = 1 [(validate.rules).string = {min_len: 1}];

// Resource detector specific configuration which depends on the detector being
// instantiated. See the supported detectors for further documentation.
// Not required for detectors that don't need a config. E.g., Environment variable Detector
google.protobuf.Any typed_config = 2;
}

// Configuration for the OpenTelemetry tracer.
// [#extension: envoy.tracers.opentelemetry]
message OpenTelemetryConfig {
Expand All @@ -25,4 +38,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 ResourceDetector resource_detectors = 3;
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
}
6 changes: 6 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,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
5 changes: 5 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1641,3 +1641,8 @@ envoy.config_mux.sotw_grpc_mux_factory:
- envoy.config_mux
security_posture: unknown
status: stable
envoy.tracers.opentelemetry.resource_detectors.environment:
categories:
- envoy.tracers.opentelemetry.resource_detectors
security_posture: unknown
status: wip
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
5 changes: 4 additions & 1 deletion source/extensions/tracers/opentelemetry/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "source/common/common/logger.h"
#include "source/extensions/tracers/opentelemetry/opentelemetry_tracer_impl.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_provider.h"

namespace Envoy {
namespace Extensions {
Expand All @@ -18,7 +19,9 @@ OpenTelemetryTracerFactory::OpenTelemetryTracerFactory()
Tracing::DriverSharedPtr OpenTelemetryTracerFactory::createTracerDriverTyped(
const envoy::config::trace::v3::OpenTelemetryConfig& proto_config,
Server::Configuration::TracerFactoryContext& context) {
return std::make_shared<Driver>(proto_config, context);

joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
ResourceProviderImpl resource_provider;
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
return std::make_shared<Driver>(proto_config, context, resource_provider);
}

/**
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/config/utility.h"
#include "source/common/tracing/http_tracer_impl.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_detector.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_provider.h"

#include "opentelemetry/proto/collector/trace/v1/trace_service.pb.h"
#include "opentelemetry/proto/trace/v1/trace.pb.h"
Expand All @@ -21,13 +23,17 @@ namespace Tracers {
namespace OpenTelemetry {

Driver::Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context)
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);

// 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](Event::Dispatcher& dispatcher) {
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
OpenTelemetryGrpcTraceExporterPtr exporter;
if (opentelemetry_config.has_grpc_service()) {
Grpc::AsyncClientFactoryPtr&& factory =
Expand All @@ -39,7 +45,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);

return std::make_shared<TlsTracer>(std::move(tracer));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#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 @@ -30,7 +31,8 @@ using OpenTelemetryConstants = ConstSingleton<OpenTelemetryConstantValues>;
class Driver : Logger::Loggable<Logger::Id::tracing>, public Tracing::Driver {
public:
Driver(const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config,
Server::Configuration::TracerFactoryContext& context);
Server::Configuration::TracerFactoryContext& context,
const ResourceProvider& resource_provider);

// Tracing::Driver
Tracing::SpanPtr startSpan(const Tracing::Config& config, Tracing::TraceContext& trace_context,
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,31 @@
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 = [
":resource_detector_environment_lib",
"//envoy/registry",
"//source/common/config:utility_lib",
],
)

envoy_cc_library(
name = "resource_detector_environment_lib",
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
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",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "config.h"

#include "source/common/config/utility.h"

#include "environment_resource_detector.h"

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

ResourceDetectorPtr EnvironmentResourceDetectorFactory::createResourceDetector(
Server::Configuration::TracerFactoryContext& context) {
return std::make_shared<EnvironmentResourceDetector>(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,37 @@
#pragma once

#include <string>

#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 context
* @return ResourceDetectorPtr
*/
ResourceDetectorPtr
createResourceDetector(Server::Configuration::TracerFactoryContext& context) override;

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,56 @@
#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 = "";

TRY_NEEDS_AUDIT {
auto attributes_str = Config::DataSource::read(ds, true, context_.serverFactoryContext().api());
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
if (attributes_str.empty()) {
return resource;
}

std::istringstream iss(attributes_str);
std::string token;
while (std::getline(iss, token, ',')) {
size_t pos = token.find('=');
std::string key = token.substr(0, pos);
std::string value = token.substr(pos + 1);
resource.attributes[key] = value;
}
}
END_TRY catch (const EnvoyException& e) {
ENVOY_LOG(error, "Failed to read resource attributes: {}.", e.what());
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
}

return resource;
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
}

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

#include "envoy/server/factory_context.h"

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

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

/**
* @brief A resource detector that extracts attributes from the OTEL_RESOURCE_ATTRIBUTES environment
* variable.
* @see
* https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/resource/sdk.md#detecting-resource-information-from-the-environment
*
*/
class EnvironmentResourceDetector : public ResourceDetector, Logger::Loggable<Logger::Id::tracing> {
public:
EnvironmentResourceDetector(Server::Configuration::TracerFactoryContext& context)
: context_(context) {}
Resource detect() override;

private:
Server::Configuration::TracerFactoryContext&
context_; // TODO, is keeping a reference ok (ownership)?
joaopgrassi marked this conversation as resolved.
Show resolved Hide resolved
};

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