View Javadoc

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