View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.spi;
15  
16  import ch.qos.logback.core.CoreConstants;
17  
18  /**
19   * This class computes caller data returning the result in the form
20   * of a StackTraceElement array.
21   * 
22   * @author Ceki Gülcü
23   */
24  public class CallerData {
25  
26  
27    /**
28     * When caller information is not available this constant is used for file
29     * name, method name, etc.
30     */
31    public static final String NA = "?";
32  
33    // All logger call's in log4j-over-slf4j use the Category class
34    private static final String LOG4J_CATEGORY = "org.apache.log4j.Category";
35  
36    /**
37     * When caller information is not available this constant is used for the line
38     * number.
39     */
40    public static final int LINE_NA = -1;
41  
42    public static String CALLER_DATA_NA = "?#?:?" + CoreConstants.LINE_SEPARATOR;
43  
44    /**
45     * This value is returned in case no caller data could be extracted.
46     */
47    public static StackTraceElement[] EMPTY_CALLER_DATA_ARRAY = new StackTraceElement[0];
48  
49  
50    /**
51     * Extract caller data information as an array based on a Throwable passed as
52     * parameter
53     */
54    public static StackTraceElement[] extract(Throwable t,
55        String fqnOfInvokingClass, final int maxDepth) {
56      if (t == null) {
57        return null;
58      }
59  
60      StackTraceElement[] steArray = t.getStackTrace();
61      StackTraceElement[] callerDataArray;
62  
63      int found = LINE_NA;
64      for (int i = 0; i < steArray.length; i++) {
65        if (isDirectlyInvokingClass(steArray[i].getClassName(),
66            fqnOfInvokingClass)) {
67          // the caller is assumed to be the next stack frame, hence the +1.
68          found = i + 1;
69        } else {
70          if (found != LINE_NA) {
71            break;
72          }
73        }
74      }
75  
76      // we failed to extract caller data
77      if (found == LINE_NA) {
78        return EMPTY_CALLER_DATA_ARRAY;
79      }
80  
81      int availableDepth = steArray.length - found;
82      int desiredDepth = maxDepth < (availableDepth) ? maxDepth : availableDepth;
83  
84      callerDataArray = new StackTraceElement[desiredDepth];
85      for (int i = 0; i < desiredDepth; i++) {
86        callerDataArray[i] = steArray[found + i];
87      }
88      return callerDataArray;
89    }
90  
91    public static boolean isDirectlyInvokingClass(String currentClass,
92        String fqnOfInvokingClass) {
93      // the check for org.apachje.log4j.Category class is intended to support
94      // log4j-over-slf4j
95      // it solves http://bugzilla.slf4j.org/show_bug.cgi?id=66
96      if (currentClass.equals(fqnOfInvokingClass)
97          || currentClass.equals(LOG4J_CATEGORY)) {
98        return true;
99      } else {
100       return false;
101     }
102   }
103 
104 }