diff --git a/sdk/include/opentelemetry/sdk/configuration/document_node.h b/sdk/include/opentelemetry/sdk/configuration/document_node.h index dfc21df0ca..0ca1046542 100644 --- a/sdk/include/opentelemetry/sdk/configuration/document_node.h +++ b/sdk/include/opentelemetry/sdk/configuration/document_node.h @@ -58,6 +58,13 @@ class DocumentNode virtual PropertiesNodeConstIterator end_properties() const = 0; virtual std::string Dump() const = 0; + +protected: + void DoSubstitution(std::string &value); + + bool BooleanFromString(const std::string &value); + size_t IntegerFromString(const std::string &value); + double DoubleFromString(const std::string &value); }; class DocumentNodeConstIteratorImpl diff --git a/sdk/src/configuration/CMakeLists.txt b/sdk/src/configuration/CMakeLists.txt index 03e70f9723..15efe1d364 100644 --- a/sdk/src/configuration/CMakeLists.txt +++ b/sdk/src/configuration/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( opentelemetry_configuration - configuration_factory.cc yaml_configuration_factory.cc ryml_document.cc + configuration_factory.cc document_node.cc yaml_configuration_factory.cc ryml_document.cc ryml_document_node.cc) set_target_properties(opentelemetry_configuration PROPERTIES EXPORT_NAME diff --git a/sdk/src/configuration/document_node.cc b/sdk/src/configuration/document_node.cc new file mode 100644 index 0000000000..a89242a504 --- /dev/null +++ b/sdk/src/configuration/document_node.cc @@ -0,0 +1,103 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#include "opentelemetry/sdk/common/global_log_handler.h" + +#include "opentelemetry/sdk/configuration/document_node.h" +#include "opentelemetry/sdk/configuration/invalid_schema_exception.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace configuration +{ + +void DocumentNode::DoSubstitution(std::string &value) +{ + size_t len = value.length(); + char c; + + if (len < 4) + { + return; + } + + c = value[0]; + if (c != '$') + { + return; + } + + c = value[1]; + if (c != '{') + { + return; + } + + c = value[len - 1]; + if (c != '}') + { + return; + } + + c = value[2]; + if (!std::isalpha(c) && c != '_') + { + return; + } + + for (int i = 3; i <= len - 2; i++) + { + c = value[i]; + if (!std::isalnum(c) && c != '_') + { + return; + } + } + + // value is of the form ${ENV_NAME} + + std::string name = value.substr(2, len - 3); + + const char *sub = std::getenv(name.c_str()); + if (sub != nullptr) + { + value = sub; + } + else + { + value = ""; + } +} + +bool DocumentNode::BooleanFromString(const std::string &value) +{ + if (value == "true") + { + return true; + } + + if (value == "false") + { + return false; + } + + throw InvalidSchemaException("Illegal bool value"); +} + +size_t DocumentNode::IntegerFromString(const std::string &value) +{ + size_t val = atoll(value.c_str()); + return val; +} + +double DocumentNode::DoubleFromString(const std::string &value) +{ + double val = atof(value.c_str()); + return val; +} + +} // namespace configuration +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/configuration/ryml_document_node.cc b/sdk/src/configuration/ryml_document_node.cc index 1cc2c2839f..0fc61dd36a 100644 --- a/sdk/src/configuration/ryml_document_node.cc +++ b/sdk/src/configuration/ryml_document_node.cc @@ -256,6 +256,8 @@ std::string RymlDocumentNode::GetRequiredString(const std::string &name) ryml::csubstr view = ryml_child.val(); std::string value(view.str, view.len); + DoSubstitution(value); + return value; } @@ -272,6 +274,9 @@ std::string RymlDocumentNode::GetString(const std::string &name, const std::stri ryml::csubstr view = ryml_child.val(); std::string value(view.str, view.len); + + DoSubstitution(value); + return value; } diff --git a/sdk/test/configuration/yaml_test.cc b/sdk/test/configuration/yaml_test.cc index 210265d752..8c69f022a0 100644 --- a/sdk/test/configuration/yaml_test.cc +++ b/sdk/test/configuration/yaml_test.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include "opentelemetry/sdk/configuration/yaml_configuration_factory.h" @@ -143,3 +144,42 @@ file_format: xx.yy auto config = DoParse(yaml); ASSERT_EQ(config, nullptr); } + +TEST(Yaml, no_substitution) +{ + unsetenv("ENV_NAME"); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, ""); +} + +TEST(Yaml, empty_substitution) +{ + setenv("ENV_NAME", "", 1); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, ""); +} + +TEST(Yaml, with_substitution) +{ + setenv("ENV_NAME", "foo.bar", 1); + + std::string yaml = R"( +file_format: ${ENV_NAME} +)"; + + auto config = DoParse(yaml); + ASSERT_NE(config, nullptr); + ASSERT_EQ(config->file_format, "foo.bar"); +}