Skip to content

Commit be410d6

Browse files
joaopgrassisamohte
andauthored
opentelemetry tracer: add Dynatrace resource detector (envoyproxy#30824)
* Add Dynatrace resource detector Co-authored-by: Thomas Ebner <96168670+samohte@users.noreply.github.com> Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> * PR suggestions Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> * Add tests for Dynatrace file reader Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> * PR suggestions Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> * schemaUrl_ -> schema_url_ Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> * PR suggestions and changelog Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> --------- Signed-off-by: Joao Grassi <joao.grassi@dynatrace.com> Co-authored-by: Thomas Ebner <96168670+samohte@users.noreply.github.com>
1 parent 61b5fcb commit be410d6

23 files changed

+742
-19
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
syntax = "proto3";
2+
3+
package envoy.extensions.tracers.opentelemetry.resource_detectors.v3;
4+
5+
import "udpa/annotations/status.proto";
6+
7+
option java_package = "io.envoyproxy.envoy.extensions.tracers.opentelemetry.resource_detectors.v3";
8+
option java_outer_classname = "DynatraceResourceDetectorProto";
9+
option java_multiple_files = true;
10+
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/tracers/opentelemetry/resource_detectors/v3;resource_detectorsv3";
11+
option (udpa.annotations.file_status).package_version_status = ACTIVE;
12+
13+
// [#protodoc-title: Dynatrace Resource Detector config]
14+
15+
// Configuration for the Dynatrace Resource Detector extension.
16+
// The resource detector reads from the Dynatrace enrichment files
17+
// and adds host/process related attributes to the OpenTelemetry resource.
18+
//
19+
// See:
20+
//
21+
// `Enrich ingested data with Dynatrace-specific dimensions <https://docs.dynatrace.com/docs/shortlink/enrichment-files>`_
22+
//
23+
// [#extension: envoy.tracers.opentelemetry.resource_detectors.dynatrace]
24+
message DynatraceResourceDetectorConfig {
25+
}

changelogs/current.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,5 +210,8 @@ new_features:
210210
and
211211
:ref:`response_attributes <envoy_v3_api_field_extensions.filters.http.ext_proc.v3.ExternalProcessor.response_attributes>`
212212
config APIs to enable sending and receiving attributes from/to the external processing server.
213+
- area: tracing
214+
change: |
215+
Added support to configure a Dynatrace resource detector for the OpenTelemetry tracer.
213216
214217
deprecated:

source/extensions/extensions_build_config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ EXTENSIONS = {
271271
#
272272

273273
"envoy.tracers.opentelemetry.resource_detectors.environment": "//source/extensions/tracers/opentelemetry/resource_detectors/environment:config",
274+
"envoy.tracers.opentelemetry.resource_detectors.dynatrace": "//source/extensions/tracers/opentelemetry/resource_detectors/dynatrace:config",
274275

275276
#
276277
# OpenTelemetry tracer samplers

source/extensions/extensions_metadata.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,3 +1697,10 @@ envoy.tracers.opentelemetry.resource_detectors.environment:
16971697
status: wip
16981698
type_urls:
16991699
- envoy.extensions.tracers.opentelemetry.resource_detectors.v3.EnvironmentResourceDetectorConfig
1700+
envoy.tracers.opentelemetry.resource_detectors.dynatrace:
1701+
categories:
1702+
- envoy.tracers.opentelemetry.resource_detectors
1703+
security_posture: unknown
1704+
status: wip
1705+
type_urls:
1706+
- envoy.extensions.tracers.opentelemetry.resource_detectors.v3.DynatraceResourceDetectorConfig
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
load(
2+
"//bazel:envoy_build_system.bzl",
3+
"envoy_cc_extension",
4+
"envoy_cc_library",
5+
"envoy_extension_package",
6+
)
7+
8+
licenses(["notice"]) # Apache 2
9+
10+
envoy_extension_package()
11+
12+
envoy_cc_extension(
13+
name = "config",
14+
srcs = ["config.cc"],
15+
hdrs = ["config.h"],
16+
deps = [
17+
":dynatrace_resource_detector_lib",
18+
"//envoy/registry",
19+
"//source/common/config:utility_lib",
20+
"@envoy_api//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg_cc_proto",
21+
],
22+
)
23+
24+
envoy_cc_library(
25+
name = "dynatrace_resource_detector_lib",
26+
srcs = [
27+
"dynatrace_metadata_file_reader.cc",
28+
"dynatrace_resource_detector.cc",
29+
],
30+
hdrs = [
31+
"dynatrace_metadata_file_reader.h",
32+
"dynatrace_resource_detector.h",
33+
],
34+
deps = [
35+
"//source/common/config:datasource_lib",
36+
"//source/extensions/tracers/opentelemetry/resource_detectors:resource_detector_lib",
37+
"@envoy_api//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg_cc_proto",
38+
],
39+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/config.h"
2+
3+
#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/dynatrace_resource_detector.pb.h"
4+
#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/dynatrace_resource_detector.pb.validate.h"
5+
6+
#include "source/common/config/utility.h"
7+
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader.h"
8+
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.h"
9+
10+
namespace Envoy {
11+
namespace Extensions {
12+
namespace Tracers {
13+
namespace OpenTelemetry {
14+
15+
ResourceDetectorPtr DynatraceResourceDetectorFactory::createResourceDetector(
16+
const Protobuf::Message& message, Server::Configuration::TracerFactoryContext& context) {
17+
18+
auto mptr = Envoy::Config::Utility::translateAnyToFactoryConfig(
19+
dynamic_cast<const ProtobufWkt::Any&>(message), context.messageValidationVisitor(), *this);
20+
21+
const auto& proto_config = MessageUtil::downcastAndValidate<
22+
const envoy::extensions::tracers::opentelemetry::resource_detectors::v3::
23+
DynatraceResourceDetectorConfig&>(*mptr, context.messageValidationVisitor());
24+
25+
DynatraceMetadataFileReaderPtr reader = std::make_unique<DynatraceMetadataFileReaderImpl>();
26+
return std::make_unique<DynatraceResourceDetector>(proto_config, std::move(reader));
27+
}
28+
29+
/**
30+
* Static registration for the Dynatrace resource detector factory. @see RegisterFactory.
31+
*/
32+
REGISTER_FACTORY(DynatraceResourceDetectorFactory, ResourceDetectorFactory);
33+
34+
} // namespace OpenTelemetry
35+
} // namespace Tracers
36+
} // namespace Extensions
37+
} // namespace Envoy
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
#include "envoy/extensions/tracers/opentelemetry/resource_detectors/v3/dynatrace_resource_detector.pb.h"
6+
7+
#include "source/extensions/tracers/opentelemetry/resource_detectors/resource_detector.h"
8+
9+
namespace Envoy {
10+
namespace Extensions {
11+
namespace Tracers {
12+
namespace OpenTelemetry {
13+
14+
/**
15+
* Config registration for the Dynatrace resource detector. @see ResourceDetectorFactory.
16+
*/
17+
class DynatraceResourceDetectorFactory : public ResourceDetectorFactory {
18+
public:
19+
/**
20+
* @brief Creates a Resource Detector that reads from the Dynatrace enrichment files.
21+
*
22+
* @see
23+
* https://docs.dynatrace.com/docs/shortlink/enrichment-files#oneagent-virtual-files
24+
*
25+
* @param message The resource detector configuration.
26+
* @param context The tracer factory context.
27+
* @return ResourceDetectorPtr
28+
*/
29+
ResourceDetectorPtr
30+
createResourceDetector(const Protobuf::Message& message,
31+
Server::Configuration::TracerFactoryContext& context) override;
32+
33+
ProtobufTypes::MessagePtr createEmptyConfigProto() override {
34+
return std::make_unique<envoy::extensions::tracers::opentelemetry::resource_detectors::v3::
35+
DynatraceResourceDetectorConfig>();
36+
}
37+
38+
std::string name() const override {
39+
return "envoy.tracers.opentelemetry.resource_detectors.dynatrace";
40+
}
41+
};
42+
43+
DECLARE_FACTORY(DynatraceResourceDetectorFactory);
44+
45+
} // namespace OpenTelemetry
46+
} // namespace Tracers
47+
} // namespace Extensions
48+
} // namespace Envoy
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_metadata_file_reader.h"
2+
3+
#include <fstream>
4+
#include <iostream>
5+
#include <sstream>
6+
#include <string>
7+
8+
#include "envoy/common/exception.h"
9+
10+
#include "source/common/common/logger.h"
11+
12+
#include "absl/strings/str_cat.h"
13+
14+
namespace Envoy {
15+
namespace Extensions {
16+
namespace Tracers {
17+
namespace OpenTelemetry {
18+
19+
namespace {
20+
21+
bool isIndirectionFile(const std::string& file_name) {
22+
return absl::StartsWith(file_name, "dt_metadata_");
23+
}
24+
25+
std::string readFile(const std::string& file_name) {
26+
if (file_name.empty()) {
27+
return "";
28+
}
29+
30+
std::ifstream file(file_name);
31+
if (file.fail()) {
32+
throw EnvoyException(absl::StrCat("Unable to read Dynatrace enrichment file: ", file_name));
33+
}
34+
35+
std::stringstream file_string;
36+
file_string << file.rdbuf();
37+
38+
return file_string.str();
39+
}
40+
41+
} // namespace
42+
43+
std::string DynatraceMetadataFileReaderImpl::readEnrichmentFile(const std::string& file_name) {
44+
if (const bool indirection_file = isIndirectionFile(file_name); indirection_file) {
45+
return readFile(readFile(file_name));
46+
} else {
47+
return readFile(file_name);
48+
}
49+
}
50+
51+
} // namespace OpenTelemetry
52+
} // namespace Tracers
53+
} // namespace Extensions
54+
} // namespace Envoy
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
3+
#include <array>
4+
#include <memory>
5+
#include <string>
6+
7+
#include "envoy/common/pure.h"
8+
9+
#include "absl/strings/match.h"
10+
11+
namespace Envoy {
12+
namespace Extensions {
13+
namespace Tracers {
14+
namespace OpenTelemetry {
15+
16+
/**
17+
* @brief A file reader that reads the content of the Dynatrace metadata enrichment files.
18+
* When OneAgent is monitoring your application, it provides access to the enrichment files.
19+
* These files do not physically exists in your file system, but are provided by the OneAgent on
20+
* demand. This allows obtaining not only information about the host, but also about process.
21+
*
22+
* @see
23+
* https://docs.dynatrace.com/docs/shortlink/enrichment-files#oneagent-virtual-files
24+
*
25+
*/
26+
class DynatraceMetadataFileReader {
27+
public:
28+
virtual ~DynatraceMetadataFileReader() = default;
29+
30+
/**
31+
* @brief Reads the enrichment file and returns the enrichment metadata.
32+
*
33+
* @param file_name The file name.
34+
* @return const std::string String (java-like properties) containing the enrichment metadata.
35+
*/
36+
virtual std::string readEnrichmentFile(const std::string& file_name) PURE;
37+
};
38+
39+
using DynatraceMetadataFileReaderPtr = std::unique_ptr<DynatraceMetadataFileReader>;
40+
41+
class DynatraceMetadataFileReaderImpl : public DynatraceMetadataFileReader {
42+
public:
43+
std::string readEnrichmentFile(const std::string& file_name) override;
44+
};
45+
46+
} // namespace OpenTelemetry
47+
} // namespace Tracers
48+
} // namespace Extensions
49+
} // namespace Envoy
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "source/extensions/tracers/opentelemetry/resource_detectors/dynatrace/dynatrace_resource_detector.h"
2+
3+
#include <fstream>
4+
#include <iostream>
5+
6+
namespace Envoy {
7+
namespace Extensions {
8+
namespace Tracers {
9+
namespace OpenTelemetry {
10+
namespace {
11+
12+
void addAttributes(const std::string& content, Resource& resource) {
13+
for (const auto& line : StringUtil::splitToken(content, "\n", false, true)) {
14+
const auto key_value = StringUtil::splitToken(line, "=");
15+
if (key_value.size() != 2) {
16+
continue;
17+
}
18+
resource.attributes_[std::string(key_value[0])] = std::string(key_value[1]);
19+
}
20+
}
21+
22+
} // namespace
23+
24+
Resource DynatraceResourceDetector::detect() {
25+
Resource resource;
26+
resource.schema_url_ = "";
27+
int failure_count = 0;
28+
29+
for (const auto& file_name : DynatraceResourceDetector::dynatraceMetadataFiles()) {
30+
TRY_NEEDS_AUDIT {
31+
std::string content = dynatrace_file_reader_->readEnrichmentFile(file_name);
32+
if (content.empty()) {
33+
failure_count++;
34+
} else {
35+
addAttributes(content, resource);
36+
}
37+
}
38+
END_TRY catch (const EnvoyException&) { failure_count++; }
39+
}
40+
41+
if (failure_count > 0) {
42+
ENVOY_LOG(
43+
warn,
44+
"Dynatrace OpenTelemetry resource detector is configured but could not detect attributes. "
45+
"Check the Dynatrace deployment status to ensure it is correctly deployed.");
46+
}
47+
48+
return resource;
49+
}
50+
51+
} // namespace OpenTelemetry
52+
} // namespace Tracers
53+
} // namespace Extensions
54+
} // namespace Envoy

0 commit comments

Comments
 (0)