View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6   * See the AUTHORS.txt file in the distribution for a full listing of 
7   * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.common.util;
25  
26  import java.util.Locale;
27  import java.util.concurrent.atomic.AtomicReference;
28  import net.jcip.annotations.ThreadSafe;
29  import org.modeshape.common.i18n.I18n;
30  import org.slf4j.ILoggerFactory;
31  import org.slf4j.LoggerFactory;
32  
33  /**
34   * A simple logging interface that is fully compatible with multiple logging implementations. This interface does take advantage
35   * of the variable arguments and autoboxing features in Java 5, reducing the number of methods that are necessary and allowing
36   * callers to supply primitive values as parameters.
37   */
38  @ThreadSafe
39  public final class Logger {
40  
41      public enum Level {
42          OFF,
43          ERROR,
44          WARNING,
45          INFO,
46          DEBUG,
47          TRACE;
48      }
49  
50      private static final AtomicReference<Locale> LOGGING_LOCALE = new AtomicReference<Locale>(null);
51  
52      /**
53       * Get the locale used for the logs. If null, the {@link Locale#getDefault() default locale} is used.
54       * 
55       * @return the current locale used for logging, or null if the system locale is used
56       * @see #setLoggingLocale(Locale)
57       */
58      public static Locale getLoggingLocale() {
59          return LOGGING_LOCALE.get();
60      }
61  
62      /**
63       * Set the locale used for the logs. This should be used when the logs are to be written is a specific locale, independent of
64       * the {@link Locale#getDefault() default locale}. To use the default locale, call this method with a null value.
65       * 
66       * @param locale the desired locale to use for the logs, or null if the system locale should be used
67       * @return the previous locale
68       * @see #getLoggingLocale()
69       */
70      public static Locale setLoggingLocale( Locale locale ) {
71          return LOGGING_LOCALE.getAndSet(locale != null ? locale : Locale.getDefault());
72      }
73  
74      /**
75       * Return a logger named corresponding to the class passed as parameter, using the statically bound {@link ILoggerFactory}
76       * instance.
77       * 
78       * @param clazz the returned logger will be named after clazz
79       * @return logger
80       */
81      public static Logger getLogger( Class<?> clazz ) {
82          return new Logger(LoggerFactory.getLogger(clazz));
83      }
84  
85      /**
86       * Return a logger named according to the name parameter using the statically bound {@link ILoggerFactory} instance.
87       * 
88       * @param name The name of the logger.
89       * @return logger
90       */
91      public static Logger getLogger( String name ) {
92          return new Logger(LoggerFactory.getLogger(name));
93      }
94  
95      private final org.slf4j.Logger delegate;
96  
97      private Logger( org.slf4j.Logger delegate ) {
98          this.delegate = delegate;
99      }
100 
101     /**
102      * Return the name of this logger instance.
103      * 
104      * @return the logger's name
105      */
106     public String getName() {
107         return this.delegate.getName();
108     }
109 
110     /**
111      * Log a message at the suplied level according to the specified format and (optional) parameters. The message should contain
112      * a pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is
113      * efficient and avoids superfluous object creation when the logger is disabled for the desired level.
114      * 
115      * @param level the level at which to log
116      * @param message the (localized) message string
117      * @param params the parameter values that are to replace the variables in the format string
118      */
119     public void log( Level level,
120                      I18n message,
121                      Object... params ) {
122         if (message == null) return;
123         switch (level) {
124             case DEBUG:
125                 debug(message.text(LOGGING_LOCALE.get(), params));
126                 break;
127             case ERROR:
128                 error(message, params);
129                 break;
130             case INFO:
131                 info(message, params);
132                 break;
133             case TRACE:
134                 trace(message.text(LOGGING_LOCALE.get(), params));
135                 break;
136             case WARNING:
137                 warn(message, params);
138                 break;
139             case OFF:
140                 break;
141         }
142     }
143 
144     /**
145      * Log an exception (throwable) at the supplied level with an accompanying message. If the exception is null, then this method
146      * calls {@link #debug(String, Object...)}.
147      * 
148      * @param level the level at which to log
149      * @param t the exception (throwable) to log
150      * @param message the message accompanying the exception
151      * @param params the parameter values that are to replace the variables in the format string
152      */
153     public void log( Level level,
154                      Throwable t,
155                      I18n message,
156                      Object... params ) {
157         if (message == null) return;
158         switch (level) {
159             case DEBUG:
160                 debug(t, message.text(LOGGING_LOCALE.get(), params));
161                 break;
162             case ERROR:
163                 error(t, message, params);
164                 break;
165             case INFO:
166                 info(t, message, params);
167                 break;
168             case TRACE:
169                 trace(t, message.text(LOGGING_LOCALE.get(), params));
170                 break;
171             case WARNING:
172                 warn(t, message, params);
173                 break;
174             case OFF:
175                 break;
176         }
177     }
178 
179     /**
180      * Log a message at the DEBUG level according to the specified format and (optional) parameters. The message should contain a
181      * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
182      * and avoids superfluous object creation when the logger is disabled for the DEBUG level.
183      * 
184      * @param message the message string
185      * @param params the parameter values that are to replace the variables in the format string
186      */
187     public void debug( String message,
188                        Object... params ) {
189         if (!isDebugEnabled()) return;
190         if (message == null) return;
191         this.delegate.debug(StringUtil.createString(message, params));
192     }
193 
194     /**
195      * Log an exception (throwable) at the DEBUG level with an accompanying message. If the exception is null, then this method
196      * calls {@link #debug(String, Object...)}.
197      * 
198      * @param t the exception (throwable) to log
199      * @param message the message accompanying the exception
200      * @param params the parameter values that are to replace the variables in the format string
201      */
202     public void debug( Throwable t,
203                        String message,
204                        Object... params ) {
205         if (!isDebugEnabled()) return;
206         if (t == null) {
207             debug(message, params);
208             return;
209         }
210         if (message == null) {
211             this.delegate.debug(null, t);
212             return;
213         }
214         this.delegate.debug(StringUtil.createString(message, params), t);
215     }
216 
217     /**
218      * Log a message at the ERROR level according to the specified format and (optional) parameters. The message should contain a
219      * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
220      * and avoids superfluous object creation when the logger is disabled for the ERROR level.
221      * 
222      * @param message the message string
223      * @param params the parameter values that are to replace the variables in the format string
224      */
225     public void error( I18n message,
226                        Object... params ) {
227         if (!isErrorEnabled()) return;
228         if (message == null) return;
229         this.delegate.error(message.text(LOGGING_LOCALE.get(), params));
230     }
231 
232     /**
233      * Log an exception (throwable) at the ERROR level with an accompanying message. If the exception is null, then this method
234      * calls {@link #error(I18n, Object...)}.
235      * 
236      * @param t the exception (throwable) to log
237      * @param message the message accompanying the exception
238      * @param params the parameter values that are to replace the variables in the format string
239      */
240     public void error( Throwable t,
241                        I18n message,
242                        Object... params ) {
243         if (!isErrorEnabled()) return;
244         if (t == null) {
245             error(message, params);
246             return;
247         }
248         if (message == null) {
249             this.delegate.error(null, t);
250             return;
251         }
252         this.delegate.error(message.text(LOGGING_LOCALE.get(), params), t);
253     }
254 
255     /**
256      * Log a message at the INFO level according to the specified format and (optional) parameters. The message should contain a
257      * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
258      * and avoids superfluous object creation when the logger is disabled for the INFO level.
259      * 
260      * @param message the message string
261      * @param params the parameter values that are to replace the variables in the format string
262      */
263     public void info( I18n message,
264                       Object... params ) {
265         if (!isInfoEnabled()) return;
266         if (message == null) return;
267         this.delegate.info(message.text(LOGGING_LOCALE.get(), params));
268     }
269 
270     /**
271      * Log an exception (throwable) at the INFO level with an accompanying message. If the exception is null, then this method
272      * calls {@link #info(I18n, Object...)}.
273      * 
274      * @param t the exception (throwable) to log
275      * @param message the message accompanying the exception
276      * @param params the parameter values that are to replace the variables in the format string
277      */
278     public void info( Throwable t,
279                       I18n message,
280                       Object... params ) {
281         if (!isInfoEnabled()) return;
282         if (t == null) {
283             info(message, params);
284             return;
285         }
286         if (message == null) {
287             this.delegate.info(null, t);
288             return;
289         }
290         this.delegate.info(message.text(LOGGING_LOCALE.get(), params), t);
291     }
292 
293     /**
294      * Log a message at the TRACE level according to the specified format and (optional) parameters. The message should contain a
295      * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
296      * and avoids superfluous object creation when the logger is disabled for the TRACE level.
297      * 
298      * @param message the message string
299      * @param params the parameter values that are to replace the variables in the format string
300      */
301     public void trace( String message,
302                        Object... params ) {
303         if (!isTraceEnabled()) return;
304         if (message == null) return;
305         this.delegate.trace(StringUtil.createString(message, params));
306     }
307 
308     /**
309      * Log an exception (throwable) at the TRACE level with an accompanying message. If the exception is null, then this method
310      * calls {@link #trace(String, Object...)}.
311      * 
312      * @param t the exception (throwable) to log
313      * @param message the message accompanying the exception
314      * @param params the parameter values that are to replace the variables in the format string
315      */
316     public void trace( Throwable t,
317                        String message,
318                        Object... params ) {
319         if (!isTraceEnabled()) return;
320         if (t == null) {
321             this.trace(message, params);
322             return;
323         }
324         if (message == null) {
325             this.delegate.trace(null, t);
326             return;
327         }
328         this.delegate.trace(StringUtil.createString(message, params), t);
329     }
330 
331     /**
332      * Log a message at the WARNING level according to the specified format and (optional) parameters. The message should contain
333      * a pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is
334      * efficient and avoids superfluous object creation when the logger is disabled for the WARNING level.
335      * 
336      * @param message the message string
337      * @param params the parameter values that are to replace the variables in the format string
338      */
339     public void warn( I18n message,
340                       Object... params ) {
341         if (!isWarnEnabled()) return;
342         if (message == null) return;
343         this.delegate.warn(message.text(LOGGING_LOCALE.get(), params));
344     }
345 
346     /**
347      * Log an exception (throwable) at the WARNING level with an accompanying message. If the exception is null, then this method
348      * calls {@link #warn(I18n, Object...)}.
349      * 
350      * @param t the exception (throwable) to log
351      * @param message the message accompanying the exception
352      * @param params the parameter values that are to replace the variables in the format string
353      */
354     public void warn( Throwable t,
355                       I18n message,
356                       Object... params ) {
357         if (!isWarnEnabled()) return;
358         if (t == null) {
359             warn(message, params);
360             return;
361         }
362         if (message == null) {
363             this.delegate.warn(null, t);
364             return;
365         }
366         this.delegate.warn(message.text(LOGGING_LOCALE.get(), params), t);
367     }
368 
369     /**
370      * Return whether messages at the INFORMATION level are being logged.
371      * 
372      * @return true if INFORMATION log messages are currently being logged, or false otherwise.
373      */
374     protected boolean isInfoEnabled() {
375         return this.delegate.isInfoEnabled();
376     }
377 
378     /**
379      * Return whether messages at the WARNING level are being logged.
380      * 
381      * @return true if WARNING log messages are currently being logged, or false otherwise.
382      */
383     protected boolean isWarnEnabled() {
384         return this.delegate.isWarnEnabled();
385     }
386 
387     /**
388      * Return whether messages at the ERROR level are being logged.
389      * 
390      * @return true if ERROR log messages are currently being logged, or false otherwise.
391      */
392     protected boolean isErrorEnabled() {
393         return this.delegate.isErrorEnabled();
394     }
395 
396     /**
397      * Return whether messages at the DEBUG level are being logged.
398      * 
399      * @return true if DEBUG log messages are currently being logged, or false otherwise.
400      */
401     public boolean isDebugEnabled() {
402         return this.delegate.isDebugEnabled();
403     }
404 
405     /**
406      * Return whether messages at the TRACE level are being logged.
407      * 
408      * @return true if TRACE log messages are currently being logged, or false otherwise.
409      */
410     public boolean isTraceEnabled() {
411         return this.delegate.isTraceEnabled();
412     }
413 
414     /**
415      * Get the logging level at which this logger is current set.
416      * 
417      * @return the current logging level
418      */
419     public Level getLevel() {
420         if (this.isTraceEnabled()) return Level.TRACE;
421         if (this.isDebugEnabled()) return Level.DEBUG;
422         if (this.isInfoEnabled()) return Level.INFO;
423         if (this.isWarnEnabled()) return Level.WARNING;
424         if (this.isErrorEnabled()) return Level.ERROR;
425         return Level.OFF;
426     }
427 
428 }