View Javadoc

1   /**
2    * Logback: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 2000-2008, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  package ch.qos.logback.classic.spi;
11  
12  import ch.qos.logback.core.CoreConstants;
13  
14  /**
15   * The internal representation of caller location information.
16   * 
17   * @author Ceki Gülcü
18   */
19  public class CallerData implements java.io.Serializable {
20  
21    private static final long serialVersionUID = 2473626903716082403L;
22  
23    /**
24     * When caller information is not available this constant is used for file
25     * name, method name, etc.
26     */
27    public static final String NA = "?";
28  
29    // All logger call's in log4j-over-slf4j use the Category class
30    private static final String LOG4J_CATEGORY = "org.apache.log4j.Category";
31    
32    /**
33     * When caller information is not available this constant is used for the line
34     * number.
35     */
36    public static final int LINE_NA = -1;
37  
38    
39    public static String CALLER_DATA_NA = "?#?:?"+CoreConstants.LINE_SEPARATOR;
40  
41    /**
42     * This value is returned in case no caller data could be extracted.
43     */
44    public static CallerData[] EMPTY_CALLER_DATA_ARRAY = new CallerData[0];
45    
46    /**
47     * Caller's line number.
48     */
49    int lineNumber;
50  
51    /**
52     * Caller's file name.
53     */
54    String fileName;
55  
56    /**
57     * Caller's fully qualified class name.
58     */
59    String className;
60  
61    /**
62     * Caller's method name.
63     */
64    String methodName;
65  
66    boolean nativeMethod = false;
67    
68    public CallerData(String fileName, String className, String methodName,
69        int lineNumber) {
70      this.fileName = fileName;
71      this.className = className;
72      this.methodName = methodName;
73      this.lineNumber = lineNumber;
74    }
75  
76    public CallerData(StackTraceElement ste) {
77      className = ste.getClassName();
78      fileName = ste.getFileName();
79      methodName = ste.getMethodName();
80      lineNumber = ste.getLineNumber();
81      nativeMethod = ste.isNativeMethod();
82    }
83  
84    /**
85     * Extract caller data information as an array based on a Throwable passed as parameter
86     */
87    public static CallerData[] extract(Throwable t, String fqnOfInvokingClass) {
88      if (t == null) {
89        return null;
90      }
91  
92      StackTraceElement[] steArray = t.getStackTrace();
93      CallerData[] callerDataArray;
94      
95      int found = LINE_NA;
96      for (int i = 0; i < steArray.length; i++) {
97        if(isDirectlyInvokingClass(steArray[i].getClassName(), fqnOfInvokingClass)) {
98          // the caller is assumed to be the next stack frame, hence the +1.
99          found = i + 1;
100       } else {
101         if(found != LINE_NA) {
102           break;
103         }
104       }
105     }
106 
107     // we failed to extract caller data
108     if(found == LINE_NA) {
109       return EMPTY_CALLER_DATA_ARRAY;
110     }
111     
112     callerDataArray = new CallerData[steArray.length - found];
113     for (int i = found; i < steArray.length; i++) {
114       callerDataArray[i-found] = new CallerData(steArray[i]);
115     }
116     return callerDataArray;
117   }
118   
119   public static boolean isDirectlyInvokingClass(String currentClass, String fqnOfInvokingClass) {
120     // the check for org.apachje.log4j.Category class is intended to support log4j-over-slf4j
121     // it solves http://bugzilla.slf4j.org/show_bug.cgi?id=66
122     if(currentClass.equals(fqnOfInvokingClass) || currentClass.equals(LOG4J_CATEGORY)) {
123       return true;
124     } else {
125       return false;
126     }
127   }
128   
129   public boolean equals(Object o) {
130     // LogLog.info("equals called");
131     if (this == o) {
132       return true;
133     }
134 
135     if (!(o instanceof CallerData)) {
136       // LogLog.info("inequality point 1");
137       return false;
138     }
139 
140     CallerData r = (CallerData) o;
141 
142     if (!getClassName().equals(r.getClassName())) {
143       // LogLog.info("inequality point 2");
144       return false;
145     }
146 
147     if (!getFileName().equals(r.getFileName())) {
148       // LogLog.info("inequality point 3");
149       return false;
150     }
151 
152     if (!getMethodName().equals(r.getMethodName())) {
153       // LogLog.info("inequality point 4");
154       return false;
155     }
156 
157     if (!(lineNumber == r.lineNumber)) {
158       // LogLog.info("inequality point 5");
159       return false;
160     }
161 
162     return true;
163   }
164 
165   /**
166    * Return the fully qualified class name of the caller making the logging
167    * request.
168    */
169   public String getClassName() {
170     return className;
171   }
172 
173   /**
174    * Return the file name of the caller.
175    * 
176    * <p>
177    * This information is not always available.
178    */
179   public String getFileName() {
180     return fileName;
181   }
182 
183   /**
184    * Returns the line number of the caller.
185    * 
186    * <p>
187    * This information is not always available.
188    */
189   public int getLineNumber() {
190     return lineNumber;
191   }
192 
193   /**
194    * Returns the method name of the caller.
195    */
196   public String getMethodName() {
197     return methodName;
198   }
199 
200   public String toString() {
201     StringBuffer buf = new StringBuffer();
202     buf.append(getClassName());
203     buf.append('.');
204     buf.append(getMethodName());
205     buf.append('(');
206     if (isNativeMethod()) {
207       buf.append("Native Method");
208     } else if (getFileName() == null) {
209       buf.append("Unknown Source");
210     } else {
211       buf.append(getFileName());
212       buf.append(':');
213       buf.append(getLineNumber());
214     }
215     buf.append(')');
216     return buf.toString();
217   }
218 
219   public boolean isNativeMethod() {
220     return nativeMethod;
221   }
222 }