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.CallerData;
21  import ch.qos.logback.classic.spi.ILoggingEvent;
22  import ch.qos.logback.core.Context;
23  import ch.qos.logback.core.CoreConstants;
24  import ch.qos.logback.core.boolex.EvaluationException;
25  import ch.qos.logback.core.boolex.EventEvaluator;
26  import ch.qos.logback.core.status.ErrorStatus;
27  
28  /**
29   * This converter outputs caller data depending on depth and marker data.
30   * 
31   * @author Ceki Gulcu
32   */
33  public class CallerDataConverter extends ClassicConverter {
34  
35    int depth = 5;
36    List<EventEvaluator<ILoggingEvent>> evaluatorList = null;
37  
38    final int MAX_ERROR_COUNT = 4;
39    int errorCount = 0;
40  
41    @SuppressWarnings("unchecked")
42    public void start() {
43      String depthStr = getFirstOption();
44      if (depthStr == null) {
45        return;
46      }
47  
48      try {
49        depth = Integer.parseInt(depthStr);
50      } catch (NumberFormatException nfe) {
51        addError("Failed to parse depth option [" + depthStr + "]", nfe);
52      }
53  
54      final List optionList = getOptionList();
55  
56      if (optionList != null && optionList.size() > 1) {
57        final int optionListSize = optionList.size();
58        for (int i = 1; i < optionListSize; i++) {
59          String evaluatorStr = (String) optionList.get(i);
60          Context context = getContext();
61          if (context != null) {
62            Map evaluatorMap = (Map) context
63                .getObject(CoreConstants.EVALUATOR_MAP);
64            EventEvaluator<ILoggingEvent> ee = (EventEvaluator<ILoggingEvent>) evaluatorMap
65                .get(evaluatorStr);
66            if (ee != null) {
67              addEvaluator(ee);
68            }
69          }
70        }
71      }
72    }
73  
74    private void addEvaluator(EventEvaluator<ILoggingEvent> ee) {
75      if (evaluatorList == null) {
76        evaluatorList = new ArrayList<EventEvaluator<ILoggingEvent>>();
77      }
78      evaluatorList.add(ee);
79    }
80  
81    public String convert(ILoggingEvent le) {
82      StringBuilder buf = new StringBuilder();
83  
84      if (evaluatorList != null) {
85        boolean printCallerData = false;
86        for (int i = 0; i < evaluatorList.size(); i++) {
87          EventEvaluator<ILoggingEvent> ee = evaluatorList.get(i);
88          try {
89            if (ee.evaluate(le)) {
90              printCallerData = true;
91              break;
92            }
93          } catch (EvaluationException eex) {
94            errorCount++;
95            if (errorCount < MAX_ERROR_COUNT) {
96              addError("Exception thrown for evaluator named [" + ee.getName()
97                  + "]", eex);
98            } else if (errorCount == MAX_ERROR_COUNT) {
99              ErrorStatus errorStatus = new ErrorStatus(
100                 "Exception thrown for evaluator named [" + ee.getName() + "].",
101                 this, eex);
102             errorStatus.add(new ErrorStatus(
103                 "This was the last warning about this evaluator's errors."
104                     + "We don't want the StatusManager to get flooded.", this));
105             addStatus(errorStatus);
106           }
107 
108         }
109       }
110 
111       if (!printCallerData) {
112         return CoreConstants.EMPTY_STRING;
113       }
114     }
115 
116     StackTraceElement[] cda = le.getCallerData();
117     if (cda != null && cda.length > 0) {
118       int limit = depth < cda.length ? depth : cda.length;
119 
120       for (int i = 0; i < limit; i++) {
121         buf.append("Caller+");
122         buf.append(i);
123         buf.append("\t at ");
124         buf.append(cda[i]);
125         buf.append(CoreConstants.LINE_SEPARATOR);
126       }
127       return buf.toString();
128     } else {
129       return CallerData.CALLER_DATA_NA;
130     }
131   }
132 }