Skip to content

Commit 48d0e51

Browse files
committed
Change ConfigProvider to iterate from lowest to highest precedence source, adn report all to ConfigCollector
1 parent 0f91094 commit 48d0e51

File tree

2 files changed

+139
-78
lines changed

2 files changed

+139
-78
lines changed

internal-api/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java

Lines changed: 110 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import datadog.environment.SystemProperties;
66
import datadog.trace.api.ConfigCollector;
77
import datadog.trace.api.ConfigOrigin;
8+
import datadog.trace.api.config.AppSecConfig;
89
import de.thetaphi.forbiddenapis.SuppressForbidden;
910
import java.io.File;
1011
import java.io.FileNotFoundException;
1112
import java.io.FileReader;
1213
import java.io.IOException;
1314
import java.util.Arrays;
1415
import java.util.BitSet;
16+
import java.util.Collections;
1517
import java.util.HashMap;
1618
import java.util.HashSet;
1719
import java.util.LinkedHashMap;
@@ -42,6 +44,32 @@ private ConfigProvider(boolean collectConfig, ConfigProvider.Source... sources)
4244
this.sources = sources;
4345
}
4446

47+
/**
48+
* Creates a ConfigProvider with sources ordered from lowest to highest precedence. Internally
49+
* reverses the array to support the new approach of iterating from lowest to highest precedence,
50+
* enabling reporting of all configured sources to telemetry (not just the highest-precedence
51+
* match).
52+
*
53+
* @param sources the configuration sources, in order from lowest to highest precedence
54+
* @return a ConfigProvider with sources in precedence order (highest first)
55+
*/
56+
public static ConfigProvider createWithPrecedenceOrder(Source... sources) {
57+
Source[] reversed = Arrays.copyOf(sources, sources.length);
58+
Collections.reverse(Arrays.asList(reversed));
59+
return new ConfigProvider(reversed);
60+
}
61+
62+
/**
63+
* Same as {@link #createWithPrecedenceOrder(Source...)} but allows specifying the collectConfig
64+
* flag.
65+
*/
66+
public static ConfigProvider createWithPrecedenceOrder(boolean collectConfig, Source... sources) {
67+
Source[] reversed = Arrays.copyOf(sources, sources.length);
68+
Collections.reverse(Arrays.asList(reversed));
69+
return new ConfigProvider(collectConfig, reversed);
70+
}
71+
72+
// TODO: Handle this special case
4573
public String getConfigFileStatus() {
4674
for (ConfigProvider.Source source : sources) {
4775
if (source instanceof PropertiesConfigSource) {
@@ -75,63 +103,79 @@ public <T extends Enum<T>> T getEnum(String key, Class<T> enumType, T defaultVal
75103
}
76104

77105
public String getString(String key, String defaultValue, String... aliases) {
106+
if (collectConfig) {
107+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
108+
}
109+
String value = null;
78110
for (ConfigProvider.Source source : sources) {
79-
String value = source.get(key, aliases);
80-
if (value != null) {
111+
String tmp = source.get(key, aliases);
112+
if (tmp != null) {
113+
value = tmp;
81114
if (collectConfig) {
82115
ConfigCollector.get().put(key, value, source.origin());
83116
}
84-
return value;
85117
}
86118
}
87-
if (collectConfig) {
88-
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
89-
}
90-
return defaultValue;
119+
return value != null ? value : defaultValue;
91120
}
92121

93122
/**
94123
* Like {@link #getString(String, String, String...)} but falls back to next source if a value is
95124
* an empty or blank string.
96125
*/
97126
public String getStringNotEmpty(String key, String defaultValue, String... aliases) {
127+
if (collectConfig) {
128+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
129+
}
130+
String value = null;
98131
for (ConfigProvider.Source source : sources) {
99-
String value = source.get(key, aliases);
100-
if (value != null && !value.trim().isEmpty()) {
132+
String tmp = source.get(key, aliases);
133+
if (key.equals(AppSecConfig.APPSEC_AUTOMATED_USER_EVENTS_TRACKING)) {
134+
System.out.println("MTOFF - source: " + source.getClass().getSimpleName() + " tmp: " + tmp);
135+
}
136+
if (tmp != null && !tmp.trim().isEmpty()) {
137+
value = tmp;
138+
if (key.equals(AppSecConfig.APPSEC_AUTOMATED_USER_EVENTS_TRACKING)) {
139+
System.out.println(
140+
"MTOFF - source: " + source.getClass().getSimpleName() + " value: " + value);
141+
}
101142
if (collectConfig) {
102143
ConfigCollector.get().put(key, value, source.origin());
103144
}
104-
return value;
105145
}
106146
}
107147
if (collectConfig) {
108148
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
109149
}
110-
return defaultValue;
150+
return value != null ? value : defaultValue;
111151
}
112152

113153
public String getStringExcludingSource(
114154
String key,
115155
String defaultValue,
116156
Class<? extends ConfigProvider.Source> excludedSource,
117157
String... aliases) {
158+
if (collectConfig) {
159+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
160+
}
161+
String value = null;
118162
for (ConfigProvider.Source source : sources) {
119163
if (excludedSource.isAssignableFrom(source.getClass())) {
120164
continue;
121165
}
122166

123-
String value = source.get(key, aliases);
124-
if (value != null) {
167+
String tmp = source.get(key, aliases);
168+
if (tmp != null) {
169+
value = tmp;
125170
if (collectConfig) {
126171
ConfigCollector.get().put(key, value, source.origin());
127172
}
128-
return value;
129173
}
130174
}
131175
if (collectConfig) {
132176
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
133177
}
134-
return defaultValue;
178+
return value != null ? value : defaultValue;
135179
}
136180

137181
public boolean isSet(String key) {
@@ -192,15 +236,19 @@ public double getDouble(String key, double defaultValue) {
192236
}
193237

194238
private <T> T get(String key, T defaultValue, Class<T> type, String... aliases) {
239+
if (collectConfig) {
240+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
241+
}
242+
T value = null;
195243
for (ConfigProvider.Source source : sources) {
196244
try {
197245
String sourceValue = source.get(key, aliases);
198-
T value = ConfigConverter.valueOf(sourceValue, type);
199-
if (value != null) {
246+
T tmp = ConfigConverter.valueOf(sourceValue, type);
247+
if (tmp != null) {
248+
value = tmp;
200249
if (collectConfig) {
201250
ConfigCollector.get().put(key, sourceValue, source.origin());
202251
}
203-
return value;
204252
}
205253
} catch (NumberFormatException ex) {
206254
// continue
@@ -209,31 +257,31 @@ private <T> T get(String key, T defaultValue, Class<T> type, String... aliases)
209257
if (collectConfig) {
210258
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
211259
}
212-
return defaultValue;
260+
return value != null ? value : defaultValue;
213261
}
214262

215263
public List<String> getList(String key) {
216264
return ConfigConverter.parseList(getString(key));
217265
}
218266

219267
public List<String> getList(String key, List<String> defaultValue) {
268+
if (collectConfig) {
269+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
270+
}
220271
String list = getString(key);
221272
if (null == list) {
222-
if (collectConfig) {
223-
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
224-
}
225273
return defaultValue;
226274
} else {
227275
return ConfigConverter.parseList(list);
228276
}
229277
}
230278

231279
public Set<String> getSet(String key, Set<String> defaultValue) {
280+
if (collectConfig) {
281+
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
282+
}
232283
String list = getString(key);
233284
if (null == list) {
234-
if (collectConfig) {
235-
ConfigCollector.get().put(key, defaultValue, ConfigOrigin.DEFAULT);
236-
}
237285
return defaultValue;
238286
} else {
239287
return new HashSet(ConfigConverter.parseList(list));
@@ -250,16 +298,20 @@ public Map<String, String> getMergedMap(String key, String... aliases) {
250298
// System properties take precedence over env
251299
// prior art:
252300
// https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html
253-
// We reverse iterate to allow overrides
254-
for (int i = sources.length - 1; 0 <= i; i--) {
255-
String value = sources[i].get(key, aliases);
301+
// We iterate in order so higher precedence sources overwrite lower precedence
302+
for (Source source : sources) {
303+
String value = source.get(key, aliases);
256304
Map<String, String> parsedMap = ConfigConverter.parseMap(value, key);
257305
if (!parsedMap.isEmpty()) {
258-
origin = sources[i].origin();
306+
origin = source.origin();
307+
if (collectConfig) {
308+
ConfigCollector.get().put(key, parsedMap, origin);
309+
}
259310
}
260311
merged.putAll(parsedMap);
261312
}
262313
if (collectConfig) {
314+
// TO DISCUSS: But if multiple sources have been set, origin isn't exactly accurate here...?
263315
ConfigCollector.get().put(key, merged, origin);
264316
}
265317
return merged;
@@ -271,13 +323,16 @@ public Map<String, String> getMergedTagsMap(String key, String... aliases) {
271323
// System properties take precedence over env
272324
// prior art:
273325
// https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html
274-
// We reverse iterate to allow overrides
275-
for (int i = sources.length - 1; 0 <= i; i--) {
276-
String value = sources[i].get(key, aliases);
326+
// We iterate in order so higher precedence sources overwrite lower precedence
327+
for (Source source : sources) {
328+
String value = source.get(key, aliases);
277329
Map<String, String> parsedMap =
278330
ConfigConverter.parseTraceTagsMap(value, ':', Arrays.asList(',', ' '));
279331
if (!parsedMap.isEmpty()) {
280-
origin = sources[i].origin();
332+
origin = source.origin();
333+
if (collectConfig) {
334+
ConfigCollector.get().put(key, parsedMap, origin);
335+
}
281336
}
282337
merged.putAll(parsedMap);
283338
}
@@ -293,12 +348,15 @@ public Map<String, String> getOrderedMap(String key) {
293348
// System properties take precedence over env
294349
// prior art:
295350
// https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html
296-
// We reverse iterate to allow overrides
297-
for (int i = sources.length - 1; 0 <= i; i--) {
298-
String value = sources[i].get(key);
351+
// We iterate in order so higher precedence sources overwrite lower precedence
352+
for (Source source : sources) {
353+
String value = source.get(key);
299354
Map<String, String> parsedMap = ConfigConverter.parseOrderedMap(value, key);
300355
if (!parsedMap.isEmpty()) {
301-
origin = sources[i].origin();
356+
origin = source.origin();
357+
if (collectConfig) {
358+
ConfigCollector.get().put(key, parsedMap, origin);
359+
}
302360
}
303361
merged.putAll(parsedMap);
304362
}
@@ -315,14 +373,17 @@ public Map<String, String> getMergedMapWithOptionalMappings(
315373
// System properties take precedence over env
316374
// prior art:
317375
// https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html
318-
// We reverse iterate to allow overrides
376+
// We iterate in order so higher precedence sources overwrite lower precedence
319377
for (String key : keys) {
320-
for (int i = sources.length - 1; 0 <= i; i--) {
321-
String value = sources[i].get(key);
378+
for (Source source : sources) {
379+
String value = source.get(key);
322380
Map<String, String> parsedMap =
323381
ConfigConverter.parseMapWithOptionalMappings(value, key, defaultPrefix, lowercaseKeys);
324382
if (!parsedMap.isEmpty()) {
325-
origin = sources[i].origin();
383+
origin = source.origin();
384+
if (collectConfig) {
385+
ConfigCollector.get().put(key, parsedMap, origin);
386+
}
326387
}
327388
merged.putAll(parsedMap);
328389
}
@@ -378,15 +439,15 @@ public static ConfigProvider createDefault() {
378439
loadConfigurationFile(
379440
new ConfigProvider(new SystemPropertiesConfigSource(), new EnvironmentConfigSource()));
380441
if (configProperties.isEmpty()) {
381-
return new ConfigProvider(
442+
return createWithPrecedenceOrder(
382443
new SystemPropertiesConfigSource(),
383444
StableConfigSource.FLEET,
384445
new EnvironmentConfigSource(),
385446
new OtelEnvironmentConfigSource(),
386447
StableConfigSource.LOCAL,
387448
new CapturedEnvironmentConfigSource());
388449
} else {
389-
return new ConfigProvider(
450+
return createWithPrecedenceOrder(
390451
new SystemPropertiesConfigSource(),
391452
StableConfigSource.FLEET,
392453
new EnvironmentConfigSource(),
@@ -400,10 +461,10 @@ public static ConfigProvider createDefault() {
400461
public static ConfigProvider withoutCollector() {
401462
Properties configProperties =
402463
loadConfigurationFile(
403-
new ConfigProvider(
464+
createWithPrecedenceOrder(
404465
false, new SystemPropertiesConfigSource(), new EnvironmentConfigSource()));
405466
if (configProperties.isEmpty()) {
406-
return new ConfigProvider(
467+
return createWithPrecedenceOrder(
407468
false,
408469
new SystemPropertiesConfigSource(),
409470
StableConfigSource.FLEET,
@@ -412,7 +473,7 @@ public static ConfigProvider withoutCollector() {
412473
StableConfigSource.LOCAL,
413474
new CapturedEnvironmentConfigSource());
414475
} else {
415-
return new ConfigProvider(
476+
return createWithPrecedenceOrder(
416477
false,
417478
new SystemPropertiesConfigSource(),
418479
StableConfigSource.FLEET,
@@ -428,12 +489,12 @@ public static ConfigProvider withPropertiesOverride(Properties properties) {
428489
PropertiesConfigSource providedConfigSource = new PropertiesConfigSource(properties, false);
429490
Properties configProperties =
430491
loadConfigurationFile(
431-
new ConfigProvider(
492+
createWithPrecedenceOrder(
432493
new SystemPropertiesConfigSource(),
433494
new EnvironmentConfigSource(),
434495
providedConfigSource));
435496
if (configProperties.isEmpty()) {
436-
return new ConfigProvider(
497+
return createWithPrecedenceOrder(
437498
new SystemPropertiesConfigSource(),
438499
StableConfigSource.FLEET,
439500
new EnvironmentConfigSource(),
@@ -442,7 +503,7 @@ public static ConfigProvider withPropertiesOverride(Properties properties) {
442503
StableConfigSource.LOCAL,
443504
new CapturedEnvironmentConfigSource());
444505
} else {
445-
return new ConfigProvider(
506+
return createWithPrecedenceOrder(
446507
providedConfigSource,
447508
new SystemPropertiesConfigSource(),
448509
StableConfigSource.FLEET,

0 commit comments

Comments
 (0)