| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| |
| <head> |
| <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> |
| <title>SLF4J FAQ</title> |
| <link rel="stylesheet" type="text/css" media="screen" href="css/site.css" /> |
| <link rel="stylesheet" type="text/css" href="css/prettify.css" /> |
| </head> |
| <body onload="prettyPrint()"> |
| |
| <script type="text/javascript" src="js/prettify.js"></script> |
| <script type="text/javascript">prefix='';</script> |
| |
| <script src="templates/header.js" type="text/javascript"></script> |
| <div id="left"> |
| <script src="templates/left.js" type="text/javascript"></script> |
| </div> |
| |
| <div id="content"> |
| |
| <h2><a name="top">Frequently Asked Questions about SLF4J</a></h2> |
| |
| <p><b>Generalities</b></p> |
| |
| <ol type="1"> |
| <li><a href="#what_is">What is SLF4J?</a></li> |
| |
| <li><a href="#when">When should SLF4J be used?</a></li> |
| |
| <li><a href="#yet_another_facade"> Is SLF4J yet another loggingfacade?</a></li> |
| |
| <li><a href="#why_new_project"> If SLF4J fixes JCL, then why |
| wasn't the fix made in JCL instead of creating a new project? |
| </a> |
| </li> |
| |
| <li><a href="#need_to_recompile"> When using SLF4J, do I have to |
| recompile my application to switch to a different logging |
| system? |
| </a> |
| </li> |
| |
| <li><a href="#requirements">What are SLF4J's requirements?</a></li> |
| |
| <li><a href="#compatibility">Are SLF4J versions backward |
| compatible?</a></li> |
| |
| <li><a href="#IllegalAccessError">I am getting |
| <code>IllegalAccessError</code> exceptions when using SLF4J. Why |
| is that?</a></li> |
| |
| |
| <li> |
| <a href="#license">Why is SLF4J licensed under X11 type |
| license instead of the Apache Software License? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#where_is_binding">Where can I get a particular |
| SLF4J binding? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#configure_logging">Should my library attempt to |
| configure logging? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#optional_dependency">In order to reduce the number of |
| dependencies of our software we would like to make SLF4J an |
| optional dependency. Is that a good idea? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#maven2">What about Maven 2 transitive |
| dependencies? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#excludingJCL">How do I exclude commons-logging as a |
| Maven dependency? |
| </a> |
| </li> |
| </ol> |
| |
| |
| <b>About the SLF4J API</b> |
| |
| <ol type="1"> |
| |
| <li> |
| <a href="#string_or_object"> Why don't the printing methods |
| in the Logger interface accept message of type Object, but only |
| messages of type String? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#exception_message"> |
| Can I log an exception without an accompanying message? |
| </a> |
| </li> |
| |
| |
| <li> |
| <a href="#logging_performance"> What is the fastest way of |
| (not) logging? |
| </a> |
| </li> |
| |
| <li> |
| <a href="#string_contents"> How can I log the string contents |
| of a single (possibly complex) object? |
| </a> |
| </li> |
| |
| |
| <li><a href="#fatal"> Why doesn't the |
| <code>org.slf4j.Logger</code> interface have methods for the |
| FATAL level? </a></li> |
| |
| <li><a href="#trace">Why was the TRACE level introduced only in |
| SLF4J version 1.4.0? </a></li> |
| |
| <li><a href="#i18n">Does the SLF4J logging API support I18N |
| (internationalization)? </a></li> |
| |
| |
| <li><a href="#noLoggerFactory">Is it possible to retrieve loggers |
| without going through the static methods in |
| <code>LoggerFactory</code>? </a></li> |
| |
| <li><a href="#paramException">In the presence of an |
| exception/throwable, is it possible to parametizere a logging |
| statement?</a></li> |
| |
| </ol> |
| |
| |
| |
| <b>Implementing the SLF4J API</b> |
| |
| <ol type="1"> |
| |
| <li><a href="#slf4j_compatible"> How do I make my logging |
| framework SLF4J compatible? </a></li> |
| |
| <li><a href="#marker_interface"> How can my logging system add |
| support for the <code>Marker</code> interface? </a></li> |
| |
| <li><a href="#version_checks">How does SLF4J's version check |
| mechanism work? </a></li> |
| |
| |
| </ol> |
| |
| |
| <b>General questions about logging</b> |
| |
| |
| <ol type="1"> |
| |
| <li><a href="#declared_static"> Should Logger members of a class |
| be declared as static? </a></li> |
| |
| |
| <li><a href="#declaration_pattern">Is there a recommended idiom |
| for declaring a loggers in a class?</a></li> |
| |
| </ol> |
| |
| <h2>Generalities</h2> |
| |
| <dl> |
| <dt><a name="what_is" href="#what_is">What is SLF4J?</a></dt> |
| <dd> |
| <p>SLF4J is a simple facade for logging systems allowing the |
| end-user to plug-in the desired logging system at deployment |
| time. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| <dt><a name="when" href="#when"> When should SLF4J be used? |
| </a></dt> |
| |
| <dd> |
| <p>In short, libraries and other embedded components should |
| consider SLF4J for their logging needs because libraries |
| cannot afford to impose their choice of logging system on the |
| end-user. On the other hand, it does not necessarily make |
| sense for stand-alone applications to use SLF4J. Stand-alone |
| applications can invoke the logging system of their choice |
| directly. |
| </p> |
| |
| <p>SLF4J is only a facade, meaning that it does not provide a |
| complete logging solution. Operations such as configuring |
| appenders or setting logging levels cannot be performed with |
| SLF4J. Thus, at some point in time, any non-trivial |
| application will need to directly invoke the underlying |
| logging system. In other words, complete independence from the |
| API underlying logging system is not possible for a |
| stand-alone application. Nevertheless, SLF4J reduces the |
| impact of this dependence to near-painless levels. |
| </p> |
| |
| <p>Suppose that your CRM application uses log4j for its |
| logging. However, one of your important clients request that |
| logging be performed through JDK 1.4 logging. If your |
| application is riddled with thousands of direct log4j calls, |
| migration to JDK 1.4 would be a relatively lengthy and |
| error-prone process. Even worse, you would potentially need to |
| maintain two versions of your CRM software. Had you been |
| invoking SLF4J API instead of log4j, the migration could be |
| completed in a matter of minutes by replacing one jar file with |
| another. |
| </p> |
| |
| <p>SLF4J lets component developers to defer the choice of the |
| logging system to the end-user but eventually a choice needs |
| to be made. |
| </p> |
| |
| <hr /> |
| |
| </dd> |
| |
| <dt> |
| <a name="yet_another_facade" href="#yet_another_facade"> |
| Is SLF4J yet another logging facade? </a> |
| </dt> |
| |
| <dd> |
| <p>SLF4J is conceptually very similar to JCL. As such, it can |
| be thought of as yet another logging facade. However, SLF4J is |
| much simpler in design and arguably more robust. In a |
| nutshell, SLF4J avoid the class loader issues that plague JCL. |
| </p> |
| |
| <hr /> |
| |
| </dd> |
| <dt> |
| <a name="why_new_project" href="#why_new_project"> |
| If SLF4J fixes JCL, then why wasn't the fix made in JCL |
| instead of creating a new project? |
| </a> |
| </dt> |
| |
| <dd> |
| <p>This is a very good question. First, SLF4J static binding |
| approach is very simple, perhaps even laughably so. It was |
| not easy to convince developers of the validity of that |
| approach. It is only after SLF4J was released and started to |
| become accepted did it gain respectability in the relevant |
| community. |
| </p> |
| |
| <p>Second, SLF4J offers two enhancements which tend to be |
| underestimated. Parameterized log messages solve an important |
| problem associated with logging performance, in a pragmatic |
| way. Marker objects, which are supported by the |
| <code>org.slf4j.Logger</code> interface, pave the way for |
| adoption of advanced logging systems and still leave the door |
| open to switching back to more traditional logging systems if |
| need be. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| <dt> |
| <a name="need_to_recompile" href="#need_to_recompile"> When |
| using SLF4J, do I have to recompile my application to switch |
| to a different logging system? </a> |
| </dt> |
| |
| <dd> |
| <p>No, you do not need to recompile your application. You can |
| switch to a different logging system by removing the previous |
| SLF4J binding and replacing it with the binding of your choice. |
| </p> |
| |
| <p>For example, if you were using the NOP implementation and |
| would like to switch to log4j version 1.2, simply replace |
| <em>slf4j-nop.jar</em> with <em>slf4j-log4j12.jar</em> on |
| your class path but do not forget to add log4j-1.2.x.jar as |
| well. Want to switch to JDK 1.4 logging? Just replace |
| <em>slf4j-log4j12.jar</em> with <em>slf4j-jdk14.jar</em>. |
| </p> |
| |
| <hr /> |
| </dd> |
| <dt> |
| <a name="requirements" href="#requirements">What are SLF4J's |
| requirements?</a> |
| </dt> |
| |
| <dd> |
| |
| <p>In principle, SLF4J requires JDK 1.3 or above, in |
| particular slf4j-api is compatible with JDK 1.3. However, |
| the underlying logging system might have a higher |
| requirement. For instance, the <em>slf4j-jdk14</em> binding |
| requires JDK 1.4. Logback requires JDK 1.5. |
| </p> |
| |
| <p> </p> |
| |
| <table border="1"> |
| <tr align="left"> |
| <th>Binding</th> |
| <th>Requirements</th> |
| </tr> |
| |
| <tr> |
| <td>slf4j-nop</td> |
| <td>JDK 1.3</td> |
| </tr> |
| <tr> |
| <td>slf4j-simple</td> |
| <td>JDK 1.3</td> |
| </tr> |
| |
| <tr> |
| <td>slf4j-log4j12</td> |
| <td align="left">JDK 1.3, plus any other library |
| dependencies required by the log4j appenders in use</td> |
| </tr> |
| <tr> |
| <td>slf4j-jdk14</td> |
| <td>JDK 1.4 or above</td> |
| </tr> |
| <tr> |
| <td>logback-classic</td> |
| <td>JDK 1.5 or above, plus any other library dependencies |
| required by the logback appenders in use</td> |
| </tr> |
| |
| </table> |
| |
| <hr /> |
| </dd> |
| |
| <!-- ==================================================== --> |
| <!-- entry has order dependees --> |
| <dt><a name="compatibility" href="#compatibility">Are SLF4J |
| versions backward compatible?</a> |
| </dt> |
| |
| <dd> |
| <p>With rare theoretical exceptions, SLF4J versions are backward |
| compatible. This means than you can upgrade from SLF4J version |
| 1.0 to any later version without problems.</p> |
| |
| <p>However, while the SLF4J API is very stable from the client's |
| perspective, SLF4J bindings such as slf4j-simple or |
| slf4j-log4j12 may require a specific version of slf4j-api. <span |
| class="redBold">Mixing different versions of slf4j artifacts can |
| be problematic and is strongly discouraged. </span> For |
| instance, if you are using slf4j-api-1.5.6.jar, then you should |
| also use slf4j-simple-1.5.6.jar, using slf4j-simple-1.4.2.jar |
| will not work. |
| </p> |
| |
| <p>At initialization time, if SLF4J suspects that there may be a |
| version mismatch problem, it emits a warning about the said |
| mismatch. For the exact details of the version mismatch |
| detection mechanism, please refer to the <a |
| href="#version_checks">relevant entry</a> in this FAQ. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| <!-- ==================================================== --> |
| |
| <dt><a name="IllegalAccessError" href="#IllegalAccessError">I am getting |
| <code>IllegalAccessError</code> exceptions when using SLF4J. Why |
| is that?</a> |
| </dt> |
| |
| <dd> |
| |
| <p>Here are the exception details.</p> |
| |
| <pre class="source">Exception in thread "main" java.lang.IllegalAccessError: tried to access field |
| org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory |
| at org.slf4j.LoggerFactory.<clinit>(LoggerFactory.java:60)</pre> |
| |
| <p>This error is caused by the static initilizer of the |
| <code>LoggerFactory</code> class attempting to directly access |
| the SINGLETON field of |
| <code>org.slf4j.impl.StaticLoggerBinder</code>. While this was |
| allowed in SLF4J 1.5.5 and earlier, in 1.5.6 and later the |
| SINGLETON field has been marked as private access. |
| </p> |
| |
| |
| <p>If you get the exception shown above, then you are using an |
| older version of slf4j-api, e.g. 1.4.3, with a new version of a |
| slf4j binding, e.g. 1.5.6. Typically, this occurs when your |
| Maven <em>pom.ml</em> file incoprporates hibernate 3.3.0 which |
| declares a dependency on slf4j-api version 1.4.2. If your |
| <em>pom.xml</em> declares a dependency on an slf4j binding, say |
| slf4j-log4j12 version 1.5.6, then you will get illegal access |
| errors. |
| </p> |
| |
| <p>To see which version of slfj4-api is pulled in by Maven, use |
| the maven dependency plugin as follows.</p> |
| |
| <p class="source">mvn dependency:tree</p> |
| |
| <p>If you are usig Eclipse, please do not rely on the dependency |
| tree shown by <a |
| href="http://m2eclipse.codehaus.org/">m2eclipse</a>.</p> |
| |
| <p>In your <em>pom.xml</em> file, excplicitly declaring a |
| dependecy on slf4j-api matching the version of the declared |
| binding will make the problem go away. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| |
| <!-- ==================================================== --> |
| |
| <dt> |
| <a name="license" href="#license"> |
| Why is SLF4J licensed under X11 type license instead of the |
| Apache Software License? |
| </a> |
| </dt> |
| |
| <dd> |
| <p>SLF4J is licensed under a permissive X11 type license |
| instead of the <a |
| href="http://www.apache.org/licenses/">ASL</a> or the <a |
| href="http://www.gnu.org/copyleft/lesser.html">LGPL</a> |
| because the X11 license is deemed by both the Apache Software |
| Foundation as well as the Free Software Foundation as |
| compatible with their respective licenses. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| <!-- ==================================================== --> |
| <dt> |
| <a name="where_is_binding" href="#where_is_binding"> |
| Where can I get a particular SLF4J binding? |
| </a> |
| </dt> |
| |
| <dd> |
| |
| <p>SLF4J bindings for <a |
| href="api/org/slf4j/impl/SimpleLogger.html">SimpleLogger</a>, |
| <a href="api/org/slf4j/impl/NOPLogger.html">NOPLogger</a>, <a |
| href="api/org/slf4j/impl/Log4jLoggerAdapter.html">Log4jLoggerAdapter</a> |
| and <a |
| href="api/org/slf4j/impl/JDK14LoggerAdapter.html">JDK14LoggerAdapter</a> |
| are contained within the files <em>slf4j-nop.jar</em>, |
| <em>slf4j-simple.jar</em>, <em>slf4j-log4j12.jar</em>, and |
| <em>slf4j-jdk14.jar</em>. These files ship with the <a |
| href="download.html">official SLF4J distribution</a>. Please |
| note that all bindings depend on <em>slf4j-api.jar</em>. |
| </p> |
| |
| <p>The binding for logback-classic ships with the <a |
| href="http://logback.qos.ch/download.html">logback |
| distribution</a>. However, as with all other bindings, the |
| logback-classic binding requires <em>slf4j-api.jar</em>. |
| </p> |
| |
| <hr /> |
| </dd> |
| |
| <dt><a name="configure_logging" href="#configure_logging"> |
| Should my library attempt to configure logging? </a> |
| </dt> |
| |
| <dd> |
| <p><b>Embedded components such as libraries not only do not need |
| to configure the underlying logging framework, they really |
| should not do so</b>. They should invoke SLF4J to log but should |
| let the end-user configure the logging environment. When |
| embedded components try to configure logging on their own, they |
| often override the end-user's wishes. At the end of the day, it |
| is the end-user who has to read the logs and process them. She |
| should be the person to decide how she wants her logging |
| configured. |
| </p> |
| |
| <hr/> |
| </dd> |
| |
| <!-- ======================================================= --> |
| |
| <dt> |
| <a name="optional_dependency" href="#optional_dependency">In |
| order to reduce the number of dependencies of our software we |
| would like to make SLF4J an optional dependency. Is that a good |
| idea? |
| </a> |
| </dt> |
| |
| <dd> |
| <p><a |
| href="http://stackoverflow.com/questions/978670/is-it-worth-wrapping-a-logging-framework-in-an-additional-layer">This |
| question pops up</a> whenever a software project reaches a point |
| where it needs to devise a logging strategy. |
| </p> |
| |
| <p>Let Wombat be a software library with very few |
| dependencies. If SLF4J is chosen as Wombat's logging API, then a |
| new dependency on <em>slf4j-api.jar</em> will be added to |
| Wombat's list of dependencies. Given that writing a logging |
| wrapper does not seem that hard, some developers will be tempted |
| to wrap SLF4J and link with it only if it is already present on |
| the classpath, making SLF4J an optional dependency of Wombat. In |
| addition to solving the dependency problem, the wrapper will |
| isolate Wombat from SLF4J's API ensuring that logging in Wombat |
| is future-proof. |
| </p> |
| |
| <p>On the other hand, any SLF4J-wrapper by definition depends on |
| SLF4J. It is bound to have the same general API. If in the |
| future a new and significantly different logging API comes |
| along, code that uses the wrapper will be equally difficult to |
| migrate to the new API as code that used SLF4J directly. Thus, |
| the wrapper is not likely to future-proof your code, but to make |
| it heavier by adding an additional indirection on top SLF4J |
| which is an indirection in itself. It's actually a lot worse |
| than that. Wrappers will need to depend on certain internal |
| SLF4J interfaces which change from time to time, typical on each |
| major series, contrary to the client-facing API which never |
| changes. Thus, wrappers are usually dependent on the major |
| version they were compiled with. A wrapper compiled against |
| SLF4J version 1.5.x will not work with SLF4J 1.6 whereas client |
| code using <code>org.slf4j.Logger</code>, |
| <code>LoggerFactory</code>, <code>MarkerFactory</code>, |
| <code>org.slf4j.Marker</code>, and <code>MDC</code> will work |
| fine with any SLF4J version from version 1.0 and onwards. |
| </p> |
| |
| <p>It is reasonable to assume that in most projects Wombat will |
| be one dependency among many. If each library had its own |
| logging wrapper, then each wrapper would presumably need to be |
| configured separately. Thus, instead of having to deal with one |
| logging framework, namely SLF4J, the user of Wombat would have |
| to detail with Wombat's logging wrapper as well. The problem |
| will be compounded by each framework that comes up with its own |
| wrapper in order to make SLF4J optional. (Configuring or |
| dealing with the intricacies of five different logging wrappers |
| is not exactly exciting nor endearing.) |
| </p> |
| |
| <p>Some projects try to detect the presence of SLF4J on the |
| class path and switch to it if present. While this approach |
| seems transperent enough, it will result in erroneous location |
| information. Underlying logging frameworks will print the |
| location (class name and line number) of the wrapper instead of |
| the real caller. Then there is the question of API coverage as |
| SLF4J support MDC and markers in addition to parameterized |
| logging. While one can come up with a seemingly working |
| SLF4J-wrapper within hours, many technical issues will emerge |
| over time which Wombat developers will have to deal with. Note |
| that SLF4J has evolved over several years and has 170 bug |
| reports filed against it.</p> |
| |
| <p>For the above reasons, developers of frameworks should resist |
| the temptation to write their own logging wrapper. Not only is |
| it a waste of time of the developer, it will actually make life |
| more difficult for the users of said frameworks and make logging |
| code paradoxically more vulnerable to change. |
| </p> |
| </dd> |
| |
| |
| <!-- ======================================================= --> |
| |
| <dt><a name="maven2" href="#maven2">What about Maven2 |
| transitive dependencies? </a> |
| </dt> |
| |
| <dd> |
| <p>As an author of a library built with Maven2, you might |
| want to test your application using a binding, say |
| slf4j-log4j12 or logback-classic, without forcing log4j or |
| logback-classic as a dependency upon your users. As of SLF4J |
| version 1.3, this quite easy to accomplish. But first, since |
| your library's code depends on the SLF4J API you will need to |
| declare slf4j-api as a compile-time (default scope) |
| dependency. |
| </p> |
| <pre class="prettyprint source"><dependency> |
| <groupId>org.slf4j</groupId> |
| <artifactId>slf4j-api</artifactId> |
| <version>${project.version}</version> |
| </dependency></pre> |
| |
| <p>Limiting the transitivity of the SLF4J binding used in your |
| tests can be accomplished by declaring the scope of the |
| SLF4J-binding dependency as "test". Here is an example:</p> |
| |
| <pre class="prettyprint source"><dependency> |
| <groupId>org.slf4j</groupId> |
| <artifactId>slf4j-log4j12</artifactId> |
| <version>${project.version}</version> |
| <b><scope>test</scope></b> |
| </dependency></pre> |
| |
| <p>Thus, as far as your users are concerned you are exporting |
| slf4j-api as a transitive dependency of your library, but not |
| any SLF4J-binding or any underlying logging system. |
| </p> |
| |
| <p>Note that as of SLF4J version 1.6, in the absence of an SLF4J |
| binding, slf4j-api will default to a no-operation |
| implementation. |
| </p> |
| |
| <hr/> |
| |
| </dd> |
| |
| |
| <dt> |
| <a name="excludingJCL">How do I exclude commons-logging as a |
| Maven dependency? |
| </a> |
| </dt> |
| |
| <dd> |
| <p>A large number of Maven projects declare commons-logging as a |
| dependency. Thus, if you wish to migrate to SLF4J or use |
| jcl-over-slf4j, you would need to declare a commons-logging |
| exclusion in all of your dependencies which transitively depend |
| on commons-logging. This can be an error prone process. To |
| alleviate the pain, Erik van Oosten has developed a <a |
| href="http://day-to-day-stuff.blogspot.com/2007/10/announcement-version-99-does-not-exist.html">clever |
| hack around this problem.</a> |
| </p> |
| |
| <p>Alternatively, commons-logging can be rather simply and |
| conveniently excluded as a dependency by declaring it in the |
| <em>provided</em> scope within the pom.xml file of your |
| project. The actual commons-logging classes would be provided by |
| jcl-over-slf4j. This translates into the following pom file |
| snippet:</p> |
| |
| <pre class="prettyprint source"><dependency> |
| <groupId>commons-logging</groupId> |
| <artifactId>commons-logging</artifactId> |
| <version>1.1.1</version> |
| <scope>provided</scope> |
| </dependency> |
| |
| <dependency> |
| <groupId>org.slf4j</groupId> |
| <artifactId>jcl-over-slf4j</artifactId> |
| <version>${project.version}</version> |
| </dependency></pre> |
| |
| |
| </dd> |
| |
| |
| </dl> |
| |
| |
| <h2>About the SLF4J API</h2> |
| |
| <dl> |
| |
| <dt><a name="string_or_object" href="#string_or_object"> Why |
| don't the printing methods in the Logger interface accept |
| message of type Object, but only messages of type String? </a> |
| </dt> |
| |
| <dd> |
| |
| <p>In SLF4J 1.0beta4, the printing methods such as debug(), |
| info(), warn(), error() in the <a |
| href="api/org/slf4j/Logger.html">Logger interface</a> were |
| modified so as to accept only messages of type String |
| instead of Object. |
| </p> |
| |
| <p>Thus, the set of printing methods for the DEBUG level |
| became:</p> |
| |
| <pre class="prettyprint source">debug(String msg); |
| debug(String format, Object arg); |
| debug(String format, Object arg1, Object arg2); |
| debug(String msg, Throwable t);</pre> |
| |
| <p>Previously, the first argument in the above methods was of |
| type <code>Object</code>.</p> |
| |
| <p>This change enforces the notion that logging systems are |
| about decorating and handling messages of type String, and not |
| any arbitrary type (Object). |
| </p> |
| |
| <p>Just as importantly, the new set of method signatures offer |
| a clearer differentiation between the overloaded methods |
| whereas previously the choice of the invoked method due to |
| Java overloading rules were not always easy to follow.</p> |
| |
| <p>It was also easy to make mistakes. For example, previously |
| it was legal to write:</p> |
| |
| <pre class="prettyprint source">logger.debug(new Exception("some error"));</pre> |
| |
| <p>Unfortunately, the above call did not print the stack trace |
| of the exception. Thus, a potentially crucial piece of |
| information could be lost. When the first parameter is |
| restricted to be of type String, then only the method |
| </p> |
| |
| <pre class="prettyprint source">debug(String msg, Throwable t);</pre> |
| |
| <p>can be used to log exceptions. Note that this method |
| ensures that every logged exception is accompanied with a |
| descriptive message.</p> |
| |
| <hr /> |
| </dd> |
| |
| <dt> |
| <a name="exception_message" href="#exception_message"> |
| Can I log an exception without an accompanying message? |
| </a> |
| </dt> |
| <dd> |
| <p>In short, no.</p> |
| |
| <p>If <code>e</code> is an <code>Exception</code>, and you |
| would like to log an exception at the ERROR level, you must |
| add an accompanying message. For example,</p> |
| |
| <pre class="prettyprint source">logger.error("some accompanying message", e);</pre> |
| |
| <p>You might legitimately argue that not all exceptions have a |
| meaningful message to accompany them. Moreover, a good exception |
| should already contain a self explanatory description. The |
| accompanying message may therefore be considered redundant. |
| </p> |
| |
| |
| <p>While these are valid arguments, there are three opposing |
| arguments also worth considering. First, on many, albeit not |
| all occasions, the accompanying message can convey useful |
| information nicely complementing the description contained |
| in the exception. Frequently, at the point where the |
| exception is logged, the developer has access to more |
| contextual information than at the point where the exception |
| is thrown. Second, it is not difficult to imagine more or |
| less generic messages, e.g. "Exception caught", "Exception |
| follows", that can be used as the first argument for |
| <code>error(String msg, Throwable t)</code> invocations. |
| Third, most log output formats display the message on a |
| line, followed by the exception on a separate line. Thus, |
| the message line would look inconsistent without a message. |
| </p> |
| |
| <p>In short, if the user were allowed to log an exception |
| without an accompanying message, it would be the job of the |
| logging system to invent a message. This is actually what |
| the <a href="http://tinyurl.com/cr9kg">throwing(String |
| sourceClass, String sourceMethod, Throwable thrown)</a> |
| method in java.util.logging package does. (It decides on its |
| own that accompanying message is the string "THROW".) |
| </p> |
| |
| <p>It may initially appear strange to require an accompanying |
| message to log an exception. Nevertheless, this is common |
| practice in <em>all</em> log4j derived systems such as |
| java.util.logging, logkit, etc. and of course log4j itself. It |
| seems that the current consensus considers requiring an |
| accompanying message as a good a thing (TM). |
| </p> |
| |
| <hr/> |
| </dd> |
| |
| |
| |
| <dt> |
| <a name="logging_performance" href="#logging_performance"> |
| What is the fastest way of (not) logging?</a> |
| </dt> |
| <dd> |
| |
| <p>SLF4J supports an advanced feature called parameterized |
| logging which can significantly boost logging performance for |
| <em>disabled</em> logging statement.</p> |
| |
| <p> For some Logger <code>logger</code>, writing,</p> |
| <pre class="prettyprint source">logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</pre> |
| |
| <p>incurs the cost of constructing the message parameter, that |
| is converting both integer <code>i</code> and |
| <code>entry[i]</code> to a String, and concatenating |
| intermediate strings. This, regardless of whether the message |
| will be logged or not. |
| </p> |
| |
| <p>One possible way to avoid the cost of parameter |
| construction is by surrounding the log statement with a |
| test. Here is an example.</p> |
| |
| <pre class="prettyprint source">if(logger.isDebugEnabled()) { |
| logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); |
| }</pre> |
| |
| |
| <p>This way you will not incur the cost of parameter |
| construction if debugging is disabled for |
| <code>logger</code>. On the other hand, if the logger is |
| enabled for the DEBUG level, you will incur the cost of |
| evaluating whether the logger is enabled or not, twice: once in |
| <code>debugEnabled</code> and once in <code>debug</code>. This |
| is an insignificant overhead because evaluating a logger takes |
| less than 1% of the time it takes to actually log a statement. |
| </p> |
| |
| <p><b>Better yet, use parameterized messages</b></p> |
| |
| <p>There exists a very convenient alternative based on message |
| formats. Assuming <code>entry</code> is an object, you can write: |
| </p> |
| |
| |
| <pre class="prettyprint source">Object entry = new SomeObject(); |
| logger.debug("The entry is {}.", entry);</pre> |
| |
| <p>After evaluating whether to log or not, and only if the |
| decision is affirmative, will the logger implementation format |
| the message and replace the '{}' pair with the string value of |
| <code>entry</code>. In other words, this form does not incur |
| the cost of parameter construction in case the log statement is |
| disabled. |
| </p> |
| |
| <p>The following two lines will yield the exact same |
| output. However, the second form will outperform the first |
| form by a factor of at least 30, in case of a |
| <em>disabled</em> logging statement. |
| </p> |
| |
| <pre class="prettyprint source">logger.debug("The new entry is "+entry+"."); |
| logger.debug("The new entry is {}.", entry);</pre> |
| |
| |
| <p>A two argument variant is also available. For example, you |
| can write:</p> |
| |
| |
| <pre class="prettyprint source">logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</pre> |
| |
| <p>If three or more arguments need to be passed, you can make |
| use of the <code>Object[]</code> variant. For example, you can |
| write:</p> |
| |
| <pre class="prettyprint source">logger.debug("Value {} was inserted between {} and {}.", new Object[] {newVal, below, above});</pre> |
| |
| |
| |
| <p>Array type arguments, including multi-dimensional arrays, |
| are also supported.</p> |
| |
| <p>SLF4J uses its own message formatting implementation which |
| differs from that of the Java platform. This is justified by |
| the fact that SLF4J's implementation performs about 10 times |
| faster but at the cost of being non-standard and less |
| flexible. |
| </p> |
| |
| <p><b>Escaping the "{}" pair</b></p> |
| |
| <p>The "{}" pair is called the <em>formatting anchor</em>. It |
| serves to designate the location where arguments need to be |
| substituted within the message pattern. |
| </p> |
| |
| <p>SLF4J only cares about the <em>formatting anchor</em>, that |
| is the '{' character immediately followed by '}'. Thus, in |
| case your message contains the '{' or the '}' character, you |
| do not have to do anything special unless the '}' character |
| immediately follows '}'. For example, |
| </p> |
| |
| <pre class="prettyprint source">logger.debug("Set {1,2} differs from {}", "3");</pre> |
| |
| <p>which will print as "Set {1,2} differs from 3". </p> |
| |
| <p>You could have even written,</p> |
| <pre class="prettyprint source">logger.debug("Set {1,2} differs from {{}}", "3");</pre> |
| <p>which would have printed as "Set {1,2} differs from {3}". </p> |
| |
| <p>In the extremely rare case where the the "{}" pair occurs |
| naturally within your text and you wish to disable the special |
| meaning of the formatting anchor, then you need to escape the |
| '{' character with '\', that is the backslash character. Only |
| the '{' character should be escaped. There is no need to |
| escape the '}' character. For example, |
| </p> |
| |
| <pre class="prettyprint source">logger.debug("Set \\{} differs from {}", "3");</pre> |
| |
| <p>will print as "Set {} differs from 3". Note that within |
| Java code, the backslash cracacter needs to be written as |
| '\\'.</p> |
| |
| <p>In the rare case where the "\{}" occurs naturally in the |
| message, you can double escape the formatting anchor so that |
| it retains its original meaning. For example,</p> |
| |
| |
| <pre class="prettyprint source">logger.debug("File name is C:\\\\{}.", "file.zip");</pre> |
| <p>will print as "File name is C:\file.zip".</p> |
| |
| <hr /> |
| |
| </dd> |
| |
| |
| <dt><a name="string_contents" href="#string_contents"> How can |
| I log the string contents of a single (possibly complex) |
| object? |
| </a> |
| </dt> |
| |
| <dd> |
| <p> In relatively rare cases where the message to be logged |
| is the string form of an object, then the parameterized |
| printing method of the appropriate level can be |
| used. Assuming <code>complexObject</code> is an object of |
| certain complexity, for a log statement of level DEBUG, you |
| can write: |
| </p> |
| |
| <pre class="prettyprint source">logger.debug("{}", complexObject);</pre> |
| |
| |
| <p>The logging system will invoke |
| <code>complexObject.toString()</code> method only after it |
| has ascertained that the log statement was |
| enabled. Otherwise, the cost of |
| <code>complexObject.toString()</code> conversion will be |
| advantageously avoided. |
| </p> |
| |
| <hr /> |
| |
| </dd> |
| |
| |
| |
| |
| <dt> |
| <a name="fatal" href="#fatal"> Why doesn't the |
| <code>org.slf4j.Logger</code> interface have methods for the FATAL |
| level? </a> |
| </dt> |
| |
| <dd> |
| <p>From the stand point of a logging system, the distinction |
| between a fatal error and an error is usually not very |
| useful. Most programmers exit the application when a fatal |
| error is encountered. However, a logging library cannot (and |
| should not) decide on its own to terminate an |
| application. The initiative to exit the application must be |
| left to the developer. |
| </p> |
| |
| |
| <p>Thus, the most the FATAL level can do is to |
| <em>highlight</em> a given error as the cause for |
| application to crash. However, errors are by definition |
| exceptional events that merit attention. If a given |
| situation causes errors to be logged, the causes should be |
| attended to as soon as possible. However, if the "error" is |
| actually a normal situation which cannot be prevented but |
| merits being aware of, then it should be marked as WARN, not |
| ERROR. |
| </p> |
| |
| <p>Assuming the ERROR level designates exceptional situations |
| meriting close attention, we are inclined to believe that the |
| FATAL level is superfluous. |
| </p> |
| |
| |
| <hr /> |
| </dd> |
| |
| <dt> |
| <a name="trace" href="#trace">Why was the TRACE level introduced only in |
| SLF4J version 1.4.0? |
| </a> |
| </dt> |
| |
| <dd> |
| |
| <p>The addition of the TRACE level has been frequently and |
| hotly debated request. By studying various projects, we |
| observed that the TRACE level was used to disable logging |
| output from certain classes <em>without</em> needing to |
| configure logging for those classes. Indeed, the TRACE level |
| is by default disabled in log4j and logback as well most other |
| logging systems. The same result can be achieved by adding the |
| appropriate directives in configuration files. |
| </p> |
| |
| <p>Thus, in many of cases the TRACE level carried the same |
| semantic meaning as DEBUG. In such cases, the TRACE level |
| merely saves a few configuration directives. In other, more |
| interesting occasions, where TRACE carries a different meaning |
| than DEBUG, <a href="api/org/slf4j/Marker.html">Marker</a> |
| objects can be put to use to convey the desired |
| meaning. However, if you can't be bothered with markers and |
| wish to use a logging level lower than DEBUG, the TRACE level |
| can get the job done. |
| </p> |
| |
| <p>Note that while the cost of evaluating a disabled log |
| request is in the order of a few <code>nanoseconds</code>, the |
| use of the TRACE level (or any other level for that matter) is |
| discouraged in tight loops where the log request might be |
| evaluated millions of times. If the log request is enabled, |
| then it will overwhelm the target destination with massive |
| output. If the request is disabled, it will waste resources. |
| </p> |
| |
| <p>In short, although we still discourage the use of the TRACE |
| level because alternatives exist or because in many cases log |
| requests of level TRACE are wasteful, given that people kept |
| asking for it, we decided to bow to popular demand. |
| </p> |
| <hr/> |
| |
| </dd> |
| |
| <dt> |
| <a name="i18n" href="#i18n">Does the SLF4J logging API support |
| I18N (internationalization)? |
| </a> |
| </dt> |
| |
| <dd> |
| <p>Yes, as of version 1.5.9, SLF4J ships with a package called |
| <code>org.slf4j.cal10n</code> which adds <a |
| href="localization.html">localized/internationalized logging</a> |
| support as a thin layer built upon the <a |
| href="http://cal10n.qos.ch">CAL10N API</a>.</p> |
| |
| <hr/> |
| </dd> |
| |
| <dt><a name="noLoggerFactory" href="#noLoggerFactory">Is it |
| possible to retrieve loggers without going through the static |
| methods in <code>LoggerFactory</code>?</a> |
| </dt> |
| |
| <dd> |
| |
| <p>Yes. <code>LoggerFactory</code> is essentially a wrapper |
| around an <a |
| href="xref/org/slf4j/ILoggerFactory.html"><code>ILoggerFactory</code></a> |
| instance. The <code>ILoggerFactory</code> instance in use is |
| determined according to the static binding conventions of the |
| SLF4J framework. See the <a |
| href="xref/org/slf4j/LoggerFactory.html#217">getSingleton()</a> |
| method in <code>LoggerFactory</code> for details. |
| </p> |
| |
| <p>However, nothing prevents you from using your own |
| <code>ILoggerFactory</code> instance. Note that you can also |
| obtain a reference to the <code>ILoggerFactory</code> that the |
| <code>LoggerFactory</code> class is using by invoking the <a |
| href="apidocs/org/slf4j/LoggerFactory.html#getILoggerFactory()"> |
| <code>LoggerFactory.getILoggerFactory()</code></a> method. |
| </p> |
| |
| <p>Thus, if SLF4J binding conventions do not fit your needs, or |
| if you need additional flexibility, then do consider using the |
| <code>ILoggerFactory</code> interface as an alternative to |
| inventing your own logging API.</p> |
| </dd> |
| |
| <dt><a name="paramException" href="#paramException">In the presence of an |
| exception/throwable, is it possible to parametizere a logging |
| statement?</a></dt> |
| |
| |
| <dd> |
| <p>Yes, as of SLF4J 1.6.0, but not in previous versions. The |
| SLF4J API supports parametrization in the presence of an |
| exception, assuming the exception is the last parameter. Thus, |
| </p> |
| <pre class="prettyprint">String s = "Hello world"; |
| try { |
| Integer i = Integer.valueOf(s); |
| } catch (NumberFormatException e) { |
| logger.error("Failed to format {}", s, e); |
| }</pre> |
| |
| <p>will print the <code>NumberFormatException</code> with its |
| stack trace as expected. The java compiler will invoke the <a |
| href="http://www.slf4j.org/apidocs/org/slf4j/Logger.html#error%28java.lang.String,%20java.lang.Object,%20java.lang.Object%29">error |
| method taking a String and two Object arguments</a>. SLF4J, in |
| accordance with the programmer's most probable intention, will |
| interpret <code>NumberFormatException</code> instance as a |
| throwable instead of an unused <code>Object</code> parameter. In |
| SLF4J versions prior to 1.6.0, the |
| <code>NumberFormatException</code> instance was simply ignored. |
| </p> |
| |
| <p>If the exception is not the last argument, it will be treated |
| as a plain object and its stack trace will NOT be printed. |
| However, such situations should not occur in practice. |
| </p> |
| |
| </dd> |
| |
| |
| |
| </dl> |
| |
| |
| |
| <h2>Implementing the SLF4J API</h2> |
| |
| <dl> |
| <dt><a name="slf4j_compatible" href="#slf4j_compatible"> How do |
| I make my logging framework SLF4J compatible? |
| </a> |
| </dt> |
| |
| |
| <dd> |
| |
| <p>Adding supporting for the SLF4J is surprisingly |
| easy. Essentially, you coping an existing binding and tailoring |
| it a little (as explained below) does the trick. |
| </p> |
| |
| <p>Assuming your logging system has notion of a |
| logger, called say <code>MyLogger</code>, you need to provide |
| an adapter for <code>MyLogger</code> to |
| <code>org.slf4j.Logger</code> interface. Refer to slf4j-jcl, |
| slf4j-jdk14, and slf4j-log4j12 modules for examples of |
| adapters. |
| </p> |
| |
| <p>Once you have written an appropriate adapter, say |
| <code>MyLoggerAdapter</code>, you need to provide a factory |
| class implementing the <code>org.slf4j.ILoggerFactory</code> |
| interface. This factory should return instances |
| <code>MyLoggerAdapter</code>. Let <code>MyLoggerFactory</code> |
| be the name of your factory class. |
| </p> |
| |
| <p>Once you have the adapter, namely |
| <code>MyLoggerAdapter</code>, and a factory, namely |
| <code>MyLoggerFactory</code>, the last remaining step is to |
| modify the <code>StaticLoggerBinder</code> class so that it |
| returns an new instance of <code>MyLoggerFactory</code>. You |
| will also need to modify the |
| <code>loggerFactoryClassStr</code> variable. |
| </p> |
| |
| <p>For Marker or MDC support, you could use the one of the |
| existing NOP implementations. |
| </p> |
| |
| <p>In summary, to create an SLF4J binding for your logging |
| system, follow these steps:</p> |
| |
| <ol> |
| <li>start with a copy of an existing module,</li> |
| <li>create an adapter between your logging system and |
| <code>org.slf4j.Logger</code> interface |
| </li> |
| <li>create a factory for the adapter created in the previous step,</li> |
| <li>modify <code>StaticLoggerBinder</code> class to use the |
| factory you created in the previous step</li> |
| </ol> |
| |
| <hr/> |
| </dd> |
| <dt> |
| <a name="marker_interface" href="#marker_interface"> How |
| can my logging system add support for the <code>Marker</code> |
| interface? |
| </a> |
| </dt> |
| <dd> |
| |
| <p>Markers constitute a revolutionary concept which is |
| supported by logback but not other existing logging |
| systems. Consequently, SLF4J conforming logging systems are |
| allowed to ignore marker data passed by the user. |
| </p> |
| |
| <p>However, even though marker data may be ignored, the user |
| must still be allowed to specify marker data. Otherwise, users |
| would not be able to switch between logging systems that |
| support markers and those that do not. |
| </p> |
| |
| <p>The <code>MarkerIgnoringBase</code> class can serve as a |
| base for adapters or native implementations of logging |
| systems lacking marker support. In |
| <code>MarkerIgnoringBase</code>, methods taking marker data |
| simply invoke the corresponding method without the Marker |
| argument, discarding any Marker data passed as |
| argument. Your SLF4J adapters can extend |
| <code>MarkerIgnoringBase</code> to quickly implement the |
| methods in <code>org.slf4j.Logger</code> which take a |
| <code>Marker</code> as the first argument. |
| </p> |
| |
| <hr/> |
| </dd> |
| |
| <dt><a name="version_checks" href="#version_checks"> How does |
| SLF4J's version check mechanism work?</a> |
| </dt> |
| |
| <dd> |
| <p>The version check performed by SLF4J API during its |
| initialization is an elective process. Conforming SLF4J |
| implementations may choose <em>not</em> to participate, in |
| which case, no version check will be performed. |
| </p> |
| |
| <p>However, if an SLF4J implementation decides to participate, |
| than it needs to declare a variable called |
| REQUESTED_API_VERSION within its copy of the |
| <code>StaticLoggerBinder</code> class. The value of this |
| variable should be equal to the version of the slf4j-api.jar |
| it is compiled with. If the implementation is upgraded to a |
| newer version of slf4j-api, than you also need to update the |
| value of REQUESTED_API_VERSION. |
| </p> |
| |
| <p>For each version, SLF4J API maintains a list of compatible |
| versions. SLF4J will emit a version mismatch warning only if |
| the requested version is not found in the compatibility |
| list. So even if your SLF4J binding has a different release |
| schedule than SLF4J, assuming you update the SLF4J version you |
| use every 6 to 12 months, you can still participate in the |
| version check without incurring a mismatch warning. For |
| example, logback has a different release schedule but still |
| participates in version checks.</p> |
| |
| <p><b>As of SLF4J 1.5.5</b>, all bindings shipped within the |
| SLF4J distribution, e.g. slf4j-logj12, slf4j-simple and |
| slf4j-jdk14, declare the REQUESTED_API_VERSION field with a |
| value equal to their SLF4J version. It follows that, for |
| example if slf4j-simple-1.5.6.jar is mixed with |
| slf4j-api-1.5.5.jar, then a version mismatch warning will be |
| issued. Note that SLF4J versions prior to 1.5.5 did not have a |
| version check mechanism. Only slf4j-api-1.5.5.jar and later |
| can emit version mismatch warnings. (Actually, version 1.5.4 |
| offered a check policy which was much too restrictive and |
| inconsistent with the size of our user base. Consequently, |
| SLF4J version 1.5.5 was released just a day after 1.5.4.) |
| </p> |
| |
| <p>Given its large installed user base and several external |
| implementations, it would have been unwise to expect all SLF4J |
| implementations to closely follow SLF4J's release schedule, let |
| alone align their release schedules with SLF4J. Hence, the |
| elective version check policy. |
| </p> |
| |
| </dd> |
| |
| </dl> |
| |
| <h2>General questions about logging</h2> |
| |
| |
| <dl> |
| <dt><a name="declared_static" href="#declared_static"> Should Logger |
| members of a class be declared as static? </a> |
| </dt> |
| <dd> |
| |
| <p>We <code>used</code> to recommend that loggers members be |
| declared as instance variables instead of static. After further |
| analysis, <b>we no longer recommend one approach over the |
| other.</b> |
| </p> |
| |
| <p>Here is a summary of the pros and cons of each approach. |
| </p> |
| |
| <table class="bodyTable"> |
| <tr valign="top"> |
| <th width="50%">Advantages for declaring loggers as static</th> |
| <th width="50%">Disadvantages for declaring loggers as static</th> |
| </tr> |
| <tr valign="top" class="alt"> |
| <td> |
| <ol> |
| <li>common and well-established idiom</li> |
| <li>less CPU overhead: loggers are retrieved and |
| assigned only once, at hosting class |
| initialization</li> |
| <li>less memory overhead: logger declaration will |
| consume one reference per class</li> |
| </ol> |
| </td> |
| |
| <td> <!-- static con --> |
| <ol> |
| <li>For libraries shared between applications, not |
| possible to take advantage of repository selectors. It |
| should be noted that if the SLF4J binding and the |
| underlying API ships with each application (not shared |
| between applications), then each application will still |
| have its own logging environment. |
| </li> |
| <li>not IOC-friendly</li> |
| </ol> |
| </td> |
| </tr> |
| |
| <tr> |
| <th width="50%">Advantages for declaring loggers as instance variables</th> |
| <th width="50%">Disadvantages for declaring loggers as |
| instance variables</th> |
| </tr> |
| |
| <tr class="alt" valign="top"> |
| <td> <!-- instance pros --> |
| <ol> |
| <li>Possible to take advantage of repository selectors |
| even for libraries shared between applications. However, |
| repository selectors only work if the underlying logging |
| system is logback-classic. Repository selectors do not |
| work for the SLF4J+log4j combination. |
| </li> |
| <li>IOC-friendly</li> |
| </ol> |
| </td> |
| |
| <td> <!-- instance cons --> |
| <ol> |
| <li>Less common idiom than declaring loggers as static |
| variables</li> |
| |
| <li>higher CPU overhead: loggers are retrieved and |
| assigned for each instance of the hosting class</li> |
| |
| <li>higher memory overhead: logger declaration will |
| consume one reference per instance of the hosting class</li> |
| </ol> |
| </td> |
| </tr> |
| </table> |
| |
| |
| <h3>Explanation</h3> |
| |
| <p>Static logger members cost a single variable reference for |
| all instances of the class whereas an instance logger member |
| will cost a variable reference for every instance of the |
| class. For simple classes instantiated thousands of times |
| there might be a noticeable difference. |
| </p> |
| |
| <p>However, more recent logging systems, e.g log4j or logback, |
| support a distinct logger context for each application running |
| in the application server. Thus, even if a single copy of |
| <em>log4j.jar</em> or <em>logback-classic.jar</em> is deployed |
| in the server, the logging system will be able to differentiate |
| between applications and offer a distinct logging environment |
| for each application. |
| </p> |
| |
| <p>More specifically, each time a logger is retrieved by |
| invoking <code>LoggerFactory.getLogger()</code> method, the |
| underlying logging system will return an instance appropriate |
| for the current application. Please note that within the |
| <em>same</em> application retrieving a logger by a given name |
| will always return the same logger. For a given name, a |
| different logger will be returned only for different |
| applications. |
| </p> |
| |
| <p>If the logger is static, then it will only be retrieved once |
| when the hosting class is loaded into memory. If the hosting |
| class is used in only in one application, there is not much to |
| be concerned about. However, if the hosting class is shared |
| between several applications, then all instances of the shared |
| class will log into the context of the application which |
| happened to first load the shared class into memory - hardly the |
| behavior expected by the user. |
| </p> |
| |
| <p>Unfortunately, for non-native implementations of the SLF4J |
| API, namely with slf4j-log4j12, log4j's repository selector will |
| not be able to do its job properly because slf4j-log4j12, a |
| non-native SLF4J binding, will store logger instances in a map, |
| short-circuiting context-dependent logger retrieval. For native |
| SLF4J implementations, such as logback-classic, repository |
| selectors will work as expected. |
| </p> |
| |
| <p>The Apache Commons wiki contains an <a |
| href="http://wiki.apache.org/jakarta-commons/Logging/StaticLog">informative |
| article</a> covering the same question.</p> |
| |
| <p><b>Logger serialization</b></p> |
| |
| <p>Contrary to static variables, instance variables are |
| serialized by default. As of SLF4J version 1.5.3, logger |
| instances survive serialization. Thus, serialization of the host |
| class no longer requires any special action, even when loggers |
| are declared as instance variables. In previous versions, logger |
| instances needed to be declared as <code>transient</code> in the |
| host class. </p> |
| |
| <p><b>Summary</b></p> |
| |
| <p>In summary, declaring logger members as static variables |
| requires less CPU time and have a slightly smaller memory |
| footprint. On the other hand, declaring logger members as |
| instance variables requires more CPU time and have a slighlty |
| higher memory overhead. However, instance variables make it |
| possible to create a distinct logger environment for each |
| application, even for loggers declared in shared |
| libraries. Perhaps more important than previously mentioned |
| considerations, instance variables are IOC-friendly whereas |
| static variables are not. |
| </p> |
| |
| <p>See also <a |
| href="http://wiki.apache.org/jakarta-commons/Logging/StaticLog">related |
| discussion</a> in the commons-logging wiki. |
| </p> |
| |
| </dd> |
| </dl> |
| |
| <dl> |
| <dt> <a name="declaration_pattern" |
| href="#declaration_pattern">Is there a recommended idiom for |
| declaring a logger in a class?</a> |
| </dt> |
| |
| <dd> |
| <p>The following is the recommended logger declaration |
| idiom. For reasons <a href="#declared_static">explained |
| above</a>, it is left to the user to determine whether loggers |
| are declared as static variables or not.</p> |
| |
| <pre class="prettyprint source">package some.package; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class MyClass { |
| <b>final (static) Logger logger = LoggerFactory.getLogger(MyClass.class);</b> |
| ... etc |
| }</pre> |
| |
| <p>Unfortunately, give that the name of the hosting class is |
| part of the logger declaration, the above logger declaration |
| idiom is not is <em>not</em> resistant to cut-and-pasting |
| between classes. |
| </p> |
| </dd> |
| </dl> |
| |
| <script src="templates/footer.js" type="text/javascript"></script> |
| </div> |
| </body> |
| </html> |