Line data Source code
1 : #include "source/extensions/tracers/opentelemetry/resource_detectors/resource_provider.h" 2 : 3 : #include <string> 4 : 5 : #include "source/common/common/logger.h" 6 : #include "source/common/config/utility.h" 7 : 8 : namespace Envoy { 9 : namespace Extensions { 10 : namespace Tracers { 11 : namespace OpenTelemetry { 12 : 13 : namespace { 14 0 : bool isEmptyResource(const Resource& resource) { return resource.attributes_.empty(); } 15 : 16 0 : Resource createInitialResource(const std::string& service_name) { 17 0 : Resource resource{}; 18 : 19 : // Creates initial resource with the static service.name attribute. 20 0 : resource.attributes_[std::string(kServiceNameKey.data(), kServiceNameKey.size())] = 21 0 : service_name.empty() ? std::string{kDefaultServiceName} : service_name; 22 : 23 0 : return resource; 24 0 : } 25 : 26 : /** 27 : * @brief Resolves the new schema url when merging two resources. 28 : * This function implements the algorithm as defined in the OpenTelemetry Resource SDK 29 : * specification. @see 30 : * https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/resource/sdk.md#merge 31 : * 32 : * @param old_schema_url The old resource's schema URL. 33 : * @param updating_schema_url The updating resource's schema URL. 34 : * @return std::string The calculated schema URL. 35 : */ 36 : std::string resolveSchemaUrl(const std::string& old_schema_url, 37 0 : const std::string& updating_schema_url) { 38 0 : if (old_schema_url.empty()) { 39 0 : return updating_schema_url; 40 0 : } 41 0 : if (updating_schema_url.empty()) { 42 0 : return old_schema_url; 43 0 : } 44 0 : if (old_schema_url == updating_schema_url) { 45 0 : return old_schema_url; 46 0 : } 47 : // The OTel spec leaves this case (when both have value but are different) unspecified. 48 0 : ENVOY_LOG_MISC(info, "Resource schemaUrl conflict. Fall-back to old schema url: {}", 49 0 : old_schema_url); 50 0 : return old_schema_url; 51 0 : } 52 : 53 : /** 54 : * @brief Updates an old resource with a new one. This function implements 55 : * the Merge operation defined in the OpenTelemetry Resource SDK specification. 56 : * @see 57 : * https://github.com/open-telemetry/opentelemetry-specification/blob/v1.24.0/specification/resource/sdk.md#merge 58 : * 59 : * @param old_resource The old resource. 60 : * @param updating_resource The new resource. 61 : */ 62 0 : void mergeResource(Resource& old_resource, const Resource& updating_resource) { 63 : // The schemaUrl is merged, regardless if the resources being merged 64 : // have attributes or not. This behavior is compliant with the OTel spec. 65 : // see: https://github.com/envoyproxy/envoy/pull/29547#discussion_r1344540427 66 0 : old_resource.schema_url_ = 67 0 : resolveSchemaUrl(old_resource.schema_url_, updating_resource.schema_url_); 68 : 69 0 : if (isEmptyResource(updating_resource)) { 70 0 : return; 71 0 : } 72 0 : for (auto const& attr : updating_resource.attributes_) { 73 0 : old_resource.attributes_.insert_or_assign(attr.first, attr.second); 74 0 : } 75 0 : } 76 : } // namespace 77 : 78 : Resource ResourceProviderImpl::getResource( 79 : const envoy::config::trace::v3::OpenTelemetryConfig& opentelemetry_config, 80 0 : Server::Configuration::TracerFactoryContext& context) const { 81 : 82 0 : Resource resource = createInitialResource(opentelemetry_config.service_name()); 83 : 84 0 : const auto& detectors_configs = opentelemetry_config.resource_detectors(); 85 : 86 0 : for (const auto& detector_config : detectors_configs) { 87 0 : ResourceDetectorPtr detector; 88 0 : auto* factory = Envoy::Config::Utility::getFactory<ResourceDetectorFactory>(detector_config); 89 : 90 0 : if (!factory) { 91 0 : throw EnvoyException( 92 0 : fmt::format("Resource detector factory not found: '{}'", detector_config.name())); 93 0 : } 94 : 95 0 : detector = factory->createResourceDetector(detector_config.typed_config(), context); 96 : 97 0 : if (!detector) { 98 0 : throw EnvoyException( 99 0 : fmt::format("Resource detector could not be created: '{}'", detector_config.name())); 100 0 : } 101 : 102 0 : Resource detected_resource = detector->detect(); 103 0 : mergeResource(resource, detected_resource); 104 0 : } 105 0 : return resource; 106 0 : } 107 : 108 : } // namespace OpenTelemetry 109 : } // namespace Tracers 110 : } // namespace Extensions 111 : } // namespace Envoy