diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java index 7e5e98344d6..759bab24d65 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java @@ -51,7 +51,7 @@ public final class FileConfiguration { private static final Logger logger = Logger.getLogger(FileConfiguration.class.getName()); private static final Pattern ENV_VARIABLE_REFERENCE = - Pattern.compile("\\$\\{([a-zA-Z_][a-zA-Z0-9_]*)(:-([^\n}]*))?}"); + Pattern.compile("\\${1,2}\\{([a-zA-Z_][a-zA-Z0-9_]*)(:-([^\n}]*))?}"); private static final ComponentLoader DEFAULT_COMPONENT_LOADER = SpiHelper.serviceComponentLoader(FileConfiguration.class.getClassLoader()); @@ -317,13 +317,22 @@ private Object constructValueObject(Node node) { ScalarStyle scalarStyle = ((ScalarNode) node).getScalarStyle(); do { MatchResult matchResult = matcher.toMatchResult(); - String envVarKey = matcher.group(1); - String defaultValue = matcher.group(3); - if (defaultValue == null) { - defaultValue = ""; + newVal.append(val, offset, matchResult.start()); + + String ref = val.substring(matchResult.start(), matchResult.end()); + // $$ indicates that env var reference is escaped. Strip the leading $. + if (ref.startsWith("$$")) { + newVal.append(ref.substring(1)); + } else { + String envVarKey = matcher.group(1); + String defaultValue = matcher.group(3); + if (defaultValue == null) { + defaultValue = ""; + } + String replacement = environmentVariables.getOrDefault(envVarKey, defaultValue); + newVal.append(replacement); } - String replacement = environmentVariables.getOrDefault(envVarKey, defaultValue); - newVal.append(val, offset, matchResult.start()).append(replacement); + offset = matchResult.end(); } while (matcher.find()); if (offset != val.length()) { diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigurationParseTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigurationParseTest.java index 7de63dcb45c..ee7c597baac 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigurationParseTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigurationParseTest.java @@ -656,7 +656,13 @@ private static java.util.stream.Stream envVarSubstitutionArgs() { Arguments.of("key1: \"${EMPTY_STR}\"\n", mapOf(entry("key1", ""))), Arguments.of("key1: \"${BOOL}\"\n", mapOf(entry("key1", "true"))), Arguments.of("key1: \"${INT}\"\n", mapOf(entry("key1", "1"))), - Arguments.of("key1: \"${FLOAT}\"\n", mapOf(entry("key1", "1.1")))); + Arguments.of("key1: \"${FLOAT}\"\n", mapOf(entry("key1", "1.1"))), + // Escaped + Arguments.of("key1: $${STR_1}\n", mapOf(entry("key1", "${STR_1}"))), + Arguments.of("key1: \"$${STR_1}\"\n", mapOf(entry("key1", "${STR_1}"))), + Arguments.of("key1: $${STR_1} ${STR_2}\n", mapOf(entry("key1", "${STR_1} value2"))), + Arguments.of("key1: $${STR_1} $${STR_2}\n", mapOf(entry("key1", "${STR_1} ${STR_2}"))), + Arguments.of("key1: $${NOT_SET:-value1}\n", mapOf(entry("key1", "${NOT_SET:-value1}")))); } private static Map.Entry entry(K key, @Nullable V value) {