Author: ceki Date: Tue Aug 29 22:43:47 2006 New Revision: 627 Added: slf4j/trunk/slf4j-site/src/site/fml/ slf4j/trunk/slf4j-site/src/site/fml/faq.fml Log: migrating to FML format for SLF4J FAQ
Added: slf4j/trunk/slf4j-site/src/site/fml/faq.fml ============================================================================== --- (empty file) +++ slf4j/trunk/slf4j-site/src/site/fml/faq.fml Tue Aug 29 22:43:47 2006 @@ -0,0 +1,712 @@ +<?xml version="1.0"?> + + <faqs title="Frequently Asked Questions about SLF4J"> + + <part id="Generalities"> + <title>Generalities</title> + + <faq id="what_is"> + <question> + What is SLF4J? + </question> + <answer> + <p>SLF4J is a simple facade for logging systems allowing the + end-user to plug-in the desired logging system at deployment + time. + </p> + </answer> + </faq> + + <faq id="when"> + <question> + When should SLF4J be used? + </question> + <answer> + <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 same 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 long and error-prone + process. Had you been invoking SLF4J API instead of log4j, the + migration could be completed in a matter of minutes instead of + hours. + </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> + + </answer> + </faq> + + <faq id="yet_another_facade"> + <question> + Is SLF4J yet another logging facade? + </question> + <answer> + <p>SLF4J is conceptually similar to JCL. As such, it can be + thought of as yet another logging facade. However, SLF4J is + orders of magnitude simpler in design and arguably more + robust. + </p> + </answer> + </faq> + + <faq id="why_new_project"> + <question> + If SLF4J fixes JCL, then why wasn't the fix made in JCL + instead of creating a new project? + </question> + <answer> + <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 the + approach. It is only after SLF4J was released and started to + become accepted did the approach gain respectability in the + relevant community. + </p> + + <p>Second, SLF4J offers two enhancements which developers + currently tend to underestimate. 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> + </answer> + </faq> + + <faq id="need_to_recompile"> + <question> + When using SLF4J, do I have to recompile my application + to switch to a different logging system? + </question> + + <answer> + 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>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> + </answer> + </faq> + + <faq id="license"> + <question> + Why is SLF4J licensed under X11 type license instead of the + Apache Software License? + </question> + <answer> + <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> + </answer> + </faq> + + <faq id="where_is_binding"> + <question> + Where can I get a particular SLF4J binding? + </question> + + <answer> + <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">LoggerLoggerAdapter</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>, + <em>slf4j-log4j13.jar</em> and <em>slf4j-jdk14.jar</em>. These + files ship with the <a href="download.html">official SLF4J + distribution.</a> + </p> + + <p>The binding for NLOG4J ships with the <a + href="http://www.slf4j.org/nlog4j/download.html">NLOG4J + distribution</a>. If you use NLOG4J, you don't need to load + SLF4J because NLOG4J 1.2.10 and later already contain the + SLF4J interfaces and classes. + </p> + </answer> + </faq> + + <faq id="configure_logging"> + <question> + Should my library attempt to configure logging? + </question> + <answer> + <p>Embedded components such as libraries do not need and + should not configure the logging system. They 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> + </answer> + </faq> + </part> + + + <part> + <title>About the SLF4J API</title> + + <faq id="string_or_object"> + <question> + Why don't the printing methods in the Logger interface + accept message of type Object, but only messages of type + String? + </question> + <answer> + + <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> + <p class="source">debug(String msg); +debug(String format, Object arg); +debug(String format, Object arg1, Object arg2); +debug(String msg, Throwable t); </p> + + <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 overladed methods + whereas previously the choice of the invoked method due to + Java overloding 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> + + <p class="source">logger.debug(new Exception("some error"));</p> + + <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> + <p class="source">debug(String msg, Throwable t) </p> + + <p>can be used to log exceptions. Note that this method + ensures that every logged exception is accompanied with a + descriptive message.</p> + </answer> + </faq> + + <faq id="exception_message"> + <question> + Can I log an exception without an accompanying message? + </question> + + <answer> + <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> + + <p class="source">logger.error("some accompanying message", e);</p> + + <p>You might correctly observe 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> + + </answer> + </faq> + + <faq id="logging_performance"> + <question> + What is the fastest way of (not) logging? + </question> + + <answer> + <p> For some Logger <code>logger</code>, writing, </p> + <p class="source">logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</p> + + <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> + + <p class="source">if(logger.isDebugEnabled()) { + logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); +} </p> + + + <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 alternative based on format 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> + + + <p class="source">Object entry = new SomeObject(); +logger.debug("The entry is {}.", entry); </p> + + <p>After evaluting 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, tis 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> + + <p class="source">logger.debug("The new entry is "+entry+"."); +logger.debug("The new entry is {}.", entry); </p> + + + <p>A two argument variant is also availalble. For example, you can + write: </p> + + <p class="source">logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</p> + + <p>If three or more arguments need to be passed, an + <code>Object[]</code> variant is also availalble. For example, + you can write: </p> + + <p class="source">logger.debug("Value {} was inserted between {} and {}.", + new Object[] {newVal, below, above});</p> + + + + </answer> + </faq> + + <faq id="string_contents"> + <question> + How can I log the string contents of a single (possibly + complex) object? + </question> + + <answer> + <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> + + <p class="source">logger.debug("{}", complexObject);</p> + + + <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> + + </answer> + </faq> + + <faq id="fatal"> + <question> + Why doesn't the <code>org.slf4j.Logger</code> interface + have methods for the FATAL level? + </question> + + <answer> + <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> + </answer> + </faq> + + <faq id="trace"> + <question> + Why doesn't the <code>org.slf4j.Logger</code> interface + have methods for the TRACE level? + </question> + + <answer> + + <p>The addition of the TRACE level has been frequently and + hotly debated request. By studying various projects, it looks + like the TRACE level is mostly used to disable logging output + from certain classes without needing to configure logging for + those classes. Indeed, the TRACE level is by default disabled + in log4j and other logging systems. We believe that the same + result could be achieved by adding the appropriate directives + in configuration files. + </p> + + <p>Thus, in the majority of cases the TRACE level has the same + semantic meaning as DEBUG. In such case, the TRACE level + merely saves a few configuration directives. In the rare but + interesting cases where TRACE has a different meaning than + DEBUG, <a href="api/org/slf4j/Marker.html">Marker</a> objects + can be put to use to convey the desired new meaning. + </p> + </answer> + + </faq> + + <faq id="log4j_12_vs_13"> + <question> + What is the difference between + <em>slf4j-log4j12.jar</em> and <em>slf4j-log4j13.jar</em>? + </question> + + <answer> + + <p>Although log4j versions 1.2 and 1.3 are compile-time + compatible, due to highly technical reasons they are <b>not</b> + run-time compatible. This means that an slf4j-log4j binding + compiled with log4j 1.2 will not run with log4j 1.3 and vice + versa. The <em>slf4j-log4j12.jar</em> binding is compiled with + log4j 1.2 and will run without problems with log4j + 1.2. However, <em>slf4j-log4j12.jar</em> will not run with + log4j 1.3. Similarly, The <em>slf4j-log4j13.jar</em> binding is + compiled with log4j 1.3 and will run without problems with + log4j 1.3. However, <em>slf4j-log4j13.jar</em> will not run + with log4j 1.2. + </p> + </answer> + </faq> + + <faq id="nlog4j_or_log4j"> + <question> + NLOG4J or log4j, which one should I choose? + </question> + + <answer> + <p>NLOG4J is almost identical to log4j. NLOG4J natively supports + the SLF4J API while vanilla log4j is supported through a + wrapper, i.e <em>slf4j-log4j12.jar</em> or + <em>slf4j-log4j13.jar</em> depending on the version of log4j. + </p> + + <p>NLOG4J demonstrates the feasibility of natively implementing + SLF4J API in log4j. As a native implementation of the SLF4J + API, NLOG4J has a smaller memory footprint and is + computationally faster than a wrapped implementation of SLF4J + API. + </p> + + <p>NLOG4J is a drop-in replacement for log4j. In particular, code + previously compiled with log4j will run fine with NLOG4J. The + same will also compile fine against NLOG4J (without any + changes). However, due to signature changes in some important + logging methods, compilation against NLOG4J is sticky. Software + compiled against NLOG4J will require NLOG4J to run. </p> + + <p>Thus, you can easily switch from log4j to NLOG4J but you + cannot switch back without first recompiling your code with + log4j. + </p> + + <p>At this stage, we should emphasize that if you code against + the SLF4J API, the question of compiling against log4j or + NLOG4J is not relevant. As far as your code is concerned, the + java compiler only sees the SLF4J API, not log4j or + NLOG4J. + </p> + </answer> + </faq> + </part> + + <part> + <title>Implementing the SLF4J API</title> + + <faq id="slf4j_compatible"> + <question> + How do I make my logging framework SLF4J + compatible? + </question> + + <answer> + <p>We suggest that the <code>Logger</code> class in your + framework directly implement the <a + href="api/org/slf4j/Logger.html"><code>org.slf4j.Logger</code></a> + interface. + </p> + + <p>We further recommend that your framework copy the SLF4J + java source files (.java files) into your source tree. This + can be accomplished by checking out SLF4J files from its + source code repository using Subversion, more on this later. + </p> + + <p>Client code will only refer to <a + href="api/org/slf4j/LoggerFactory.html">LoggerFactory</a> to + retreive org.slf4j.Logger instances, your framework needs to + instruct <code>LoggerFactory</code> to return your framework's + <code>Logger</code> instances. This step is usually reffered + to as binding SLF4J with your framework. In recent versions of + SLF4J, the binding information has been isolated into a small + class named <a + href="api/org/slf4j/impl/StaticLoggerBinder.html">StaticLoggerBinder</a>. + </p> + + + <p>With the static binding approach we recommend, your + framework's copy of <code>StaticBinder</code> class needs to + be customized before compile time. You should be able to + easily adapt NLOG4J's copy of <a + href="http://svn.slf4j.org/viewcvs/nlog4j/trunk/src/java/org/slf4j/impl/StaticLoggerBinder.java?view=markup">StaticLoggerBinder.java</a> + to your framework. Note that you do not need to change any + other classes to ensure correct binding. + </p> + + + <p>Just as importantly, adapting SLF4J to your system can be an + entirely automated process. Thus, when there are small changes + to the SLF4J API, you can update to the latest SLF4J version + without needing to edit any java files. For example, NLOG4J + uses an entirely automated build procedure to synchronize with + SLF4J changes. + </p> + + <p>For a complete example of an automated build file, please + refer to the <a + href="http://svn.slf4j.org/viewcvs/nlog4j/trunk/slf4j.xml?view=markup">slf4j.xml</a> + build file in the NLOG4J project. + </p> + </answer> + </faq> + + <faq id="marker_interface"> + <question> + How can my logging system add support for + the <code>Marker</code> interface? + </question> + + <answer> + <p>Markers consitute a revolutionary concept which is + supported by LOGBack but not other existing logging + systems. Consequently, SLF4J confromant 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. In order to provide + minimal support for markers, SLF4J conformant systems need to + to include certain Marker related classes, namely, + <code>org.slf4j.Marker</code>, + <code>org.slf4j.IMarkerFactory</code>, + <code>org.slf4j.MarkerFactory</code>, + <code>org.slf4j.impl.BasicMarker</code>, + <code>org.slf4j.impl.BasicMarkerFactory</code>, + <code>org.slf4j.impl.MarkerIgnoringBase</code>, + <code>org.slf4j.impl.StaticMarkerBinder</code> and + <code>org.slf4j.spi.MarkerFactoryBinder</code>. Al of these + classes are availalbe in the SLF4J subversion repository. + </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> + + </answer> + </faq> + </part> + + + <part> + <title>General questions about logging</title> + + <faq id="declared_static"> + <question> + Should Logger members of a class be declared as static? + </question> + + <answer> + + <p>This author recommends that loggers members be declared + as instance variables instead of static. + </p> + + <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 fist load the shared class into memory - + hardly the behavior expected by the user. + </p> + + <p>In summary, except for classes with few members + <em>and</em> instantiated very frequently, logger members + should be instance variables. + </p> + + + </answer> + </faq> + </part> + + </faqs> + + + _______________________________________________ dev mailing list [email protected] http://slf4j.org/mailman/listinfo/dev
