001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.common.util;
025
026 import java.util.Locale;
027 import java.util.concurrent.atomic.AtomicReference;
028 import net.jcip.annotations.ThreadSafe;
029 import org.jboss.dna.common.i18n.I18n;
030 import org.slf4j.ILoggerFactory;
031 import org.slf4j.LoggerFactory;
032
033 /**
034 * A simple logging interface that is fully compatible with multiple logging implementations. This interface does take advantage
035 * of the variable arguments and autoboxing features in Java 5, reducing the number of methods that are necessary and allowing
036 * callers to supply primitive values as parameters.
037 */
038 @ThreadSafe
039 public final class Logger {
040
041 public enum Level {
042 OFF,
043 ERROR,
044 WARNING,
045 INFO,
046 DEBUG,
047 TRACE;
048 }
049
050 private static final AtomicReference<Locale> LOGGING_LOCALE = new AtomicReference<Locale>(null);
051
052 /**
053 * Get the locale used for the logs. If null, the {@link Locale#getDefault() default locale} is used.
054 *
055 * @return the current locale used for logging, or null if the system locale is used
056 * @see #setLoggingLocale(Locale)
057 */
058 public static Locale getLoggingLocale() {
059 return LOGGING_LOCALE.get();
060 }
061
062 /**
063 * Set the locale used for the logs. This should be used when the logs are to be written is a specific locale, independent of
064 * the {@link Locale#getDefault() default locale}. To use the default locale, call this method with a null value.
065 *
066 * @param locale the desired locale to use for the logs, or null if the system locale should be used
067 * @return the previous locale
068 * @see #getLoggingLocale()
069 */
070 public static Locale setLoggingLocale( Locale locale ) {
071 return LOGGING_LOCALE.getAndSet(locale != null ? locale : Locale.getDefault());
072 }
073
074 /**
075 * Return a logger named corresponding to the class passed as parameter, using the statically bound {@link ILoggerFactory}
076 * instance.
077 *
078 * @param clazz the returned logger will be named after clazz
079 * @return logger
080 */
081 public static Logger getLogger( Class<?> clazz ) {
082 return new Logger(LoggerFactory.getLogger(clazz));
083 }
084
085 /**
086 * Return a logger named according to the name parameter using the statically bound {@link ILoggerFactory} instance.
087 *
088 * @param name The name of the logger.
089 * @return logger
090 */
091 public static Logger getLogger( String name ) {
092 return new Logger(LoggerFactory.getLogger(name));
093 }
094
095 private final org.slf4j.Logger delegate;
096
097 private Logger( org.slf4j.Logger delegate ) {
098 this.delegate = delegate;
099 }
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 }