From 1310bc258a1c3144e46744c85822403966489955 Mon Sep 17 00:00:00 2001
From: Havoc Pennington <hp@pobox.com>
Date: Tue, 28 Feb 2012 13:02:34 -0500
Subject: [PATCH] Add -Dconfig.trace=loads feature to log where config is
 loaded from to stderr

---
 .../com/typesafe/config/impl/ConfigImpl.java  | 47 +++++++++++++++++++
 .../com/typesafe/config/impl/Parseable.java   | 24 ++++++++++
 2 files changed, 71 insertions(+)

diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
index 73ddfdce..be5dd019 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -413,4 +413,51 @@ public class ConfigImpl {
             throw ConfigImplUtil.extractInitializerError(e);
         }
     }
+
+    private static class DebugHolder {
+        private static String LOADS = "loads";
+
+        private static Map<String, Boolean> loadDiagnostics() {
+            Map<String, Boolean> result = new HashMap<String, Boolean>();
+            result.put(LOADS, false);
+
+            // People do -Dconfig.trace=foo,bar to enable tracing of different things
+            String s = System.getProperty("config.trace");
+            if (s == null) {
+                return result;
+            } else {
+                String[] keys = s.split(",");
+                for (String k : keys) {
+                    if (k.equals(LOADS)) {
+                        result.put(LOADS, true);
+                    } else {
+                        System.err.println("config.trace property contains unknown trace topic '"
+                                + k + "'");
+                    }
+                }
+                return result;
+            }
+        }
+
+        private static final Map<String, Boolean> diagnostics = loadDiagnostics();
+
+        private static final boolean traceLoadsEnabled = diagnostics.get(LOADS);
+
+        static boolean traceLoadsEnabled() {
+            return traceLoadsEnabled;
+        }
+    }
+
+    /** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
+    public static boolean traceLoadsEnabled() {
+        try {
+            return DebugHolder.traceLoadsEnabled();
+        } catch (ExceptionInInitializerError e) {
+            throw ConfigImplUtil.extractInitializerError(e);
+        }
+    }
+
+    public static void trace(String message) {
+        System.err.println(message);
+    }
 }
diff --git a/config/src/main/java/com/typesafe/config/impl/Parseable.java b/config/src/main/java/com/typesafe/config/impl/Parseable.java
index 49386031..8295fdfa 100644
--- a/config/src/main/java/com/typesafe/config/impl/Parseable.java
+++ b/config/src/main/java/com/typesafe/config/impl/Parseable.java
@@ -87,6 +87,12 @@ public abstract class Parseable implements ConfigParseable {
     // to support the "allow missing" feature.
     protected abstract Reader reader() throws IOException;
 
+    protected static void trace(String message) {
+        if (ConfigImpl.traceLoadsEnabled()) {
+            ConfigImpl.trace(message);
+        }
+    }
+
     ConfigSyntax guessSyntax() {
         return null;
     }
@@ -300,6 +306,8 @@ public abstract class Parseable implements ConfigParseable {
 
         @Override
         protected Reader reader() {
+            if (ConfigImpl.traceLoadsEnabled())
+                trace("Loading config from reader " + reader);
             return reader;
         }
 
@@ -314,6 +322,7 @@ public abstract class Parseable implements ConfigParseable {
      * is complete.
      */
     public static Parseable newReader(Reader reader, ConfigParseOptions options) {
+
         return new ParseableReader(doNotClose(reader), options);
     }
 
@@ -327,6 +336,8 @@ public abstract class Parseable implements ConfigParseable {
 
         @Override
         protected Reader reader() {
+            if (ConfigImpl.traceLoadsEnabled())
+                trace("Loading config from a String " + input);
             return new StringReader(input);
         }
 
@@ -350,6 +361,8 @@ public abstract class Parseable implements ConfigParseable {
 
         @Override
         protected Reader reader() throws IOException {
+            if (ConfigImpl.traceLoadsEnabled())
+                trace("Loading config from a URL: " + input.toExternalForm());
             InputStream stream = input.openStream();
             return readerFromStream(stream);
         }
@@ -400,6 +413,8 @@ public abstract class Parseable implements ConfigParseable {
 
         @Override
         protected Reader reader() throws IOException {
+            if (ConfigImpl.traceLoadsEnabled())
+                trace("Loading config from a file: " + input);
             InputStream stream = new FileInputStream(input);
             return readerFromStream(stream);
         }
@@ -472,12 +487,19 @@ public abstract class Parseable implements ConfigParseable {
                 ConfigParseOptions finalOptions) throws IOException {
             Enumeration<URL> e = loader.getResources(resource);
             if (!e.hasMoreElements()) {
+                if (ConfigImpl.traceLoadsEnabled())
+                    trace("Loading config from class loader " + loader
+                            + " but there were no resources called " + resource);
                 throw new IOException("resource not found on classpath: " + resource);
             }
             AbstractConfigObject merged = SimpleConfigObject.empty(origin);
             while (e.hasMoreElements()) {
                 URL url = e.nextElement();
 
+                if (ConfigImpl.traceLoadsEnabled())
+                    trace("Loading config from URL " + url.toExternalForm() + " from class loader "
+                            + loader);
+
                 ConfigOrigin elementOrigin = ((SimpleConfigOrigin) origin).addURL(url);
 
                 AbstractConfigValue v;
@@ -611,6 +633,8 @@ public abstract class Parseable implements ConfigParseable {
         @Override
         protected AbstractConfigObject rawParseValue(ConfigOrigin origin,
                 ConfigParseOptions finalOptions) {
+            if (ConfigImpl.traceLoadsEnabled())
+                trace("Loading config from properties " + props);
             return PropertiesParser.fromProperties(origin, props);
         }