You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ch...@apache.org on 2013/11/13 12:17:05 UTC

svn commit: r1541471 - in /sling/trunk/bundles/commons/log: ./ src/main/java/ch/qos/logback/classic/spi/ src/test/java/org/apache/sling/commons/log/logback/integration/

Author: chetanm
Date: Wed Nov 13 11:17:05 2013
New Revision: 1541471

URL: http://svn.apache.org/r1541471
Log:
SLING-3049 - Make Logback Stacktrace Packaging data support OSGi aware

Adding OSGi aware PackagingDataCalculator

Also disabled animal-sniffer-maven-plugin as it is causing issue. See bug notes for details

Added:
    sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/
    sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java   (with props)
Modified:
    sling/trunk/bundles/commons/log/pom.xml
    sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITAppenderServices.java
    sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITConfigFragments.java

Modified: sling/trunk/bundles/commons/log/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/log/pom.xml?rev=1541471&r1=1541470&r2=1541471&view=diff
==============================================================================
--- sling/trunk/bundles/commons/log/pom.xml (original)
+++ sling/trunk/bundles/commons/log/pom.xml Wed Nov 13 11:17:05 2013
@@ -59,6 +59,36 @@
   </properties>
 
   <build>
+    <pluginManagement>
+      <plugins>
+        <!--
+        Unfortunately the <ignores> sections do not seem to
+        properly work, so the sniffer is disabled by default.
+
+        Note: 1.9 contains a call to a Java 7 specific method
+        (java.nio.CharBuffer.subSequence(II)Ljava/nio/CharBuffer;)
+        that is triggered when an undefined reference is found. This breaks error
+        reporting on Java 5/6.
+      -->
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>animal-sniffer-maven-plugin</artifactId>
+          <version>1.8</version>
+          <configuration>
+            <skip>true</skip>
+            <ignores>
+              <ignore>ch.qos.logback.classic.spi*</ignore>
+            </ignores>
+            <signature>
+              <groupId>org.codehaus.mojo.signature</groupId>
+              <artifactId>java1${sling.java.version}</artifactId>
+              <version>1.0</version>
+            </signature>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+
     <plugins>
       <plugin>
         <groupId>org.apache.felix</groupId>
@@ -209,6 +239,8 @@
     </plugins>
   </build>
 
+
+
   <reporting>
     <plugins>
       <plugin>
@@ -259,12 +291,14 @@
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
-      <version>4.0.0</version>
+      <version>4.2.0</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.compendium</artifactId>
-      <version>4.0.0</version>
+      <version>4.2.0</version>
+        <scope>provided</scope>
     </dependency>
 
     <!-- servlet API for the web console plugin -->

Added: sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java?rev=1541471&view=auto
==============================================================================
--- sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java (added)
+++ sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java Wed Nov 13 11:17:05 2013
@@ -0,0 +1,264 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2013, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ *   or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.classic.spi;
+
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.HashMap;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
+import sun.reflect.Reflection;
+// import java.security.AccessControlException; import java.security.AccessController;import java.security.PrivilegedAction;
+/**
+ * Given a classname locate associated PackageInfo (jar name, version name).
+ *
+ * @author James Strachan
+ * @Ceki G&uuml;lc&uuml;
+ */
+public class PackagingDataCalculator {
+
+  final static StackTraceElementProxy[] STEP_ARRAY_TEMPLATE = new StackTraceElementProxy[0];
+
+  HashMap<String, ClassPackagingData> cache = new HashMap<String, ClassPackagingData>();
+
+  private static boolean GET_CALLER_CLASS_METHOD_AVAILABLE = false; //private static boolean HAS_GET_CLASS_LOADER_PERMISSION = false;
+
+  static {
+    // if either the Reflection class or the getCallerClass method
+    // are unavailable, then we won't invoke Reflection.getCallerClass()
+    // This approach ensures that this class will *run* on JDK's lacking
+    // sun.reflect.Reflection class. However, this class will *not compile*
+    // on JDKs lacking sun.reflect.Reflection.
+    try {
+      Reflection.getCallerClass(2);
+      GET_CALLER_CLASS_METHOD_AVAILABLE = true;
+    } catch (NoClassDefFoundError e) {
+    } catch (NoSuchMethodError e) {
+    } catch (Throwable e) {
+      System.err.println("Unexpected exception");
+      e.printStackTrace();
+    }
+  }
+
+
+  public void calculate(IThrowableProxy tp) {
+    while (tp != null) {
+      populateFrames(tp.getStackTraceElementProxyArray());
+      IThrowableProxy[] suppressed = tp.getSuppressed();
+      if(suppressed != null) {
+        for(IThrowableProxy current:suppressed) {
+          populateFrames(current.getStackTraceElementProxyArray());
+        }
+      }
+      tp = tp.getCause();
+    }
+  }
+
+  void populateFrames(StackTraceElementProxy[] stepArray) {
+    // in the initial part of this method we populate package information for
+    // common stack frames
+    final Throwable t = new Throwable("local stack reference");
+    final StackTraceElement[] localteSTEArray = t.getStackTrace();
+    final int commonFrames = STEUtil.findNumberOfCommonFrames(localteSTEArray,
+            stepArray);
+    final int localFirstCommon = localteSTEArray.length - commonFrames;
+    final int stepFirstCommon = stepArray.length - commonFrames;
+
+    ClassLoader lastExactClassLoader = null;
+    ClassLoader firsExactClassLoader = null;
+
+    int missfireCount = 0;
+    for (int i = 0; i < commonFrames; i++) {
+      Class callerClass = null;
+      if (GET_CALLER_CLASS_METHOD_AVAILABLE) {
+        callerClass = Reflection.getCallerClass(localFirstCommon + i
+                - missfireCount + 1);
+      }
+      StackTraceElementProxy step = stepArray[stepFirstCommon + i];
+      String stepClassname = step.ste.getClassName();
+
+      if (callerClass != null && stepClassname.equals(callerClass.getName())) {
+        // see also LBCLASSIC-263
+        lastExactClassLoader = callerClass.getClassLoader();
+        if (firsExactClassLoader == null) {
+          firsExactClassLoader = lastExactClassLoader;
+        }
+        ClassPackagingData pi = calculateByExactType(callerClass);
+        step.setClassPackagingData(pi);
+      } else {
+        missfireCount++;
+        ClassPackagingData pi = computeBySTEP(step, lastExactClassLoader);
+        step.setClassPackagingData(pi);
+      }
+    }
+    populateUncommonFrames(commonFrames, stepArray, firsExactClassLoader);
+  }
+
+  void populateUncommonFrames(int commonFrames,
+                              StackTraceElementProxy[] stepArray, ClassLoader firstExactClassLoader) {
+    int uncommonFrames = stepArray.length - commonFrames;
+    for (int i = 0; i < uncommonFrames; i++) {
+      StackTraceElementProxy step = stepArray[i];
+      ClassPackagingData pi = computeBySTEP(step, firstExactClassLoader);
+      step.setClassPackagingData(pi);
+    }
+  }
+
+  private ClassPackagingData calculateByExactType(Class type) {
+    String className = type.getName();
+    ClassPackagingData cpd = cache.get(className);
+    if (cpd != null) {
+      return cpd;
+    }
+    String version = getImplementationVersion(type);
+    String codeLocation = getCodeLocation(type);
+    cpd = new ClassPackagingData(codeLocation, version);
+    cache.put(className, cpd);
+    return cpd;
+  }
+
+  private ClassPackagingData computeBySTEP(StackTraceElementProxy step,
+                                           ClassLoader lastExactClassLoader) {
+    String className = step.ste.getClassName();
+    ClassPackagingData cpd = cache.get(className);
+    if (cpd != null) {
+      return cpd;
+    }
+    Class type = bestEffortLoadClass(lastExactClassLoader, className);
+    String version = getImplementationVersion(type);
+    String codeLocation = getCodeLocation(type);
+    cpd = new ClassPackagingData(codeLocation, version, false);
+    cache.put(className, cpd);
+    return cpd;
+  }
+
+  String getImplementationVersion(Class type) {
+    if (type == null) {
+      return "na";
+    }
+
+    Bundle b = FrameworkUtil.getBundle(type);
+    if(b != null){
+      final Version version = b.getVersion();
+      return version == org.osgi.framework.Version.emptyVersion ? "na" : version.toString();
+    }
+
+    Package aPackage = type.getPackage();
+    if (aPackage != null) {
+      String v = aPackage.getImplementationVersion();
+      if (v == null) {
+        return "na";
+      } else {
+        return v;
+      }
+    }
+    return "na";
+
+  }
+
+  String getCodeLocation(Class type) {
+    try {
+      if (type != null) {
+
+        Bundle b = FrameworkUtil.getBundle(type);
+        if(b != null){
+            return b.getSymbolicName();
+        }
+        // file:/C:/java/maven-2.0.8/repo/com/icegreen/greenmail/1.3/greenmail-1.3.jar
+        CodeSource codeSource = type.getProtectionDomain().getCodeSource();
+        if (codeSource != null) {
+          URL resource = codeSource.getLocation();
+          if (resource != null) {
+            String locationStr = resource.toString();
+            // now lets remove all but the file name
+            String result = getCodeLocation(locationStr, '/');
+            if (result != null) {
+              return result;
+            }
+            return getCodeLocation(locationStr, '\\');
+          }
+        }
+      }
+    } catch (Exception e) {
+      // ignore
+    }
+    return "na";
+  }
+
+  private String getCodeLocation(String locationStr, char separator) {
+    int idx = locationStr.lastIndexOf(separator);
+    if (isFolder(idx, locationStr)) {
+      idx = locationStr.lastIndexOf(separator, idx - 1);
+      return locationStr.substring(idx + 1);
+    } else if (idx > 0) {
+      return locationStr.substring(idx + 1);
+    }
+    return null;
+  }
+
+  private boolean isFolder(int idx, String text) {
+    return (idx != -1 && idx + 1 == text.length());
+  }
+
+  private Class loadClass(ClassLoader cl, String className) {
+    if (cl == null) {
+      return null;
+    }
+    try {
+      return cl.loadClass(className);
+    } catch (ClassNotFoundException e1) {
+      return null;
+    } catch (NoClassDefFoundError e1) {
+      return null;
+    } catch (Exception e) {
+      e.printStackTrace(); // this is unexpected
+      return null;
+    }
+
+  }
+
+  /**
+   * @param lastGuaranteedClassLoader may be null
+   * @param className
+   * @return
+   */
+  private Class bestEffortLoadClass(ClassLoader lastGuaranteedClassLoader,
+                                    String className) {
+    Class result = loadClass(lastGuaranteedClassLoader, className);
+    if (result != null) {
+      return result;
+    }
+    ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+    if (tccl != lastGuaranteedClassLoader) {
+      result = loadClass(tccl, className);
+    }
+    if (result != null) {
+      return result;
+    }
+
+    try {
+      return Class.forName(className);
+    } catch (ClassNotFoundException e1) {
+      return null;
+    } catch (NoClassDefFoundError e1) {
+      return null;
+    } catch (Exception e) {
+      e.printStackTrace(); // this is unexpected
+      return null;
+    }
+  }
+
+}

Propchange: sling/trunk/bundles/commons/log/src/main/java/ch/qos/logback/classic/spi/PackagingDataCalculator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITAppenderServices.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITAppenderServices.java?rev=1541471&r1=1541470&r2=1541471&view=diff
==============================================================================
--- sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITAppenderServices.java (original)
+++ sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITAppenderServices.java Wed Nov 13 11:17:05 2013
@@ -28,7 +28,9 @@ import javax.inject.Inject;
 
 import ch.qos.logback.classic.Level;
 import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ClassPackagingData;
 import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.classic.spi.StackTraceElementProxy;
 import ch.qos.logback.core.Appender;
 import ch.qos.logback.core.AppenderBase;
 import org.junit.After;
@@ -44,7 +46,9 @@ import org.osgi.service.cm.Configuration
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.slf4j.LoggerFactory;
 
+import static org.hamcrest.CoreMatchers.startsWith;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.ops4j.pax.exam.CoreOptions.composite;
 import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
@@ -119,6 +123,26 @@ public class ITAppenderServices extends 
         assertEquals(2, ta.events.size());
     }
 
+    @Test
+    public void testPackagingData() throws Exception {
+        TestAppender ta = registerAppender("foo.bar.packaging");
+        delay();
+
+        Logger foo = (Logger)LoggerFactory.getLogger("foo.bar.packaging");
+        foo.warn("This is a test", new Exception());
+
+        // One event should be logged.
+        assertEquals(1, ta.events.size());
+        ILoggingEvent e = ta.events.get(0);
+        StackTraceElementProxy[] stProxies = e.getThrowableProxy().getStackTraceElementProxyArray();
+
+        ClassPackagingData cpd1 = stProxies[0].getClassPackagingData();
+
+        //For pax exam the bundle is created with name starting with PAXEXAM-PROBE
+        //As codeLocation is OSGi env is bundle symbolic name we check for that
+        assertThat(cpd1.getCodeLocation(), startsWith("PAXEXAM-PROBE"));
+    }
+
     @After
     public void unregisterAppender(){
         sr.unregister();

Modified: sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITConfigFragments.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITConfigFragments.java?rev=1541471&r1=1541470&r2=1541471&view=diff
==============================================================================
--- sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITConfigFragments.java (original)
+++ sling/trunk/bundles/commons/log/src/test/java/org/apache/sling/commons/log/logback/integration/ITConfigFragments.java Wed Nov 13 11:17:05 2013
@@ -19,12 +19,12 @@
 
 package org.apache.sling.commons.log.logback.integration;
 
+import java.util.Dictionary;
 import java.util.Properties;
 
 import javax.inject.Inject;
 
 import org.apache.sling.commons.log.logback.ConfigProvider;
-import org.apache.sling.commons.log.logback.integration.LogTestBase;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.Option;
@@ -109,7 +109,7 @@ public class ITConfigFragments extends L
 
         fcp.fileName = "test-reset-config-2.xml";
 
-        eventAdmin.sendEvent(new Event(RESET_EVENT_TOPIC, new Properties()));
+        eventAdmin.sendEvent(new Event(RESET_EVENT_TOPIC, (Dictionary)null));
 
         delay();