diff --git a/sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/DefaultConfigProperties.java b/sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/DefaultConfigProperties.java index b8673993fe3..b9092954605 100644 --- a/sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/DefaultConfigProperties.java +++ b/sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/internal/DefaultConfigProperties.java @@ -14,6 +14,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import java.time.Duration; import java.util.AbstractMap; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -181,7 +182,35 @@ public List getList(String name) { if (value == null) { return Collections.emptyList(); } - return filterBlanksAndNulls(value.split(",")); + + // Support list members containing commas per RFC9110 5.5 suggestion + List listMembers = new ArrayList<>(); + StringBuilder curValue = new StringBuilder(); + boolean openedQuote = false; + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + if (openedQuote) { + openedQuote = false; + listMembers.add(curValue.toString()); + curValue = new StringBuilder(); + } else { + openedQuote = true; + } + } else if (c == ',') { + if (openedQuote) { + curValue.append(c); + } else { + listMembers.add(curValue.toString()); + curValue = new StringBuilder(); + } + } else { + curValue.append(c); + } + } + listMembers.add(curValue.toString()); + + return filterBlanksAndNulls(listMembers); } /** @@ -212,8 +241,8 @@ public Map getMap(String name) { return getList(ConfigUtil.normalizePropertyKey(name)).stream() .map( entry -> { - String[] split = entry.split("=", 2); - if (split.length != 2 || StringUtils.isNullOrEmpty(split[0])) { + List split = Arrays.asList(entry.split("=", 2)); + if (split.size() != 2 || StringUtils.isNullOrEmpty(split.get(0))) { throw new ConfigurationException( "Invalid map property: " + name + "=" + config.get(name)); } @@ -246,11 +275,8 @@ private static ConfigurationException newInvalidPropertyException( "Invalid value for property " + name + "=" + value + ". Must be a " + type + "."); } - private static List filterBlanksAndNulls(String[] values) { - return Arrays.stream(values) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .collect(Collectors.toList()); + private static List filterBlanksAndNulls(List values) { + return values.stream().map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); } /** Returns the TimeUnit associated with a unit string. Defaults to milliseconds. */ diff --git a/sdk-extensions/autoconfigure-spi/src/test/java/io/opentelemetry/sdk/autoconfigure/spi/internal/ConfigPropertiesTest.java b/sdk-extensions/autoconfigure-spi/src/test/java/io/opentelemetry/sdk/autoconfigure/spi/internal/ConfigPropertiesTest.java index e0fe198dc9e..c01f88dec65 100644 --- a/sdk-extensions/autoconfigure-spi/src/test/java/io/opentelemetry/sdk/autoconfigure/spi/internal/ConfigPropertiesTest.java +++ b/sdk-extensions/autoconfigure-spi/src/test/java/io/opentelemetry/sdk/autoconfigure/spi/internal/ConfigPropertiesTest.java @@ -34,6 +34,9 @@ void allValid() { assertThat(config.getList("test.list")).containsExactly("cat", "dog", "bear"); assertThat(config.getMap("test.map")) .containsExactly(entry("cat", "meow"), entry("dog", "bark"), entry("bear", "growl")); + assertThat(config.getMap("test.map.commas")) + .containsExactly( + entry("cat", "meow,hiss"), entry("dog", "bark,growl"), entry("bear", "roar")); assertThat(config.getDuration("test.duration")).isEqualTo(Duration.ofSeconds(1)); } @@ -49,6 +52,9 @@ void allValidUsingHyphens() { assertThat(config.getList("test-list")).containsExactly("cat", "dog", "bear"); assertThat(config.getMap("test-map")) .containsExactly(entry("cat", "meow"), entry("dog", "bark"), entry("bear", "growl")); + assertThat(config.getMap("test-map-commas")) + .containsExactly( + entry("cat", "meow,hiss"), entry("dog", "bark,growl"), entry("bear", "roar")); assertThat(config.getDuration("test-duration")).isEqualTo(Duration.ofSeconds(1)); } @@ -61,6 +67,7 @@ void allMissing() { assertThat(config.getDouble("test.double")).isNull(); assertThat(config.getList("test.list")).isEmpty(); assertThat(config.getMap("test.map")).isEmpty(); + assertThat(config.getMap("test.map.commas")).isEmpty(); assertThat(config.getDuration("test.duration")).isNull(); } @@ -73,6 +80,7 @@ void allEmpty() { properties.put("test.double", ""); properties.put("test.list", ""); properties.put("test.map", ""); + properties.put("test.map.commas", ""); properties.put("test.duration", ""); ConfigProperties config = DefaultConfigProperties.createFromMap(properties); @@ -82,6 +90,7 @@ void allEmpty() { assertThat(config.getDouble("test.double")).isNull(); assertThat(config.getList("test.list")).isEmpty(); assertThat(config.getMap("test.map")).isEmpty(); + assertThat(config.getMap("test.map.commas")).isEmpty(); assertThat(config.getDuration("test.duration")).isNull(); } @@ -277,6 +286,7 @@ private static Map makeTestProps() { properties.put("test.list", "cat,dog,bear"); properties.put("test.map", "cat=meow,dog=bark,bear=growl,bird="); properties.put("test.duration", "1s"); + properties.put("test.map.commas", "cat=\"meow,hiss\",dog=\"bark,growl\", bear=roar"); return properties; } }