001 /*
002 * JBoss, Home of Professional Open Source.
003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
004 * as indicated by the @author tags. See the copyright.txt file in the
005 * distribution for a full listing of individual contributors.
006 *
007 * This is free software; you can redistribute it and/or modify it
008 * under the terms of the GNU Lesser General Public License as
009 * published by the Free Software Foundation; either version 2.1 of
010 * the License, or (at your option) any later version.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022 package org.jboss.dna.common.util;
023
024 import java.util.Locale;
025 import java.util.concurrent.atomic.AtomicReference;
026 import net.jcip.annotations.ThreadSafe;
027 import org.jboss.dna.common.i18n.I18n;
028 import org.slf4j.ILoggerFactory;
029 import org.slf4j.LoggerFactory;
030
031 /**
032 * A simple logging interface that is fully compatible with multiple logging implementations. This interface does take advantage
033 * of the variable arguments and autoboxing features in Java 5, reducing the number of methods that are necessary and allowing
034 * callers to supply primitive values as parameters.
035 */
036 @ThreadSafe
037 public final class Logger {
038
039 public enum Level {
040 OFF,
041 ERROR,
042 WARNING,
043 INFO,
044 DEBUG,
045 TRACE;
046 }
047
048 private static final AtomicReference<Locale> LOGGING_LOCALE = new AtomicReference<Locale>(null);
049
050 /**
051 * Get the locale used for the logs. If null, the {@link Locale#getDefault() default locale} is used.
052 *
053 * @return the current locale used for logging, or null if the system locale is used
054 * @see #setLoggingLocale(Locale)
055 */
056 public static Locale getLoggingLocale() {
057 return LOGGING_LOCALE.get();
058 }
059
060 /**
061 * Set the locale used for the logs. This should be used when the logs are to be written is a specific locale, independent of
062 * the {@link Locale#getDefault() default locale}. To use the default locale, call this method with a null value.
063 *
064 * @param locale the desired locale to use for the logs, or null if the system locale should be used
065 * @return the previous locale
066 * @see #getLoggingLocale()
067 */
068 public static Locale setLoggingLocale( Locale locale ) {
069 return LOGGING_LOCALE.getAndSet(locale != null ? locale : Locale.getDefault());
070 }
071
072 /**
073 * Return a logger named corresponding to the class passed as parameter, using the statically bound {@link ILoggerFactory}
074 * instance.
075 *
076 * @param clazz the returned logger will be named after clazz
077 * @return logger
078 */
079 public static Logger getLogger( Class<?> clazz ) {
080 return new Logger(LoggerFactory.getLogger(clazz));
081 }
082
083 /**
084 * Return a logger named according to the name parameter using the statically bound {@link ILoggerFactory} instance.
085 *
086 * @param name The name of the logger.
087 * @return logger
088 */
089 public static Logger getLogger( String name ) {
090 return new Logger(LoggerFactory.getLogger(name));
091 }
092
093 private final org.slf4j.Logger delegate;
094
095 private Logger( org.slf4j.Logger delegate ) {
096 this.delegate = delegate;
097 }
098
099 /**
100 * Return the name of this logger instance.
101 *
102 * @return the logger's name
103 */
104 public String getName() {
105 return this.delegate.getName();
106 }
107
108 /**
109 * Log a message at the suplied level according to the specified format and (optional) parameters. The message should contain
110 * a pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is
111 * efficient and avoids superfluous object creation when the logger is disabled for the desired level.
112 *
113 * @param level the level at which to log
114 * @param message the (localized) message string
115 * @param params the parameter values that are to replace the variables in the format string
116 */
117 public void log( Level level,
118 I18n message,
119 Object... params ) {
120 if (message == null) return;
121 switch (level) {
122 case DEBUG:
123 debug(message.text(LOGGING_LOCALE.get(), params));
124 break;
125 case ERROR:
126 error(message, params);
127 break;
128 case INFO:
129 info(message, params);
130 break;
131 case TRACE:
132 trace(message.text(LOGGING_LOCALE.get(), params));
133 break;
134 case WARNING:
135 warn(message, params);
136 break;
137 case OFF:
138 break;
139 }
140 }
141
142 /**
143 * Log an exception (throwable) at the supplied level with an accompanying message. If the exception is null, then this method
144 * calls {@link #debug(String, Object...)}.
145 *
146 * @param level the level at which to log
147 * @param t the exception (throwable) to log
148 * @param message the message accompanying the exception
149 * @param params the parameter values that are to replace the variables in the format string
150 */
151 public void log( Level level,
152 Throwable t,
153 I18n message,
154 Object... params ) {
155 if (message == null) return;
156 switch (level) {
157 case DEBUG:
158 debug(t, message.text(LOGGING_LOCALE.get(), params));
159 break;
160 case ERROR:
161 error(t, message, params);
162 break;
163 case INFO:
164 info(t, message, params);
165 break;
166 case TRACE:
167 trace(t, message.text(LOGGING_LOCALE.get(), params));
168 break;
169 case WARNING:
170 warn(t, message, params);
171 break;
172 case OFF:
173 break;
174 }
175 }
176
177 /**
178 * Log a message at the DEBUG level according to the specified format and (optional) parameters. The message should contain a
179 * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
180 * and avoids superfluous object creation when the logger is disabled for the DEBUG level.
181 *
182 * @param message the message string
183 * @param params the parameter values that are to replace the variables in the format string
184 */
185 public void debug( String message,
186 Object... params ) {
187 if (!isDebugEnabled()) return;
188 if (message == null) return;
189 this.delegate.debug(StringUtil.createString(message, params));
190 }
191
192 /**
193 * Log an exception (throwable) at the DEBUG level with an accompanying message. If the exception is null, then this method
194 * calls {@link #debug(String, Object...)}.
195 *
196 * @param t the exception (throwable) to log
197 * @param message the message accompanying the exception
198 * @param params the parameter values that are to replace the variables in the format string
199 */
200 public void debug( Throwable t,
201 String message,
202 Object... params ) {
203 if (!isDebugEnabled()) return;
204 if (t == null) {
205 debug(message, params);
206 return;
207 }
208 if (message == null) {
209 this.delegate.debug(null, t);
210 return;
211 }
212 this.delegate.debug(StringUtil.createString(message, params), t);
213 }
214
215 /**
216 * Log a message at the ERROR level according to the specified format and (optional) parameters. The message should contain a
217 * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
218 * and avoids superfluous object creation when the logger is disabled for the ERROR level.
219 *
220 * @param message the message string
221 * @param params the parameter values that are to replace the variables in the format string
222 */
223 public void error( I18n message,
224 Object... params ) {
225 if (!isErrorEnabled()) return;
226 if (message == null) return;
227 this.delegate.error(message.text(LOGGING_LOCALE.get(), params));
228 }
229
230 /**
231 * Log an exception (throwable) at the ERROR level with an accompanying message. If the exception is null, then this method
232 * calls {@link #error(I18n, Object...)}.
233 *
234 * @param t the exception (throwable) to log
235 * @param message the message accompanying the exception
236 * @param params the parameter values that are to replace the variables in the format string
237 */
238 public void error( Throwable t,
239 I18n message,
240 Object... params ) {
241 if (!isErrorEnabled()) return;
242 if (t == null) {
243 error(message, params);
244 return;
245 }
246 if (message == null) {
247 this.delegate.error(null, t);
248 return;
249 }
250 this.delegate.error(message.text(LOGGING_LOCALE.get(), params), t);
251 }
252
253 /**
254 * Log a message at the INFO level according to the specified format and (optional) parameters. The message should contain a
255 * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
256 * and avoids superfluous object creation when the logger is disabled for the INFO level.
257 *
258 * @param message the message string
259 * @param params the parameter values that are to replace the variables in the format string
260 */
261 public void info( I18n message,
262 Object... params ) {
263 if (!isInfoEnabled()) return;
264 if (message == null) return;
265 this.delegate.info(message.text(LOGGING_LOCALE.get(), params));
266 }
267
268 /**
269 * Log an exception (throwable) at the INFO level with an accompanying message. If the exception is null, then this method
270 * calls {@link #info(I18n, Object...)}.
271 *
272 * @param t the exception (throwable) to log
273 * @param message the message accompanying the exception
274 * @param params the parameter values that are to replace the variables in the format string
275 */
276 public void info( Throwable t,
277 I18n message,
278 Object... params ) {
279 if (!isInfoEnabled()) return;
280 if (t == null) {
281 info(message, params);
282 return;
283 }
284 if (message == null) {
285 this.delegate.info(null, t);
286 return;
287 }
288 this.delegate.info(message.text(LOGGING_LOCALE.get(), params), t);
289 }
290
291 /**
292 * Log a message at the TRACE level according to the specified format and (optional) parameters. The message should contain a
293 * pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is efficient
294 * and avoids superfluous object creation when the logger is disabled for the TRACE level.
295 *
296 * @param message the message string
297 * @param params the parameter values that are to replace the variables in the format string
298 */
299 public void trace( String message,
300 Object... params ) {
301 if (!isTraceEnabled()) return;
302 if (message == null) return;
303 this.delegate.trace(StringUtil.createString(message, params));
304 }
305
306 /**
307 * Log an exception (throwable) at the TRACE level with an accompanying message. If the exception is null, then this method
308 * calls {@link #trace(String, Object...)}.
309 *
310 * @param t the exception (throwable) to log
311 * @param message the message accompanying the exception
312 * @param params the parameter values that are to replace the variables in the format string
313 */
314 public void trace( Throwable t,
315 String message,
316 Object... params ) {
317 if (!isTraceEnabled()) return;
318 if (t == null) {
319 this.trace(message, params);
320 return;
321 }
322 if (message == null) {
323 this.delegate.trace(null, t);
324 return;
325 }
326 this.delegate.trace(StringUtil.createString(message, params), t);
327 }
328
329 /**
330 * Log a message at the WARNING level according to the specified format and (optional) parameters. The message should contain
331 * a pair of empty curly braces for each of the parameter, which should be passed in the correct order. This method is
332 * efficient and avoids superfluous object creation when the logger is disabled for the WARNING level.
333 *
334 * @param message the message string
335 * @param params the parameter values that are to replace the variables in the format string
336 */
337 public void warn( I18n message,
338 Object... params ) {
339 if (!isWarnEnabled()) return;
340 if (message == null) return;
341 this.delegate.warn(message.text(LOGGING_LOCALE.get(), params));
342 }
343
344 /**
345 * Log an exception (throwable) at the WARNING level with an accompanying message. If the exception is null, then this method
346 * calls {@link #warn(I18n, Object...)}.
347 *
348 * @param t the exception (throwable) to log
349 * @param message the message accompanying the exception
350 * @param params the parameter values that are to replace the variables in the format string
351 */
352 public void warn( Throwable t,
353 I18n message,
354 Object... params ) {
355 if (!isWarnEnabled()) return;
356 if (t == null) {
357 warn(message, params);
358 return;
359 }
360 if (message == null) {
361 this.delegate.warn(null, t);
362 return;
363 }
364 this.delegate.warn(message.text(LOGGING_LOCALE.get(), params), t);
365 }
366
367 /**
368 * Return whether messages at the INFORMATION level are being logged.
369 *
370 * @return true if INFORMATION log messages are currently being logged, or false otherwise.
371 */
372 protected boolean isInfoEnabled() {
373 return this.delegate.isInfoEnabled();
374 }
375
376 /**
377 * Return whether messages at the WARNING level are being logged.
378 *
379 * @return true if WARNING log messages are currently being logged, or false otherwise.
380 */
381 protected boolean isWarnEnabled() {
382 return this.delegate.isWarnEnabled();
383 }
384
385 /**
386 * Return whether messages at the ERROR level are being logged.
387 *
388 * @return true if ERROR log messages are currently being logged, or false otherwise.
389 */
390 protected boolean isErrorEnabled() {
391 return this.delegate.isErrorEnabled();
392 }
393
394 /**
395 * Return whether messages at the DEBUG level are being logged.
396 *
397 * @return true if DEBUG log messages are currently being logged, or false otherwise.
398 */
399 public boolean isDebugEnabled() {
400 return this.delegate.isDebugEnabled();
401 }
402
403 /**
404 * Return whether messages at the TRACE level are being logged.
405 *
406 * @return true if TRACE log messages are currently being logged, or false otherwise.
407 */
408 public boolean isTraceEnabled() {
409 return this.delegate.isTraceEnabled();
410 }
411
412 /**
413 * Get the logging level at which this logger is current set.
414 *
415 * @return the current logging level
416 */
417 public Level getLevel() {
418 if (this.isTraceEnabled()) return Level.TRACE;
419 if (this.isDebugEnabled()) return Level.DEBUG;
420 if (this.isInfoEnabled()) return Level.INFO;
421 if (this.isWarnEnabled()) return Level.WARNING;
422 if (this.isErrorEnabled()) return Level.ERROR;
423 return Level.OFF;
424 }
425
426 }