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 }