diff --git a/archaius-core/src/main/java/com/netflix/config/ConcurrentCompositeConfiguration.java b/archaius-core/src/main/java/com/netflix/config/ConcurrentCompositeConfiguration.java index 7b792202..d7aa61a3 100644 --- a/archaius-core/src/main/java/com/netflix/config/ConcurrentCompositeConfiguration.java +++ b/archaius-core/src/main/java/com/netflix/config/ConcurrentCompositeConfiguration.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.ConcurrentModificationException; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; @@ -32,6 +33,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicReference; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationRuntimeException; @@ -107,14 +110,25 @@ public class ConcurrentCompositeConfiguration extends ConcurrentMapConfiguration public static final String ENABLE_STACK_TRACE = "archaius_enable_stack_trace"; public static final String ENABLE_INSTRUMENTATION = "archaius_enable_instrumentation"; + public static final String STACK_TRACE_ENABLED_PROPERTIES = "archaius_stack_trace_enabled_properties"; private final boolean enableStackTrace = Boolean.parseBoolean(System.getProperty(ENABLE_STACK_TRACE)); private final boolean enableInstrumentation = Boolean.parseBoolean(System.getProperty(ENABLE_INSTRUMENTATION)); + private final Set stackTraceEnabledProperties = convertStringFlag(System.getProperty(STACK_TRACE_ENABLED_PROPERTIES)); private Map namedConfigurations = new ConcurrentHashMap<>(); private final Map stackTraces = new ConcurrentHashMap<>(); + private final Map> stackTracesAndProperties = new ConcurrentHashMap<>(); private final AtomicReference> usedPropertiesRef = new AtomicReference<>(ConcurrentHashMap.newKeySet()); + private Set convertStringFlag(String properties) { + if (properties == null) { + return Collections.emptySet(); + } + + return ImmutableSet.copyOf(Splitter.on(',').trimResults().omitEmptyStrings().split(properties)); + } + public Set getUsedProperties() { return Collections.unmodifiableSet(new HashSet<>(usedPropertiesRef.get())); } @@ -124,6 +138,15 @@ public Set getAndClearUsedProperties() { return Collections.unmodifiableSet(ret); } + public Map getInstrumentationStackTraces() { + return Collections.unmodifiableMap(new HashMap<>(stackTraces)); + } + + public Map> getInstrumentationStackTracesAndProperties() { + // Shallow copy + return Collections.unmodifiableMap(new HashMap<>(stackTracesAndProperties)); + } + private List configList = new CopyOnWriteArrayList(); private static final Logger logger = LoggerFactory.getLogger(ConcurrentCompositeConfiguration.class); @@ -589,13 +612,30 @@ private Object getProperty(String key, boolean instrument) public void recordUsage(String key) { if (enableInstrumentation) { usedPropertiesRef.get().add(key); - if (enableStackTrace) { + boolean isTrackedProperty = stackTraceEnabledProperties.contains(key); + if (enableStackTrace || isTrackedProperty) { String trace = Arrays.toString(Thread.currentThread().getStackTrace()); - stackTraces.merge(trace, 1, (v1, v2) -> v1 + 1); + if (enableStackTrace) { + stackTraces.merge(trace, 1, (v1, v2) -> v1 + 1); + } + if (isTrackedProperty) { + stackTracesAndProperties.merge(trace, createSet(key), this::union); + } } } } + private Set union(Set s1, Set s2) { + s1.addAll(s2); + return s1; + } + + private Set createSet(String s) { + Set ret = new HashSet<>(); + ret.add(s); + return ret; + } + /** * Get all the keys contained by sub configurations. *