Skip to content

Commit

Permalink
opentelemetry tracer: add Dynatrace resource detector (envoyproxy#30824)
Browse files Browse the repository at this point in the history
* Add Dynatrace resource detector

Co-authored-by: Thomas Ebner <[email protected]>
Signed-off-by: Joao Grassi <[email protected]>

* PR suggestions

Signed-off-by: Joao Grassi <[email protected]>

* Add tests for Dynatrace file reader

Signed-off-by: Joao Grassi <[email protected]>

* PR suggestions

Signed-off-by: Joao Grassi <[email protected]>

* schemaUrl_ -> schema_url_

Signed-off-by: Joao Grassi <[email protected]>

* PR suggestions and changelog

Signed-off-by: Joao Grassi <[email protected]>

---------

Signed-off-by: Joao Grassi <[email protected]>
Co-authored-by: Thomas Ebner <[email protected]>
  • Loading branch information
joaopgrassi and samohte authored Nov 23, 2023
1 parent 61b5fcb commit be410d6
Show file tree
Hide file tree
Showing 23 changed files with 742 additions and 19 deletions.
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 = "DynatraceResourceDetectorProto";
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: Dynatrace Resource Detector config]

// Configuration for the Dynatrace Resource Detector extension.
// The resource detector reads from the Dynatrace enrichment files
// and adds host/process related attributes to the OpenTelemetry resource.
//
// See:
//
// `Enrich ingested data with Dynatrace-specific dimensions <https://docs.dynatrace.com/docs/shortlink/enrichment-files>`_
//
// [#extension: envoy.tracers.opentelemetry.resource_detectors.dynatrace]
message DynatraceResourceDetectorConfig {
}
3 changes: 3 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,5 +210,8 @@ new_features:
and
:ref:`response_attributes <envoy_v3_api_field_extensions.filters.http.ext_proc.v3.ExternalProcessor.response_attributes>`
config APIs to enable sending and receiving attributes from/to the external processing server.
- area: tracing
change: |
Added support to configure a Dynatrace resource detector for the OpenTelemetry tracer.
deprecated:
1 change: 1 addition & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ EXTENSIONS = {
#

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

#
# OpenTelemetry tracer samplers
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 @@ -1697,3 +1697,10 @@ envoy.tracers.opentelemetry.resource_detectors.environment:
status: wip
type_urls:
- envoy.extensions.tracers.opentelemetry.resource_detectors.v3.EnvironmentResourceDetectorConfig
envoy.tracers.opentelemetry.resource_detectors.dynatrace:
categories:
- envoy.tracers.opentelemetry.resource_detectors
security_posture: unknown
status: wip
type_urls:
- envoy.extensions.tracers.opentelemetry.resource_detectors.v3.DynatraceResourceDetectorConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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 = [
":dynatrace_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 = "dynatrace_resource_detector_lib",
srcs = [
"dynatrace_metadata_file_reader.cc",
"dynatrace_resource_detector.cc",
],
hdrs = [
"dynatrace_metadata_file_reader.h",
"dynatrace_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,37 @@
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/config.h"

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

#include "source/common/config/utility.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader.h"
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.h"

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

ResourceDetectorPtr DynatraceResourceDetectorFactory::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::
DynatraceResourceDetectorConfig&>(*mptr, context.messageValidationVisitor());

DynatraceMetadataFileReaderPtr reader = std::make_unique<DynatraceMetadataFileReaderImpl>();
return std::make_unique<DynatraceResourceDetector>(proto_config, std::move(reader));
}

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

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

#include <string>

#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/dynatrace_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 Dynatrace resource detector. @see ResourceDetectorFactory.
*/
class DynatraceResourceDetectorFactory : public ResourceDetectorFactory {
public:
/**
* @brief Creates a Resource Detector that reads from the Dynatrace enrichment files.
*
* @see
* https://docs.dynatrace.com/docs/shortlink/enrichment-files#oneagent-virtual-files
*
* @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::
DynatraceResourceDetectorConfig>();
}

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

DECLARE_FACTORY(DynatraceResourceDetectorFactory);

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

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

#include "envoy/common/exception.h"

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

#include "absl/strings/str_cat.h"

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

namespace {

bool isIndirectionFile(const std::string& file_name) {
return absl::StartsWith(file_name, "dt_metadata_");
}

std::string readFile(const std::string& file_name) {
if (file_name.empty()) {
return "";
}

std::ifstream file(file_name);
if (file.fail()) {
throw EnvoyException(absl::StrCat("Unable to read Dynatrace enrichment file: ", file_name));
}

std::stringstream file_string;
file_string << file.rdbuf();

return file_string.str();
}

} // namespace

std::string DynatraceMetadataFileReaderImpl::readEnrichmentFile(const std::string& file_name) {
if (const bool indirection_file = isIndirectionFile(file_name); indirection_file) {
return readFile(readFile(file_name));
} else {
return readFile(file_name);
}
}

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

#include <array>
#include <memory>
#include <string>

#include "envoy/common/pure.h"

#include "absl/strings/match.h"

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

/**
* @brief A file reader that reads the content of the Dynatrace metadata enrichment files.
* When OneAgent is monitoring your application, it provides access to the enrichment files.
* These files do not physically exists in your file system, but are provided by the OneAgent on
* demand. This allows obtaining not only information about the host, but also about process.
*
* @see
* https://docs.dynatrace.com/docs/shortlink/enrichment-files#oneagent-virtual-files
*
*/
class DynatraceMetadataFileReader {
public:
virtual ~DynatraceMetadataFileReader() = default;

/**
* @brief Reads the enrichment file and returns the enrichment metadata.
*
* @param file_name The file name.
* @return const std::string String (java-like properties) containing the enrichment metadata.
*/
virtual std::string readEnrichmentFile(const std::string& file_name) PURE;
};

using DynatraceMetadataFileReaderPtr = std::unique_ptr<DynatraceMetadataFileReader>;

class DynatraceMetadataFileReaderImpl : public DynatraceMetadataFileReader {
public:
std::string readEnrichmentFile(const std::string& file_name) override;
};

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

#include <fstream>
#include <iostream>

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

void addAttributes(const std::string& content, Resource& resource) {
for (const auto& line : StringUtil::splitToken(content, "\n", false, true)) {
const auto key_value = StringUtil::splitToken(line, "=");
if (key_value.size() != 2) {
continue;
}
resource.attributes_[std::string(key_value[0])] = std::string(key_value[1]);
}
}

} // namespace

Resource DynatraceResourceDetector::detect() {
Resource resource;
resource.schema_url_ = "";
int failure_count = 0;

for (const auto& file_name : DynatraceResourceDetector::dynatraceMetadataFiles()) {
TRY_NEEDS_AUDIT {
std::string content = dynatrace_file_reader_->readEnrichmentFile(file_name);
if (content.empty()) {
failure_count++;
} else {
addAttributes(content, resource);
}
}
END_TRY catch (const EnvoyException&) { failure_count++; }
}

if (failure_count > 0) {
ENVOY_LOG(
warn,
"Dynatrace OpenTelemetry resource detector is configured but could not detect attributes. "
"Check the Dynatrace deployment status to ensure it is correctly deployed.");
}

return resource;
}

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

0 comments on commit be410d6

Please sign in to comment.