1   package org.slf4j.ext;
2   
3   import org.slf4j.Logger;
4   import org.slf4j.Marker;
5   import org.slf4j.MarkerFactory;
6   import org.slf4j.helpers.MessageFormatter;
7   import org.slf4j.spi.LocationAwareLogger;
8   
9   /**
10   * A utility that provides standard mechanisms for logging certain kinds of
11   * activities.
12   * 
13   * @author Ralph Goers
14   * @author Ceki Gülcü
15   */
16  public class XLogger extends LoggerWrapper implements Logger {
17  
18    private static final String FQCN = XLogger.class.getName();
19    static Marker FLOW_MARKER = MarkerFactory.getMarker("FLOW");
20    static Marker ENTRY_MARKER = MarkerFactory.getMarker("ENTRY");
21    static Marker EXIT_MARKER = MarkerFactory.getMarker("EXIT");
22  
23    static Marker EXCEPTION_MARKER = MarkerFactory.getMarker("EXCEPTION");
24    static Marker THROWING_MARKER = MarkerFactory.getMarker("THROWING");
25    static Marker CATCHING_MARKER = MarkerFactory.getMarker("CATCHING");
26  
27    static String EXIT_MESSAGE_0 = "exit";
28    static String EXIT_MESSAGE_1 = "exit with ({})";
29  
30    static String ENTRY_MESSAGE_0 = "entry";
31    static String ENTRY_MESSAGE_1 = "entry with ({})";
32    static String ENTRY_MESSAGE_2 = "entry with ({}, {})";
33    static String ENTRY_MESSAGE_3 = "entry with ({}, {}, {})";
34    static String ENTRY_MESSAGE_4 = "entry with ({}, {}, {}, {})";
35    static int ENTRY_MESSAGE_ARRAY_LEN = 5;
36    static String[] ENTRY_MESSAGE_ARRAY = new String[ENTRY_MESSAGE_ARRAY_LEN];
37    static {
38      ENTRY_MARKER.add(FLOW_MARKER);
39      EXIT_MARKER.add(FLOW_MARKER);
40      THROWING_MARKER.add(EXCEPTION_MARKER);
41      CATCHING_MARKER.add(EXCEPTION_MARKER);
42  
43      ENTRY_MESSAGE_ARRAY[0] = ENTRY_MESSAGE_0;
44      ENTRY_MESSAGE_ARRAY[1] = ENTRY_MESSAGE_1;
45      ENTRY_MESSAGE_ARRAY[2] = ENTRY_MESSAGE_2;
46      ENTRY_MESSAGE_ARRAY[3] = ENTRY_MESSAGE_3;
47      ENTRY_MESSAGE_ARRAY[4] = ENTRY_MESSAGE_4;
48    }
49  
50    public enum Level {
51      TRACE("TRACE", LocationAwareLogger.TRACE_INT),
52      DEBUG("DEBUG", LocationAwareLogger.DEBUG_INT),
53      INFO("INFO", LocationAwareLogger.INFO_INT),
54      WARN("WARN", LocationAwareLogger.WARN_INT),
55      ERROR("ERROR", LocationAwareLogger.ERROR_INT);
56  
57      private final String name;
58      private final int level;
59  
60      public String toString() {
61        return this.name;
62      }
63  
64      public int intValue() {
65        return this.level;
66      }
67  
68      private Level(String name, int level) {
69        this.name = name;
70        this.level = level;
71      }
72    }
73  
74    /**
75     * Given an underlying logger, construct an XLogger
76     * 
77     * @param logger
78     *                underlying logger
79     */
80    public XLogger(Logger logger) {
81      // If class B extends A, assuming B does not override method x(), the caller
82      // of new B().x() is A and not B, see also
83      // http://bugzilla.slf4j.org/show_bug.cgi?id=114
84      super(logger, LoggerWrapper.class.getName());
85    }
86  
87    /**
88     * Log method entry.
89     * 
90     * @param argArray
91     *                supplied parameters
92     */
93    public void entry(Object... argArray) {
94      if (instanceofLAL && logger.isTraceEnabled(ENTRY_MARKER)) {
95        String messagePattern = null;
96        if (argArray.length < ENTRY_MESSAGE_ARRAY_LEN) {
97          messagePattern = ENTRY_MESSAGE_ARRAY[argArray.length];
98        } else {
99          messagePattern = buildMessagePattern(argArray.length);
100       }
101       String formattedMessage = MessageFormatter.arrayFormat(messagePattern,
102           argArray);
103       ((LocationAwareLogger) logger).log(ENTRY_MARKER, FQCN,
104           LocationAwareLogger.TRACE_INT, formattedMessage, null);
105     }
106   }
107 
108   /**
109    * Log method exit
110    */
111   public void exit() {
112     if (instanceofLAL && logger.isTraceEnabled(ENTRY_MARKER)) {
113       ((LocationAwareLogger) logger).log(EXIT_MARKER, FQCN,
114           LocationAwareLogger.TRACE_INT, EXIT_MESSAGE_0, null);
115     }
116   }
117 
118   /**
119    * Log method exit
120    * 
121    * @param result
122    *                The result of the method being exited
123    */
124   public void exit(Object result) {
125     if (instanceofLAL && logger.isTraceEnabled(ENTRY_MARKER)) {
126       String formattedMessage = MessageFormatter.format(EXIT_MESSAGE_1, result);
127       ((LocationAwareLogger) logger).log(EXIT_MARKER, FQCN,
128           LocationAwareLogger.TRACE_INT, formattedMessage, null);
129     }
130   }
131 
132   /**
133    * Log an exception being thrown. The generated log event uses Level ERROR.
134    * 
135    * @param throwable
136    *                the exception being caught.
137    */
138   public void throwing(Throwable throwable) {
139     if (instanceofLAL) {
140       ((LocationAwareLogger) logger).log(THROWING_MARKER, FQCN,
141           LocationAwareLogger.ERROR_INT, "throwing", throwable);
142     }
143   }
144 
145   /**
146    * Log an exception being thrown allowing the log level to be specified.
147    *
148    * @param level the logging level to use.
149    * @param throwable
150    *                the exception being caught.
151    */
152   public void throwing(Level level, Throwable throwable) {
153     if (instanceofLAL) {
154       ((LocationAwareLogger) logger).log(THROWING_MARKER, FQCN,
155           level.level, "throwing", throwable);
156     }
157   }
158 
159   /**
160    * Log an exception being caught. The generated log event uses Level ERROR.
161    * 
162    * @param throwable
163    *                the exception being caught.
164    */
165   public void catching(Throwable throwable) {
166     if (instanceofLAL) {
167       ((LocationAwareLogger) logger).log(CATCHING_MARKER, FQCN,
168           LocationAwareLogger.ERROR_INT, "catching", throwable);
169     }
170   }
171 
172   /**
173    * Log an exception being caught allowing the log level to be specified.
174    *
175    * @param level the logging level to use.
176    * @param throwable
177    *                the exception being caught.
178    */
179   public void catching(Level level, Throwable throwable) {
180     if (instanceofLAL) {
181       ((LocationAwareLogger) logger).log(CATCHING_MARKER, FQCN,
182           level.level, "catching", throwable);
183     }
184   }
185 
186   private static String buildMessagePattern(int len) {
187     StringBuilder sb = new StringBuilder();
188     sb.append(" entry with (");
189     for (int i = 0; i < len; i++) {
190       sb.append("{}");
191       if (i != len - 1)
192         sb.append(", ");
193     }
194     sb.append(')');
195     return sb.toString();
196   }
197 }