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.pattern;
15  
16  import java.util.ArrayList;
17  import java.util.List;
18  import java.util.Map;
19  
20  import ch.qos.logback.classic.spi.ILoggingEvent;
21  import ch.qos.logback.classic.spi.IThrowableProxy;
22  import ch.qos.logback.classic.spi.StackTraceElementProxy;
23  import ch.qos.logback.classic.spi.ThrowableProxyUtil;
24  import ch.qos.logback.core.Context;
25  import ch.qos.logback.core.CoreConstants;
26  import ch.qos.logback.core.boolex.EvaluationException;
27  import ch.qos.logback.core.boolex.EventEvaluator;
28  import ch.qos.logback.core.status.ErrorStatus;
29  
30  /**
31   * Add a stack trace in case the event contains a Throwable.
32   *
33   * @author Ceki Gülcü
34   */
35  public class ThrowableProxyConverter extends ThrowableHandlingConverter {
36  
37    int lengthOption;
38    List<EventEvaluator<ILoggingEvent>> evaluatorList = null;
39  
40    int errorCount = 0;
41  
42    @SuppressWarnings("unchecked")
43    public void start() {
44  
45      String lengthStr = getFirstOption();
46  
47      if (lengthStr == null) {
48        lengthOption = Integer.MAX_VALUE;
49      } else {
50        lengthStr = lengthStr.toLowerCase();
51        if ("full".equals(lengthStr)) {
52          lengthOption = Integer.MAX_VALUE;
53        } else if ("short".equals(lengthStr)) {
54          lengthOption = 2;
55        } else {
56          try {
57            // we add one because, printing starts at offset 1
58            lengthOption = Integer.parseInt(lengthStr) + 1;
59          } catch (NumberFormatException nfe) {
60            addError("Could not parser [" + lengthStr + " as an integer");
61            lengthOption = Integer.MAX_VALUE;
62          }
63        }
64      }
65  
66      final List optionList = getOptionList();
67  
68      if (optionList != null && optionList.size() > 1) {
69        final int optionListSize = optionList.size();
70        for (int i = 1; i < optionListSize; i++) {
71          String evaluatorStr = (String) optionList.get(i);
72          Context context = getContext();
73          Map evaluatorMap = (Map) context.getObject(CoreConstants.EVALUATOR_MAP);
74          EventEvaluator<ILoggingEvent> ee = (EventEvaluator<ILoggingEvent>) evaluatorMap
75                  .get(evaluatorStr);
76          addEvaluator(ee);
77        }
78      }
79      super.start();
80    }
81  
82    private void addEvaluator(EventEvaluator<ILoggingEvent> ee) {
83      if (evaluatorList == null) {
84        evaluatorList = new ArrayList<EventEvaluator<ILoggingEvent>>();
85      }
86      evaluatorList.add(ee);
87    }
88  
89    public void stop() {
90      evaluatorList = null;
91      super.stop();
92    }
93  
94    protected void extraData(StringBuilder builder, StackTraceElementProxy step) {
95      // nop
96    }
97  
98    public String convert(ILoggingEvent event) {
99  
100     IThrowableProxy tp = event.getThrowableProxy();
101     if (tp == null) {
102       return CoreConstants.EMPTY_STRING;
103     }
104 
105     // an evaluator match will cause stack printing to be skipped
106     if (evaluatorList != null) {
107       boolean printStack = true;
108       for (int i = 0; i < evaluatorList.size(); i++) {
109         EventEvaluator<ILoggingEvent> ee = evaluatorList.get(i);
110         try {
111           if (ee.evaluate(event)) {
112             printStack = false;
113             break;
114           }
115         } catch (EvaluationException eex) {
116           errorCount++;
117           if (errorCount < CoreConstants.MAX_ERROR_COUNT) {
118             addError("Exception thrown for evaluator named [" + ee.getName()
119                     + "]", eex);
120           } else if (errorCount == CoreConstants.MAX_ERROR_COUNT) {
121             ErrorStatus errorStatus = new ErrorStatus(
122                     "Exception thrown for evaluator named [" + ee.getName() + "].",
123                     this, eex);
124             errorStatus.add(new ErrorStatus(
125                     "This was the last warning about this evaluator's errors."
126                             + "We don't want the StatusManager to get flooded.", this));
127             addStatus(errorStatus);
128           }
129         }
130       }
131 
132       if (!printStack) {
133         return CoreConstants.EMPTY_STRING;
134       }
135     }
136 
137     return throwableProxyToString(tp);
138   }
139 
140   protected String throwableProxyToString(IThrowableProxy tp) {
141     StringBuilder buf = new StringBuilder(32);
142     IThrowableProxy currentThrowable = tp;
143     while (currentThrowable != null) {
144       subjoinThrowableProxy(buf, currentThrowable);
145       currentThrowable = currentThrowable.getCause();
146     }
147     return buf.toString();
148   }
149 
150   void subjoinThrowableProxy(StringBuilder buf, IThrowableProxy tp) {
151     ThrowableProxyUtil.subjoinFirstLine(buf, tp);
152     buf.append(CoreConstants.LINE_SEPARATOR);
153     StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
154     int commonFrames = tp.getCommonFrames();
155 
156     boolean unrestrictedPrinting = lengthOption > stepArray.length;
157 
158 
159     int maxIndex = (unrestrictedPrinting) ? stepArray.length : lengthOption;
160     if (commonFrames > 0 && unrestrictedPrinting) {
161       maxIndex -= commonFrames;
162     }
163 
164     for (int i = 0; i < maxIndex; i++) {
165       String string = stepArray[i].toString();
166       buf.append(CoreConstants.TAB);
167       buf.append(string);
168       extraData(buf, stepArray[i]); // allow other data to be added
169       buf.append(CoreConstants.LINE_SEPARATOR);
170     }
171 
172     if (commonFrames > 0 && unrestrictedPrinting) {
173       buf.append("\t... ").append(tp.getCommonFrames()).append(
174               " common frames omitted").append(CoreConstants.LINE_SEPARATOR);
175     }
176   }
177 }