killbill-aplcache

log: updates to ThreadNameBasedDiscriminator Make it smarter

8/8/2014 11:29:44 AM

Details

diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/log/ThreadNameBasedDiscriminator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/log/ThreadNameBasedDiscriminator.java
index 50ddf2f..41b9e48 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/log/ThreadNameBasedDiscriminator.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/log/ThreadNameBasedDiscriminator.java
@@ -23,12 +23,22 @@ import ch.qos.logback.core.sift.Discriminator;
 public class ThreadNameBasedDiscriminator implements Discriminator<ILoggingEvent> {
 
     private static final String KEY = "threadName";
+    private static final String ORG_KILLBILL_DOT = "org.killbill.";
+    private static final String BILLING_DOT = "billing.";
+    private static final String COMMONS_DOT = "commons.";
+
+    private final KillbillSecurityManager killbillSecurityManager = new KillbillSecurityManager();
 
     private boolean started;
 
     @Override
     public String getDiscriminatingValue(final ILoggingEvent iLoggingEvent) {
-        return Thread.currentThread().getName();
+        final String element = getKillbillCaller();
+        if (element != null) {
+            return element;
+        } else {
+            return Thread.currentThread().getName();
+        }
     }
 
     @Override
@@ -47,4 +57,134 @@ public class ThreadNameBasedDiscriminator implements Discriminator<ILoggingEvent
     public boolean isStarted() {
         return started;
     }
+
+    private String getKillbillCaller() {
+        final Class[] stackTrace = killbillSecurityManager.getClassContext();
+        if (stackTrace == null || stackTrace.length <= 3) {
+            return null;
+        }
+
+        // Skip first ones (i.e. skip this class)
+        for (int i = 4; i < stackTrace.length; i++) {
+            final Class aStackTrace = stackTrace[i];
+            final String className = aStackTrace.getName();
+            final char[] classNameChars = className.toCharArray();
+
+            // Try to be faster than using patterns or String methods
+            if (classNameChars.length > 13 &&
+                classNameChars[0] == 'o' &&
+                classNameChars[1] == 'r' &&
+                classNameChars[2] == 'g' &&
+                classNameChars[3] == '.' &&
+                classNameChars[4] == 'k' &&
+                classNameChars[5] == 'i' &&
+                classNameChars[6] == 'l' &&
+                classNameChars[7] == 'l' &&
+                classNameChars[8] == 'b' &&
+                classNameChars[9] == 'i' &&
+                classNameChars[10] == 'l' &&
+                classNameChars[11] == 'l' &&
+                classNameChars[12] == '.') {
+                String markerName = ORG_KILLBILL_DOT;
+
+                // Extract the killbill module for Kill Bill proper calls, otherwise get the top-level package
+                int startPosition = 13;
+                if (classNameChars.length > 21 &&
+                    classNameChars[13] == 'b' &&
+                    classNameChars[14] == 'i' &&
+                    classNameChars[15] == 'l' &&
+                    classNameChars[16] == 'l' &&
+                    classNameChars[17] == 'i' &&
+                    classNameChars[18] == 'n' &&
+                    classNameChars[19] == 'g' &&
+                    classNameChars[20] == '.') {
+                    startPosition = 21;
+                    markerName += BILLING_DOT;
+
+                    // Extract the submodule in util
+                    if (classNameChars.length > 26 &&
+                        classNameChars[21] == 'u' &&
+                        classNameChars[22] == 't' &&
+                        classNameChars[23] == 'i' &&
+                        classNameChars[24] == 'l' &&
+                        classNameChars[25] == '.') {
+                        startPosition = 26;
+
+                        // Skip JDBI wrappers
+                        if (classNameChars.length > 33 &&
+                            classNameChars[26] == 'e' &&
+                            classNameChars[27] == 'n' &&
+                            classNameChars[28] == 't' &&
+                            classNameChars[29] == 'i' &&
+                            classNameChars[30] == 't' &&
+                            classNameChars[31] == 'y' &&
+                            classNameChars[32] == '.') {
+                            continue;
+                        } else if (classNameChars.length > 30 &&
+                                   classNameChars[26] == 'd' &&
+                                   classNameChars[27] == 'a' &&
+                                   classNameChars[28] == 'o' &&
+                                   classNameChars[29] == '.') {
+                            continue;
+                        }
+                    }
+                    // Extract the submodule in commons
+                } else if (classNameChars.length > 21 &&
+                           classNameChars[13] == 'c' &&
+                           classNameChars[14] == 'o' &&
+                           classNameChars[15] == 'm' &&
+                           classNameChars[16] == 'm' &&
+                           classNameChars[17] == 'o' &&
+                           classNameChars[18] == 'n' &&
+                           classNameChars[19] == 's' &&
+                           classNameChars[20] == '.') {
+                    startPosition = 21;
+                    markerName += COMMONS_DOT;
+
+                    // Skip profiling
+                    if (classNameChars.length > 31 &&
+                        classNameChars[21] == 'p' &&
+                        classNameChars[22] == 'r' &&
+                        classNameChars[23] == 'o' &&
+                        classNameChars[24] == 'f' &&
+                        classNameChars[25] == 'i' &&
+                        classNameChars[26] == 'l' &&
+                        classNameChars[27] == 'i' &&
+                        classNameChars[28] == 'n' &&
+                        classNameChars[29] == 'g' &&
+                        classNameChars[30] == '.') {
+                        continue;
+                        // Skip JDBI utilities
+                    } else if (classNameChars.length > 26 &&
+                               classNameChars[21] == 'j' &&
+                               classNameChars[22] == 'd' &&
+                               classNameChars[23] == 'b' &&
+                               classNameChars[24] == 'i' &&
+                               classNameChars[25] == '.') {
+                        continue;
+                    }
+                }
+
+                for (int j = startPosition; j < classNameChars.length; j++) {
+                    final char kar = classNameChars[j];
+                    if (kar == '.') {
+                        break;
+                    }
+                    markerName += kar;
+                }
+                return markerName;
+            }
+        }
+
+        return null;
+    }
+
+    // Simple utility class used to provide public access to the protected getClassContext() method of SecurityManager.
+    // Faster than new Throwable().getStackTrace() and Thread.currentThread().getStackTrace()
+    private static final class KillbillSecurityManager extends SecurityManager {
+
+        public Class[] getClassContext() {
+            return super.getClassContext();
+        }
+    }
 }