|
17 | 17 | import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; |
18 | 18 | import io.opentelemetry.sdk.resources.Resource; |
19 | 19 | import io.opentelemetry.sdk.resources.ResourceBuilder; |
20 | | -import java.io.UnsupportedEncodingException; |
21 | | -import java.net.URLDecoder; |
22 | 20 | import java.nio.charset.StandardCharsets; |
23 | 21 | import java.util.Collections; |
24 | 22 | import java.util.HashSet; |
@@ -67,18 +65,14 @@ public static Resource createEnvironmentResource() { |
67 | 65 | */ |
68 | 66 | public static Resource createEnvironmentResource(ConfigProperties config) { |
69 | 67 | AttributesBuilder resourceAttributes = Attributes.builder(); |
70 | | - try { |
71 | | - for (Map.Entry<String, String> entry : config.getMap(ATTRIBUTE_PROPERTY).entrySet()) { |
72 | | - resourceAttributes.put( |
73 | | - entry.getKey(), |
74 | | - // Attributes specified via otel.resource.attributes follow the W3C Baggage spec and |
75 | | - // characters outside the baggage-octet range are percent encoded |
76 | | - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable |
77 | | - URLDecoder.decode(entry.getValue(), StandardCharsets.UTF_8.displayName())); |
78 | | - } |
79 | | - } catch (UnsupportedEncodingException e) { |
80 | | - // Should not happen since always using standard charset |
81 | | - throw new ConfigurationException("Unable to decode resource attributes.", e); |
| 68 | + for (Map.Entry<String, String> entry : config.getMap(ATTRIBUTE_PROPERTY).entrySet()) { |
| 69 | + resourceAttributes.put( |
| 70 | + entry.getKey(), |
| 71 | + // Attributes specified via otel.resource.attributes follow the W3C Baggage spec and |
| 72 | + // characters outside the baggage-octet range are percent encoded |
| 73 | + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#specifying-resource-information-via-an-environment-variable |
| 74 | + |
| 75 | + decodeResourceAttributes(entry.getValue())); |
82 | 76 | } |
83 | 77 | String serviceName = config.getString(SERVICE_NAME_PROPERTY); |
84 | 78 | if (serviceName != null) { |
@@ -132,5 +126,35 @@ static Resource filterAttributes(Resource resource, ConfigProperties configPrope |
132 | 126 | return builder.build(); |
133 | 127 | } |
134 | 128 |
|
| 129 | + private static String decodeResourceAttributes(String value) { |
| 130 | + try { |
| 131 | + if (value.indexOf('%') < 0) { |
| 132 | + return value; |
| 133 | + } |
| 134 | + |
| 135 | + int n = value.length(); |
| 136 | + byte[] bytes = new byte[n]; |
| 137 | + int pos = 0; |
| 138 | + |
| 139 | + for (int i = 0; i < n; i++) { |
| 140 | + char c = value.charAt(i); |
| 141 | + if (c == '%' && i + 2 < n) { |
| 142 | + int d1 = Character.digit(value.charAt(i + 1), 16); |
| 143 | + int d2 = Character.digit(value.charAt(i + 2), 16); |
| 144 | + if (d1 != -1 && d2 != -1) { |
| 145 | + bytes[pos++] = (byte) ((d1 << 4) + d2); |
| 146 | + i += 2; |
| 147 | + continue; |
| 148 | + } |
| 149 | + } |
| 150 | + // Keep '+' as '+' and any other non-encoded chars |
| 151 | + bytes[pos++] = (byte) c; |
| 152 | + } |
| 153 | + return new String(bytes, 0, pos, StandardCharsets.UTF_8); |
| 154 | + } catch (RuntimeException e) { |
| 155 | + throw new ConfigurationException("Failed to decode resource attributes: " + value, e); |
| 156 | + } |
| 157 | + } |
| 158 | + |
135 | 159 | private ResourceConfiguration() {} |
136 | 160 | } |
0 commit comments