| <!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(); decorate();"> |
| |
| <script type="text/javascript" src="js/prettify.js"></script> |
| <script type="text/javascript">prefix='';</script> |
| |
| <script type="text/javascript" src="templates/header.js"></script> |
| <script type="text/javascript" src="js/jquery-min.js"></script> |
| <script type="text/javascript" src="js/decorator.js"></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 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 parameterize 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 class="doAnchor" name="what_is">What is SLF4J?</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> |
| </dd> |
| |
| <dt class="doAnchor" name="when">When should SLF4J be used?</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 framework 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 framework of their choice |
| directly. In the case of logback, the question is moot because |
| logback exposes its logger API via SLF4J. |
| </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> |
| |
| |
| |
| </dd> |
| |
| <dt class="doAnchor" name="yet_another_facade">Is SLF4J yet |
| another logging facade?</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> |
| |
| |
| |
| </dd> |
| <dt class="doAnchor" name="why_new_project">If SLF4J fixes JCL, |
| then why wasn't the fix made in JCL instead of creating a new |
| project? |
| </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> |
| |
| |
| </dd> |
| |
| <dt class="doAnchor" name="need_to_recompile">When using SLF4J, do |
| I have to recompile my application to switch to a different |
| logging system? |
| </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> |
| |
| |
| </dd> |
| |
| <dt class="doAnchor" name="requirements">What are SLF4J's |
| requirements? |
| </dt> |
| |
| <dd> |
| |
| <p>As of version 1.7.0, SLF4J requires JDK 1.5 or later. Earlier |
| SLF4J versions, namely SLF4J 1.4, 1.5. and 1.6, required JDK |
| 1.4. |
| </p> |
| |
| <p> </p> |
| |
| <table class="bodyTable striped"> |
| <tr align="left"> |
| <th>Binding</th> |
| <th>Requirements</th> |
| </tr> |
| |
| <tr> |
| <td>slf4j-nop</td> |
| <td>JDK 1.5</td> |
| </tr> |
| <tr> |
| <td>slf4j-simple</td> |
| <td>JDK 1.5</td> |
| </tr> |
| |
| <tr> |
| <td>slf4j-log4j12</td> |
| <td align="left">JDK 1.5, plus any other library |
| dependencies required by the log4j appenders in use</td> |
| </tr> |
| <tr> |
| <td>slf4j-jdk14</td> |
| <td>JDK 1.5 or later</td> |
| </tr> |
| <tr> |
| <td>logback-classic</td> |
| <td>JDK 1.5 or later, plus any other library dependencies |
| required by the logback appenders in use</td> |
| </tr> |
| |
| </table> |
| |
| |
| </dd> |
| |
| <!-- ==================================================== --> |
| <!-- entry has order dependees --> |
| |
| <dt class="doAnchor" name="compatibility">Are SLF4J versions |
| backward compatible? |
| </dt> |
| |
| <dd> |
| <p>From the clients perspective, the SLF4J API is backward |
| compatible for all versions. This means than you can upgrade |
| from SLF4J version 1.0 to any later version without |
| problems. Code compiled with <em>slf4j-api-versionN.jar</em> |
| will work with <em>slf4j-api-versionM.jar</em> for any versionN |
| and any versionM. <b>To date, binary compatibility in slf4j-api |
| has never been broken.</b></p> |
| |
| <p>However, while the SLF4J API is very stable from the client's |
| perspective, SLF4J bindings, e.g. slf4j-simple.jar or |
| slf4j-log4j12.jar, may require a specific version of slf4j-api. |
| Mixing different versions of slf4j artifacts can be problematic |
| and is strongly discouraged. 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. |
| </p> |
| |
| |
| </dd> |
| |
| <!-- ==================================================== --> |
| |
| <dt class="doAnchor" name="IllegalAccessError">I am getting |
| <code>IllegalAccessError</code> exceptions when using SLF4J. Why |
| is that? |
| </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 initializer 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 incorporates 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 slf4j-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 using 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, explicitly declaring a |
| dependency on slf4j-api matching the version of the declared |
| binding will make the problem go away. |
| </p> |
| |
| <p>Please also read the FAQ entry on <a |
| href="#compatibility">backward compatibility</a> for a more |
| general explanation.</p> |
| |
| |
| </dd> |
| |
| |
| <!-- ==================================================== --> |
| |
| <dt class="doAnchor" name="license">Why is SLF4J licensed under |
| X11 type license instead of the Apache Software License? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ==================================================== --> |
| <dt class="doAnchor" name="where_is_binding">Where can I get a |
| particular SLF4J binding? |
| </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> |
| |
| |
| </dd> |
| |
| <dt class="doAnchor" name="configure_logging">Should my library |
| attempt to configure logging? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ======================================================= --> |
| |
| <dt class="doAnchor" name="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? |
| </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 more complex by adding an additional indirection on top of |
| SLF4J, which is an indirection in itself. |
| </p> |
| |
| <p><span class="label">increased vulnerability</span> It is |
| actually worse than that. Wrappers will need to depend on |
| certain internal SLF4J interfaces which change from time to |
| time, 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>The <a |
| href="http://velocity.apache.org/engine/devel/developer-guide.html#Configuring_Logging">logging |
| strategy adopted by the Velocity project</a> is a good example |
| of the "custom logging abstraction" anti-pattern. By adopting an |
| independent logging abstraction strategy, Velocity developers |
| have made life harder for themselves, but more importantly, they |
| made life harder for their users. |
| </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 transparent 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 260 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 class="doAnchor" name="maven2">What about Maven transitive |
| dependencies? |
| </dt> |
| |
| <dd> |
| <p>As an author of a library built with Maven, 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. This is rather easy to accomplish. |
| </p> |
| |
| <p>Given that 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> |
| |
| |
| |
| </dd> |
| |
| <!-- ====================================================== --> |
| <dt class="doAnchor" name="excludingJCL">How do I exclude |
| commons-logging as a Maven dependency? |
| </dt> |
| |
| <dd> |
| <p><b>alternative 1) explicit exclusion</b></p> |
| |
| <p>Many software projects using Maven declare commons-logging as |
| a dependency. Therefore, if you wish to migrate to SLF4J or use |
| jcl-over-slf4j, you would need to exclude commons-logging in all |
| of your project's dependencies which transitively depend on |
| commons-logging. <a |
| href="http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html">Dependency |
| exclusion</a> is described in the Maven documentation. Excluding |
| commons-logging explicitly for multiple dependencies distributed |
| on several <em>pom.xml</em> files can be a cumbersome and a |
| relatively error prone process. |
| </p> |
| |
| <p><b>alternative 2) provided scope</b></p> |
| |
| <p>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> |
| |
| <p>The first dependency declaration essentially states that |
| commons-logging will be "somehow" provided by your |
| environment. The second declaration includes jcl-over-slf4j into |
| your project. As jcl-over-slf4j is a perfect binary-compatible |
| replacement for commons-logging, the first assertion becomes |
| true. |
| </p> |
| |
| <p>Unfortunately, while declaring commons-logging in the |
| provided scope gets the job done, your IDE, e.g. Eclipse, will |
| still place <em>commons-logging.jar</em> on your project's class |
| path as seen by your IDE. You would need to make sure that |
| <em>jcl-over-slf4j.jar</em> is visible before |
| <em>commons-logging.jar</em> by your IDE. |
| </p> |
| |
| <p><b>alternative 3) empty artifacts</b></p> |
| |
| <p>An alternative approach is to depend on an <b>empty</b> |
| <em>commons-logging.jar</em> artifact. This clever <a |
| href="http://day-to-day-stuff.blogspot.com/2007/10/announcement-version-99-does-not-exist.html">approach |
| first was imagined</a> and initially supported by Erik van |
| Oosten. |
| </p> |
| |
| <p>The empty artifact is available from a <a |
| href="http://version99.qos.ch">http://version99.qos.ch</a> a |
| high-availability Maven repository, replicated on several hosts |
| located in different geographical regions.</p> |
| |
| <p>The following declaration adds the version99 repository to |
| the set of remote repositories searched by Maven. This |
| repository contains empty artifacts for commons-logging and |
| log4j. By the way, if you use the version99 repository, please |
| drop us a line at <version99 AT qos.ch>. |
| </p> |
| |
| <pre class="prettyprint source"><repositories> |
| <repository> |
| <id>version99</id> |
| <!-- highly available repository serving empty artifacts --> |
| <url>http://version99.qos.ch/</url> |
| </repository> |
| </repositories></pre> |
| |
| <p>Declaring version 99-empty of commons-logging in the |
| <code><dependencyManagement></code> section of your project |
| will direct all transitive dependencies for commons-logging to |
| import version 99-empty, thus nicely addressing the |
| commons-logging exclusion problem. The classes for commons-logging |
| will be provided by jcl-over-slf4j. The following lines declare |
| commons-logging version 99-empty (in the dependency management |
| section) and declare jcl-over-slf4j as a dependency. |
| </p> |
| |
| <pre class="prettyprint source"><dependencyManagement> |
| <dependencies> |
| <dependency> |
| <groupId>commons-logging</groupId> |
| <artifactId>commons-logging</artifactId> |
| <version><b>99-empty</b></version> |
| </dependency> |
| ... other declarations... |
| </dependencies> |
| </dependencyManagement> |
| |
| <!-- Do not forget to declare a dependency on jcl-over-slf4j in the --> |
| <!-- dependencies section. Note that the dependency on commons-logging --> |
| <!-- will be imported transitively. You don't have to declare it yourself. --> |
| <dependencies> |
| <dependency> |
| <groupId>org.slf4j</groupId> |
| <artifactId>jcl-over-slf4j</artifactId> |
| <version>${project.version}</version> |
| </dependency> |
| ... other dependency declarations |
| </dependencies> |
| </pre> |
| |
| |
| </dd> |
| |
| |
| |
| </dl> |
| |
| |
| <h2>About the SLF4J API</h2> |
| |
| <dl> |
| |
| <dt class="doAnchor" name="string_or_object">Why don't the |
| printing methods in the Logger interface accept message of type |
| Object, but only messages of type String? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ====================================================== --> |
| |
| <dt class="doAnchor" name="exception_message">Can I log an |
| exception without an accompanying message? |
| </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> |
| |
| </dd> |
| |
| <!-- ====================================================== --> |
| |
| |
| <dt class="doAnchor" name="logging_performance">What is the |
| fastest way of (not) logging? |
| </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 <a |
| href="apidocs/org/slf4j/Logger.html#debug(java.lang.String,%20java.lang.Object%2C%20java.lang.Object)">two |
| argument</a> 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 <a |
| href="apidocs/org/slf4j/Logger.html#debug(java.lang.String%2C%20java.lang.Object...)"><code>Object...</code> |
| variant</a> of the printing methods. For example, you can |
| write:</p> |
| |
| <pre class="prettyprint source">logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);</pre> |
| |
| <p>This form incurs the hidden cost of construction of an |
| Object[] (object array) which is usually very small. The one and |
| two argument variants do not incur this hidden cost and exist |
| solely for this reason (efficiency). The slf4j-api would be |
| smaller/cleaner with only the Object... variant.</p> |
| |
| |
| <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 character 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> |
| |
| </dd> |
| |
| <!-- ================================================= --> |
| |
| <dt class="doAnchor" name="string_contents">How can I log the |
| string contents of a single (possibly complex) object?</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> |
| |
| |
| |
| </dd> |
| |
| <!-- ================================================= --> |
| |
| |
| <dt class="doAnchor" name="fatal">Why doesn't the |
| <code>org.slf4j.Logger</code> interface have methods for the FATAL |
| level? |
| </dt> |
| |
| <dd> |
| <p>The <a href="apidocs/org/slf4j/Marker.html">Marker</a> |
| interface, part of the <code>org.slf4j</code> package, renders |
| the FATAL level largely redundant. If a given error requires |
| attention beyond that allocated for ordinary errors, simply mark |
| the logging statement with a specially designated marker which |
| can be named "FATAL" or any other name to your liking. |
| </p> |
| |
| <p>Here is an example,</p> |
| |
| <pre class="prettyprint">import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.slf4j.Marker; |
| import org.slf4j.MarkerFactory; |
| |
| class Bar { |
| void foo() { |
| <b>Marker fatal = MarkerFactory.getMarker("FATAL");</b> |
| Logger logger = LoggerFactory.getLogger("aLogger"); |
| |
| try { |
| ... obtain a JDBC connection |
| } catch (JDBException e) { |
| logger.error(<b>fatal</b>, "Failed to obtain JDBC connection", e); |
| } |
| } |
| }</pre> |
| |
| |
| <p>While markers are part of the SLF4J API, only logback |
| supports markers off the shelf. For example, if you add the |
| <code>%marker</code> conversion word to its pattern, logback's |
| <code>PatternLayout</code> will add marker data to its |
| output. Marker data can be used to <a |
| href="http://logback.qos.ch/manual/filters.html">filter |
| messages</a> or even <a |
| href="http://logback.qos.ch/manual/appenders.html#OnMarkerEvaluator">trigger</a> |
| an outgoing email <a |
| href="http://logback.qos.ch/recipes/emailPerTransaction.html">at |
| the end of an individual transaction</a>. |
| </p> |
| |
| <p>In combination with logging frameworks such as log4j and |
| java.util.logging which do not support markers, marker data will |
| be silently ignored.</p> |
| |
| <p>Markers add a new dimension with infinite possible values for |
| processing log statements compared to five values, namely ERROR, |
| WARN, INFO, DEBUG and TRACE, allowed by levels. At present time, |
| only logback supports marker data. However, nothing prevents |
| other logging frameworks from making use of marker data. |
| </p> |
| |
| </dd> |
| |
| <!-- ======================================================= --> |
| <dt class="doAnchor" name="trace">Why was the TRACE level |
| introduced only in SLF4J version 1.4.0?</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> |
| |
| |
| </dd> |
| |
| <!-- ================================================= --> |
| <dt class="doAnchor" name="i18n">Does the SLF4J logging API |
| support I18N (internationalization)? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ================================================= --> |
| |
| <dt class="doAnchor" name="noLoggerFactory">Is it possible to |
| retrieve loggers without going through the static methods in |
| <code>LoggerFactory</code>? |
| </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 class="doAnchor" name="paramException">In the presence of an |
| exception/throwable, is it possible to parameterize a logging |
| statement?</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 class="doAnchor" name="slf4j_compatible">How do I make my |
| logging framework SLF4J compatible? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ============================================================= --> |
| |
| <dt class="doAnchor" name="marker_interface">How can my logging |
| system add support for the <code>Marker</code> interface? |
| </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> |
| |
| |
| </dd> |
| |
| <!-- ============================================================= --> |
| |
| <dt class="doAnchor" name="version_checks">How does SLF4J's |
| version check mechanism work? |
| </dt> |
| |
| <dd> |
| <p>The version check performed by SLF4J API during its |
| initialization is an <em>elective</em> 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-log4j12, 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.8.jar is mixed with slf4j-api-1.6.0.jar, |
| given that 1.5.8 is not on the compatibility list of SLF4J |
| version 1.6.x, a version mismatch warning will be issued. |
| </p> |
| |
| <p>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. |
| </p> |
| |
| |
| </dd> |
| |
| </dl> |
| |
| <h2>General questions about logging</h2> |
| |
| |
| |
| <dl> |
| |
| <!-- ============================================================= --> |
| <dt class="doAnchor" name="declared_static">Should Logger members |
| of a class be declared as static? |
| </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 slightly |
| 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 class="doAnchor" name="declaration_pattern">Is there a |
| recommended idiom for declaring a logger in a class? |
| </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> |