View Javadoc
1   package org.djutils.logger;
2   
3   import java.util.Arrays;
4   import java.util.LinkedHashMap;
5   import java.util.LinkedHashSet;
6   import java.util.Map;
7   import java.util.Set;
8   import java.util.function.BooleanSupplier;
9   
10  import org.djutils.exceptions.Throw;
11  import org.djutils.immutablecollections.Immutable;
12  import org.djutils.immutablecollections.ImmutableLinkedHashSet;
13  import org.djutils.immutablecollections.ImmutableSet;
14  import org.pmw.tinylog.Configurator;
15  import org.pmw.tinylog.Level;
16  import org.pmw.tinylog.LogEntryForwarder;
17  import org.pmw.tinylog.Logger;
18  import org.pmw.tinylog.writers.ConsoleWriter;
19  import org.pmw.tinylog.writers.Writer;
20  
21  /**
22   * The CategoryLogger can log for specific Categories. The way to call the logger for messages that always need to be logged,
23   * such as an error with an exception is:
24   * 
25   * <pre>
26   * CategoryLogger.always().error(exception, "Parameter {} did not initialize correctly", param1.toString());
27   * </pre>
28   * 
29   * It is also possible to indicate the category / categories for the message, which will only be logged if at least one of the
30   * indicated categories is turned on with addLogCategory() or setLogCategories(), or if one of the added or set LogCategories is
31   * LogCategory.ALL:
32   * 
33   * <pre>
34   * CategoryLogger.filter(Cat.BASE).debug("Parameter {} initialized correctly", param1.toString());
35   * </pre>
36   * <p>
37   * Copyright (c) 2018-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
38   * for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
39   * distributed under a three-clause BSD-style license, which can be found at
40   * <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
41   * </p>
42   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank"> Alexander Verbraeck</a>
43   */
44  @SuppressWarnings("checkstyle:needbraces")
45  public final class CategoryLogger
46  {
47      /** The default message format. */
48      public static final String DEFAULT_MESSAGE_FORMAT = "{class_name}.{method}:{line} {message|indent=4}";
49  
50      /** The current message format. */
51      private static String defaultMessageFormat = DEFAULT_MESSAGE_FORMAT;
52  
53      /** The current logging level. */
54      private static Level defaultLevel = Level.INFO;
55  
56      /** The writers registered with this CategoryLogger. */
57      private static final Set<Writer> WRITERS = new LinkedHashSet<>();
58  
59      /** The log level per Writer. */
60      private static final Map<Writer, Level> WRITER_LEVELS = new LinkedHashMap<>();
61  
62      /** The message format per Writer. */
63      private static final Map<Writer, String> WRITER_FORMATS = new LinkedHashMap<>();
64  
65      /** The categories to log. */
66      private static final Set<LogCategory> LOG_CATEGORIES = new LinkedHashSet<>(256);
67  
68      /** A cached immutable copy of the log categories to return to `extending` classes. */
69      private static ImmutableSet<LogCategory> immutableLogCategories;
70  
71      /** The delegate logger instance that does the actual logging work, after a positive filter outcome. */
72      public static final DelegateLogger DELEGATE_LOGGER = new DelegateLogger(true);
73  
74      /** The delegate logger that returns immediately after a negative filter outcome. */
75      public static final DelegateLogger NO_LOGGER = new DelegateLogger(false);
76  
77      /** */
78      private CategoryLogger()
79      {
80          // Utility class.
81      }
82  
83      static
84      {
85          create();
86      }
87  
88      /**
89       * Create a new logger for the system console. Note that this REPLACES current writers. Note that the initial LogCategory is
90       * LogCategory.ALL, so all categories will be logged. This category has to be explicitly removed (or new categories have to
91       * be set) to log a limited set of categories.
92       */
93      protected static void create()
94      {
95          Logger.getConfiguration().removeAllWriters().activate();
96          addWriter(new ConsoleWriter());
97          LOG_CATEGORIES.add(LogCategory.ALL);
98          immutableLogCategories = new ImmutableLinkedHashSet<>(LOG_CATEGORIES, Immutable.COPY);
99      }
100 
101     /**
102      * Set a new logging format for the message lines of all writers. The default message format is:<br>
103      * {class_name}.{method}:{line} {message|indent=4}<br>
104      * <br>
105      * A few popular placeholders that can be used:<br>
106      * - {class} Fully-qualified class name where the logging request is issued<br>
107      * - {class_name} Class name (without package) where the logging request is issued<br>
108      * - {date} Date and time of the logging request, e.g. {date:yyyy-MM-dd HH:mm:ss} [SimpleDateFormat]<br>
109      * - {level} Logging level of the created log entry<br>
110      * - {line} Line number from where the logging request is issued<br>
111      * - {message} Associated message of the created log entry<br>
112      * - {method} Method name from where the logging request is issued<br>
113      * - {package} Package where the logging request is issued<br>
114      * Because all individual writers get a log level at which they log, the overall log level in the Configurator is
115      * Level.TRACE, which means that all messages are passed through on a generic level and it is up to the individual Writers
116      * to decide when to log.
117      * @see <a href="https://tinylog.org/configuration#format">https://tinylog.org/configuration</a>
118      * @param newMessageFormat String; the new formatting pattern to use for all registered writers
119      */
120     public static void setAllLogMessageFormat(final String newMessageFormat)
121     {
122         Configurator configurator = Logger.getConfiguration();
123         defaultMessageFormat = newMessageFormat;
124         configurator.formatPattern(defaultMessageFormat).level(Level.TRACE);
125         for (Writer writer : WRITERS)
126         {
127             configurator.removeWriter(writer).activate();
128             WRITER_FORMATS.put(writer, newMessageFormat);
129             configurator.addWriter(writer, WRITER_LEVELS.get(writer), defaultMessageFormat);
130         }
131         configurator.activate();
132     }
133 
134     /**
135      * Set a new logging level for all registered writers. Because all individual writers get a log level at which they log, the
136      * overall log level in the Configurator is Level.TRACE, which means that all messages are passed through on a generic level
137      * and it is up to the individual Writers to decide when to log.
138      * @param newLevel Level; the new log level for all registered writers
139      */
140     public static void setAllLogLevel(final Level newLevel)
141     {
142         Configurator configurator = Logger.getConfiguration();
143         defaultLevel = newLevel;
144         configurator.formatPattern(defaultMessageFormat).level(Level.TRACE);
145         for (Writer writer : WRITERS)
146         {
147             configurator.removeWriter(writer).activate();
148             WRITER_LEVELS.put(writer, newLevel);
149             configurator.addWriter(writer, newLevel, WRITER_FORMATS.get(writer));
150         }
151         configurator.activate();
152     }
153 
154     /**
155      * Set a new logging format for the message lines of a writer. The default message format is:<br>
156      * {class_name}.{method}:{line} {message|indent=4}<br>
157      * <br>
158      * A few popular placeholders that can be used:<br>
159      * - {class} Fully-qualified class name where the logging request is issued<br>
160      * - {class_name} Class name (without package) where the logging request is issued<br>
161      * - {date} Date and time of the logging request, e.g. {date:yyyy-MM-dd HH:mm:ss} [SimpleDateFormat]<br>
162      * - {level} Logging level of the created log entry<br>
163      * - {line} Line number from where the logging request is issued<br>
164      * - {message} Associated message of the created log entry<br>
165      * - {method} Method name from where the logging request is issued<br>
166      * - {package} Package where the logging request is issued<br>
167      * @see <a href="https://tinylog.org/configuration#format">https://tinylog.org/configuration</a>
168      * @param writer Writer; the writer to change the message format for
169      * @param newMessageFormat String; the new formatting pattern to use for all registered writers
170      */
171     public static void setLogMessageFormat(final Writer writer, final String newMessageFormat)
172     {
173         Configurator configurator = Logger.getConfiguration();
174         configurator.removeWriter(writer);
175         WRITER_FORMATS.put(writer, newMessageFormat);
176         configurator.addWriter(writer, WRITER_LEVELS.get(writer), newMessageFormat);
177         configurator.activate();
178     }
179 
180     /**
181      * Set a new logging level for one of the registered writers.
182      * @param writer Writer; the writer to change the log level for
183      * @param newLevel Level; the new log level for the writer
184      */
185     public static void setLogLevel(final Writer writer, final Level newLevel)
186     {
187         Configurator configurator = Logger.getConfiguration();
188         configurator.removeWriter(writer);
189         WRITER_LEVELS.put(writer, newLevel);
190         configurator.addWriter(writer, newLevel, WRITER_FORMATS.get(writer));
191         configurator.activate();
192     }
193 
194     /**
195      * Add a writer to the CategoryLogger, using the current default for the log level and for the message format.
196      * @param writer Writer; the writer to add
197      * @return boolean; true when the writer was added; false when the writer was already registered
198      */
199     public static boolean addWriter(final Writer writer)
200     {
201         Throw.whenNull(writer, "writer may not be null");
202         Configurator configurator = Logger.getConfiguration();
203         boolean result = WRITERS.add(writer);
204         WRITER_LEVELS.put(writer, defaultLevel);
205         WRITER_FORMATS.put(writer, defaultMessageFormat);
206         configurator.addWriter(writer, defaultLevel, defaultMessageFormat);
207         configurator.activate();
208         return result;
209     }
210 
211     /**
212      * Remove a writer from the CategoryLogger.
213      * @param writer Writer; the writer to remove
214      * @return boolean; true if the writer was removed; false if the writer was not registered (and thus could not be removed)
215      */
216     public static boolean removeWriter(final Writer writer)
217     {
218         Throw.whenNull(writer, "writer may not be null");
219         Configurator configurator = Logger.getConfiguration();
220         boolean result = WRITERS.remove(writer);
221         WRITER_LEVELS.remove(writer);
222         WRITER_FORMATS.remove(writer);
223         configurator.removeWriter(writer);
224         configurator.activate();
225         return result;
226     }
227 
228     /**
229      * Return the set of all registered writers.
230      * @return ImmutableSet&lt;Writer&gt;; the set of all registered writers
231      */
232     public static ImmutableSet<Writer> getWriters()
233     {
234         return new ImmutableLinkedHashSet<>(WRITERS, Immutable.WRAP);
235     }
236 
237     /**
238      * Add a category to be logged to the Writers.
239      * @param logCategory LogCategory; the LogCategory to add
240      */
241     public static void addLogCategory(final LogCategory logCategory)
242     {
243         LOG_CATEGORIES.add(logCategory);
244         immutableLogCategories = new ImmutableLinkedHashSet<>(LOG_CATEGORIES, Immutable.COPY);
245     }
246 
247     /**
248      * Remove a category to be logged to the Writers.
249      * @param logCategory LogCategory; the LogCategory to remove
250      */
251     public static void removeLogCategory(final LogCategory logCategory)
252     {
253         LOG_CATEGORIES.remove(logCategory);
254         immutableLogCategories = new ImmutableLinkedHashSet<>(LOG_CATEGORIES, Immutable.COPY);
255     }
256 
257     /**
258      * Set the categories to be logged to the Writers.
259      * @param newLogCategories LogCategory...; the LogCategories to set, replacing the previous ones
260      */
261     public static void setLogCategories(final LogCategory... newLogCategories)
262     {
263         LOG_CATEGORIES.clear();
264         LOG_CATEGORIES.addAll(Arrays.asList(newLogCategories));
265         immutableLogCategories = new ImmutableLinkedHashSet<>(LOG_CATEGORIES, Immutable.COPY);
266     }
267 
268     /**
269      * Return the set of all log categories (cached immutable copy).
270      * @return ImmutableSet&lt;Writer&gt;; the set of all registered writers
271      */
272     public static ImmutableSet<LogCategory> getLogCategories()
273     {
274         return immutableLogCategories;
275     }
276 
277     /* ****************************************** FILTER ******************************************/
278 
279     /**
280      * The "pass" filter that will result in always trying to log.
281      * @return the logger that tries to execute logging (delegateLogger)
282      */
283     public static DelegateLogger always()
284     {
285         return DELEGATE_LOGGER;
286     }
287 
288     /**
289      * Check whether the provided category needs to be logged. Note that when LogCategory.ALL is contained in the categories,
290      * filter will return true.
291      * @param logCategory LogCategory; the category to check for.
292      * @return the logger that either tries to log (delegateLogger), or returns without logging (noLogger)
293      */
294     public static DelegateLogger filter(final LogCategory logCategory)
295     {
296         if (LOG_CATEGORIES.contains(LogCategory.ALL))
297             return DELEGATE_LOGGER;
298         if (LOG_CATEGORIES.contains(logCategory))
299             return DELEGATE_LOGGER;
300         return NO_LOGGER;
301     }
302 
303     /**
304      * Check whether the provided categories contain one or more categories that need to be logged. Note that when
305      * LogCategory.ALL is contained in the categories, filter will return true.
306      * @param logCategories LogCategory...; elements or array with the categories to check for
307      * @return the logger that either tries to log (delegateLogger), or returns without logging (noLogger)
308      */
309     public static DelegateLogger filter(final LogCategory... logCategories)
310     {
311         if (LOG_CATEGORIES.contains(LogCategory.ALL))
312             return DELEGATE_LOGGER;
313         for (LogCategory logCategory : logCategories)
314         {
315             if (LOG_CATEGORIES.contains(logCategory))
316                 return DELEGATE_LOGGER;
317         }
318         return NO_LOGGER;
319     }
320 
321     /**
322      * Check whether the provided categories contain one or more categories that need to be logged. Note that when
323      * LogCategory.ALL is contained in the categories, filter will return true.
324      * @param logCategories Set&lt;LogCategory&gt;; the categories to check for
325      * @return the logger that either tries to log (delegateLogger), or returns without logging (noLogger)
326      */
327     public static DelegateLogger filter(final Set<LogCategory> logCategories)
328     {
329         if (LOG_CATEGORIES.contains(LogCategory.ALL))
330             return DELEGATE_LOGGER;
331         for (LogCategory logCategory : logCategories)
332         {
333             if (LOG_CATEGORIES.contains(logCategory))
334                 return DELEGATE_LOGGER;
335         }
336         return NO_LOGGER;
337     }
338 
339     /**
340      * The conditional filter that will result in the usage of a DelegateLogger.
341      * @param condition boolean; the condition that should be evaluated
342      * @return the logger that further processes logging (DelegateLogger)
343      */
344     public static DelegateLogger when(final boolean condition)
345     {
346         if (condition)
347             return DELEGATE_LOGGER;
348         return NO_LOGGER;
349     }
350 
351     /**
352      * The conditional filter that will result in the usage of a DelegateLogger.
353      * @param supplier BooleanSupplier; the function evaluating the condition
354      * @return the logger that further processes logging (DelegateLogger)
355      */
356     public static DelegateLogger when(final BooleanSupplier supplier)
357     {
358         if (supplier.getAsBoolean())
359             return DELEGATE_LOGGER;
360         return NO_LOGGER;
361     }
362 
363     /* ************************************ DELEGATE LOGGER ***************************************/
364 
365     /**
366      * DelegateLogger class that takes care of actually logging the message and/or exception. <br>
367      * <p>
368      * Copyright (c) 2003-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights
369      * reserved.<br>
370      * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
371      * </p>
372      * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
373      */
374     public static class DelegateLogger
375     {
376         /** Should we try to log or not? */
377         private final boolean log;
378 
379         /**
380          * @param log boolean; indicate whether we should log or not.
381          */
382         public DelegateLogger(final boolean log)
383         {
384             this.log = log;
385         }
386 
387         /**
388          * The conditional filter that will result in the usage of a DelegateLogger.
389          * @param condition boolean; the condition that should be evaluated
390          * @return the logger that further processes logging (DelegateLogger)
391          */
392         public DelegateLogger when(final boolean condition)
393         {
394             if (this.log && condition)
395                 return this;
396             return CategoryLogger.NO_LOGGER;
397         }
398 
399         /**
400          * The conditional filter that will result in the usage of a DelegateLogger.
401          * @param supplier BooleanSupplier; the function evaluating the condition
402          * @return the logger that further processes logging (DelegateLogger)
403          */
404         public DelegateLogger when(final BooleanSupplier supplier)
405         {
406             if (this.log && supplier.getAsBoolean())
407                 return this;
408             return CategoryLogger.NO_LOGGER;
409         }
410 
411         /* ****************************************** TRACE ******************************************/
412 
413         /**
414          * Create a trace log entry that will always be output, independent of LogCategory settings.
415          * @param object Object; the result of the <code>toString()</code> method of <code>object</code> will be logged
416          */
417         public void trace(final Object object)
418         {
419             if (this.log)
420                 LogEntryForwarder.forward(1, Level.TRACE, object);
421         }
422 
423         /**
424          * Create a trace log entry that will always be output, independent of LogCategory settings.
425          * @param message String; the message to log
426          */
427         public void trace(final String message)
428         {
429             if (this.log)
430                 LogEntryForwarder.forward(1, Level.TRACE, message);
431         }
432 
433         /**
434          * Create a trace log entry that will always be output, independent of LogCategory settings.
435          * @param message String; the message to be logged, where {} entries will be replaced by arguments
436          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
437          */
438         public void trace(final String message, final Object... arguments)
439         {
440             if (this.log)
441                 LogEntryForwarder.forward(1, Level.TRACE, message, arguments);
442         }
443 
444         /**
445          * Create a trace log entry that will always be output, independent of LogCategory settings.
446          * @param exception Throwable; the exception to log
447          */
448         public void trace(final Throwable exception)
449         {
450             if (this.log)
451                 LogEntryForwarder.forward(1, Level.TRACE, exception);
452         }
453 
454         /**
455          * Create a trace log entry that will always be output, independent of LogCategory settings.
456          * @param exception Throwable; the exception to log
457          * @param message String; the message to log
458          */
459         public void trace(final Throwable exception, final String message)
460         {
461             if (this.log)
462                 LogEntryForwarder.forward(1, Level.TRACE, exception, message);
463         }
464 
465         /**
466          * Create a trace log entry that will always be output, independent of LogCategory settings.
467          * @param exception Throwable; the exception to log
468          * @param message String; the message to log, where {} entries will be replaced by arguments
469          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
470          */
471         public void trace(final Throwable exception, final String message, final Object... arguments)
472         {
473             if (this.log)
474                 LogEntryForwarder.forward(1, Level.TRACE, exception, message, arguments);
475         }
476 
477         /* ****************************************** DEBUG ******************************************/
478 
479         /**
480          * Create a debug log entry that will always be output, independent of LogCategory settings.
481          * @param object Object; the result of the <code>toString()</code> method of <code>object</code> will be logged
482          */
483         public void debug(final Object object)
484         {
485             if (this.log)
486                 LogEntryForwarder.forward(1, Level.DEBUG, object);
487         }
488 
489         /**
490          * Create a debug log entry that will always be output, independent of LogCategory settings.
491          * @param message String; the message to log
492          */
493         public void debug(final String message)
494         {
495             if (this.log)
496                 LogEntryForwarder.forward(1, Level.DEBUG, message);
497         }
498 
499         /**
500          * Create a debug log entry that will always be output, independent of LogCategory settings.
501          * @param message String; the message to be logged, where {} entries will be replaced by arguments
502          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
503          */
504         public void debug(final String message, final Object... arguments)
505         {
506             if (this.log)
507                 LogEntryForwarder.forward(1, Level.DEBUG, message, arguments);
508         }
509 
510         /**
511          * Create a debug log entry that will always be output, independent of LogCategory settings.
512          * @param exception Throwable; the exception to log
513          */
514         public void debug(final Throwable exception)
515         {
516             if (this.log)
517                 LogEntryForwarder.forward(1, Level.DEBUG, exception);
518         }
519 
520         /**
521          * Create a debug log entry that will always be output, independent of LogCategory settings.
522          * @param exception Throwable; the exception to log
523          * @param message String; the message to log
524          */
525         public void debug(final Throwable exception, final String message)
526         {
527             if (this.log)
528                 LogEntryForwarder.forward(1, Level.DEBUG, exception, message);
529         }
530 
531         /**
532          * Create a debug log entry that will always be output, independent of LogCategory settings.
533          * @param exception Throwable; the exception to log
534          * @param message String; the message to log, where {} entries will be replaced by arguments
535          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
536          */
537         public void debug(final Throwable exception, final String message, final Object... arguments)
538         {
539             if (this.log)
540                 LogEntryForwarder.forward(1, Level.DEBUG, exception, message, arguments);
541         }
542 
543         /* ****************************************** INFO ******************************************/
544 
545         /**
546          * Create a info log entry that will always be output, independent of LogCategory settings.
547          * @param object Object; the result of the <code>toString()</code> method of <code>object</code> will be logged
548          */
549         public void info(final Object object)
550         {
551             if (this.log)
552                 LogEntryForwarder.forward(1, Level.INFO, object);
553         }
554 
555         /**
556          * Create a info log entry that will always be output, independent of LogCategory settings.
557          * @param message String; the message to log
558          */
559         public void info(final String message)
560         {
561             if (this.log)
562                 LogEntryForwarder.forward(1, Level.INFO, message);
563         }
564 
565         /**
566          * Create a info log entry that will always be output, independent of LogCategory settings.
567          * @param message String; the message to be logged, where {} entries will be replaced by arguments
568          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
569          */
570         public void info(final String message, final Object... arguments)
571         {
572             if (this.log)
573                 LogEntryForwarder.forward(1, Level.INFO, message, arguments);
574         }
575 
576         /**
577          * Create a info log entry that will always be output, independent of LogCategory settings.
578          * @param exception Throwable; the exception to log
579          */
580         public void info(final Throwable exception)
581         {
582             if (this.log)
583                 LogEntryForwarder.forward(1, Level.INFO, exception);
584         }
585 
586         /**
587          * Create a info log entry that will always be output, independent of LogCategory settings.
588          * @param exception Throwable; the exception to log
589          * @param message String; the message to log
590          */
591         public void info(final Throwable exception, final String message)
592         {
593             if (this.log)
594                 LogEntryForwarder.forward(1, Level.INFO, exception, message);
595         }
596 
597         /**
598          * Create a info log entry that will always be output, independent of LogCategory settings.
599          * @param exception Throwable; the exception to log
600          * @param message String; the message to log, where {} entries will be replaced by arguments
601          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
602          */
603         public void info(final Throwable exception, final String message, final Object... arguments)
604         {
605             if (this.log)
606                 LogEntryForwarder.forward(1, Level.INFO, exception, message, arguments);
607         }
608 
609         /* ****************************************** WARN ******************************************/
610 
611         /**
612          * Create a warn log entry that will always be output, // TODO: explain better independent of LogCategory settings.
613          * @param object Object; the result of the <code>toString()</code> method of <code>object</code> will be logged
614          */
615         public void warn(final Object object)
616         {
617             if (this.log)
618                 LogEntryForwarder.forward(1, Level.WARNING, object);
619         }
620 
621         /**
622          * Create a warn log entry that will always be output, independent of LogCategory settings.
623          * @param message String; the message to log
624          */
625         public void warn(final String message)
626         {
627             if (this.log)
628                 LogEntryForwarder.forward(1, Level.WARNING, message);
629         }
630 
631         /**
632          * Create a warn log entry that will always be output, independent of LogCategory settings.
633          * @param message String; the message to be logged, where {} entries will be replaced by arguments
634          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
635          */
636         public void warn(final String message, final Object... arguments)
637         {
638             if (this.log)
639                 LogEntryForwarder.forward(1, Level.WARNING, message, arguments);
640         }
641 
642         /**
643          * Create a warn log entry that will always be output, independent of LogCategory settings.
644          * @param exception Throwable; the exception to log
645          */
646         public void warn(final Throwable exception)
647         {
648             if (this.log)
649                 LogEntryForwarder.forward(1, Level.WARNING, exception);
650         }
651 
652         /**
653          * Create a warn log entry that will always be output, independent of LogCategory settings.
654          * @param exception Throwable; the exception to log
655          * @param message String; the message to log
656          */
657         public void warn(final Throwable exception, final String message)
658         {
659             if (this.log)
660                 LogEntryForwarder.forward(1, Level.WARNING, exception, message);
661         }
662 
663         /**
664          * Create a warn log entry that will always be output, independent of LogCategory settings.
665          * @param exception Throwable; the exception to log
666          * @param message String; the message to log, where {} entries will be replaced by arguments
667          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
668          */
669         public void warn(final Throwable exception, final String message, final Object... arguments)
670         {
671             if (this.log)
672                 LogEntryForwarder.forward(1, Level.WARNING, exception, message, arguments);
673         }
674 
675         /* ****************************************** ERROR ******************************************/
676 
677         /**
678          * Create a error log entry that will always be output, independent of LogCategory settings.
679          * @param object Object; the result of the <code>toString()</code> method of <code>object</code> will be logged
680          */
681         public void error(final Object object)
682         {
683             if (this.log)
684                 LogEntryForwarder.forward(1, Level.ERROR, object);
685         }
686 
687         /**
688          * Create a error log entry that will always be output, independent of LogCategory settings.
689          * @param message String; the message to log
690          */
691         public void error(final String message)
692         {
693             if (this.log)
694                 LogEntryForwarder.forward(1, Level.ERROR, message);
695         }
696 
697         /**
698          * Create a error log entry that will always be output, independent of LogCategory settings.
699          * @param message String; the message to be logged, where {} entries will be replaced by arguments
700          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
701          */
702         public void error(final String message, final Object... arguments)
703         {
704             if (this.log)
705                 LogEntryForwarder.forward(1, Level.ERROR, message, arguments);
706         }
707 
708         /**
709          * Create a error log entry that will always be output, independent of LogCategory settings.
710          * @param exception Throwable; the exception to log
711          */
712         public void error(final Throwable exception)
713         {
714             if (this.log)
715                 LogEntryForwarder.forward(1, Level.ERROR, exception);
716         }
717 
718         /**
719          * Create a error log entry that will always be output, independent of LogCategory settings.
720          * @param exception Throwable; the exception to log
721          * @param message String; the message to log
722          */
723         public void error(final Throwable exception, final String message)
724         {
725             if (this.log)
726                 LogEntryForwarder.forward(1, Level.ERROR, exception, message);
727         }
728 
729         /**
730          * Create a error log entry that will always be output, independent of LogCategory settings.
731          * @param exception Throwable; the exception to log
732          * @param message String; the message to log, where {} entries will be replaced by arguments
733          * @param arguments Object...; the arguments to substitute for the {} entries in the message string
734          */
735         public void error(final Throwable exception, final String message, final Object... arguments)
736         {
737             if (this.log)
738                 LogEntryForwarder.forward(1, Level.ERROR, exception, message, arguments);
739         }
740     }
741 }