You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2013/11/30 15:10:27 UTC

svn commit: r1546733 - /karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf

Author: jbonofre
Date: Sat Nov 30 14:10:27 2013
New Revision: 1546733

URL: http://svn.apache.org/r1546733
Log:
[KARAF-2511] Review the log page of the documentation
[KARAF-2381] Update the document of the log:set command and the DEFAULT keyword

Modified:
    karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf

Modified: karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf
URL: http://svn.apache.org/viewvc/karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf?rev=1546733&r1=1546732&r2=1546733&view=diff
==============================================================================
--- karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf (original)
+++ karaf/trunk/manual/src/main/webapp/users-guide/logging-system.conf Sat Nov 30 14:10:27 2013
@@ -1,136 +1,480 @@
-h1. Logging system
+h1. Log
 
-Karaf provides a powerful logging system based on [OPS4j Pax Logging|http://team.ops4j.org/wiki/display/paxlogging/Pax+Logging]. 
+Apache Karaf provides a very dynamic and powerful logging system.
 
-In addition to being a standard OSGi Log service, it supports the following APIs:
-* Apache Commons Logging
-* SLF4J
-* Apache Log4j
-* Java Util Logging
+It supports:
 
-Karaf also comes with a set of console commands that can be used to display, view and change the log levels.
+* the OSGi Log Service
+* the Apache Log4j framework
+* the Apache Commons Logging framework
+* the Logback framework
+* the SLF4J framework
+* the native Java Util Logging framework
 
-h2. Configuration
+It means that the applications can use any logging framework, Apache Karaf will use the central log system to manage the
+loggers, appenders, etc.
 
-h3. Configuration file
+h2. Configuration files
+
+The initial log configuration is loaded from {{etc/org.ops4j.pax.logging.cfg}}.
+
+This file is a [standard Log4j configuration file|http://logging.apache.org/log4j/1.2/manual.html].
+
+You find the different Log4j element:
+
+* loggers
+* appenders
+* layouts
+
+You can add your own initial configuration directly in the file.
+
+The default configuration is the following:
 
-The configuration of the logging system uses a [standard Log4j configuration file|http://logging.apache.org/log4j/1.2/manual.html] at the following location:
 {code}
-[karaf_install_dir]/etc/org.ops4j.pax.logging.cfg
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You under the Apache License, Version 2.0
+#    (the "License"); you may not use this file except in compliance with
+#    the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+################################################################################
+
+# Root logger
+log4j.rootLogger=INFO, out, osgi:*
+log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.RollingFileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
+log4j.appender.out.file=${karaf.data}/log/karaf.log
+log4j.appender.out.append=true
+log4j.appender.out.maxFileSize=1MB
+log4j.appender.out.maxBackupIndex=10
+
+# Sift appender
+log4j.appender.sift=org.apache.log4j.sift.MDCSiftingAppender
+log4j.appender.sift.key=bundle.name
+log4j.appender.sift.default=karaf
+log4j.appender.sift.appender=org.apache.log4j.FileAppender
+log4j.appender.sift.appender.layout=org.apache.log4j.PatternLayout
+log4j.appender.sift.appender.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %m%n
+log4j.appender.sift.appender.file=${karaf.data}/log/$\\{bundle.name\\}.log
+log4j.appender.sift.appender.append=true
 {code}
-You can edit this file at runtime and any change will be reloaded and be effective immediately.
 
-h3. Configuring the appenders
+The default configuration only define the {{ROOT}} logger, with {{INFO}} log level, using the {{out}} file appender.
+You can change the log level to any Log4j valid values (from the most to less verbose): TRACE, DEBUG, INFO, WARN, ERROR, FATAL.
 
-The default logging configuration defines three appenders:
-* the {{stdout}} console appender is disabled by default.  If you plan to run Karaf in server mode only (i.e. with the locale console disabled), you can turn on this appender on by adding it to the list of configured appenders using the {{log4j.rootLogger}} property
-* the {{out}} appender is the one enabled by default. It logs events to a number of rotating log files of a fixed size.  You can easily change the parameters to control the number of files using {{maxBackupIndex}} and their size size {{maxFileSize}}
-* the {{sift}} appender can be used instead to provide a per-bundle log file.  The default configuration uses the bundle symbolic name as the file name to log to
+The {{osgi:*}} appender is a special appender to send the log message to the OSGi Log Service.
 
-h3. Changing the log levels
+A {{stdout}} console appender is pre-configured, but not enabled by default. This appender allows you to display log
+messages directly to standard output. It's interesting if you plan to run Apache Karaf in server mode (without console).
 
-The default logging configuration sets the logging levels so that the log file will provide enough information to monitor the behavior of the runtime and provide clues about what caused a problem. However, the default configuration will not provide enough information to debug most problems.
+To enable it, you have to add the {{stdout}} appender to the {{rootLogger}}:
 
-The most useful logger to change when trying to debug an issue with Karaf is the root logger. You will want to set its logging level to {{DEBUG}} in the {{org.ops4j.pax.logging.cfg}} file.
-{pygmentize:text}
-log4j.rootLogger=DEBUG, out, osgi:VmLogAppender
-...
-{pygmentize}
+{code}
+log4j.rootLogger=INFO, out, stdout, osgi:*
+{code}
 
-When debugging a problem in Karaf you may want to change the level of logging information that is displayed on the console. The example below shows how to set the root logger to {{DEBUG}} but limiting the information displayed on the console to WARN.
-{pygmentize:text}
-log4j.rootLogger=DEBUG, out, stdout, osgi:VmLogAppender
-log4j.appender.stdout.threshold=WARN
-...
-{pygmentize}
+The {{out}} appender is the default one. It's rolling file appender that maintain and rotate 10 log files of 1MB each.
+The log files are located in {{data/log/karaf.log}} by default.
+
+The {{sift}} appender is not enabled by default. This appender allows you to have one log file per deployed bundle.
+By default, the log file name format uses the bundle symbolic name (in the {{data/log}} folder).
+
+You can edit this file at runtime: any change will be reloaded and be effective immediately (no need to restart Apache Karaf).
+
+Another configuration file is used by Apache Karaf: {{etc/org.apache.karaf.log.cfg}}. This files configures the Log Service
+used by the log commands (see later).
+
+h2. Commands
+
+Instead of changing the {{etc/org.ops4j.pax.logging.cfg}} file, Apache Karaf provides a set of commands allowing to
+dynamically change the log configuration and see the log content:
+
+h3. {{log:clear}}
+
+The {{log:clear}} command clears the log entries.
+
+h3. {{log:display}}
+
+The {{log:display}} command displays the log entries.
+
+By default, it displays the log entries of the {{rootLogger}}:
+
+{code}
+karaf@root()> log:display
+2013-11-29 19:12:46,208 | INFO  | FelixStartLevel  | SecurityUtils                    | 16 - org.apache.sshd.core - 0.9.0 | BouncyCastle not registered, using the default JCE provider
+2013-11-29 19:12:47,368 | INFO  | FelixStartLevel  | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Starting JMX OSGi agent
+{code}
+
+You can also display the log entries from a specific logger, using the {{logger}} argument:
+
+{code}
+karaf@root()> log:display ssh
+2013-11-29 19:12:46,208 | INFO  | FelixStartLevel  | SecurityUtils                    | 16 - org.apache.sshd.core - 0.9.0 | BouncyCastle not registered, using the default JCE provider
+{code}
+
+By default, all log entries will be displayed. It could be very long if your Apache Karaf container is running since a long time.
+You can limit the number of entries to display using the {{-n}} option:
+
+{code}
+karaf@root()> log:display -n 5
+2013-11-30 06:53:24,143 | INFO  | JMX OSGi Agent   | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering org.osgi.jmx.framework.BundleStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.core:type=bundleState,version=1.7,framework=org.apache.felix.framework,uuid=5335370f-9dee-449f-9b1c-cabe74432ed1
+2013-11-30 06:53:24,150 | INFO  | JMX OSGi Agent   | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering org.osgi.jmx.framework.PackageStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.core:type=packageState,version=1.5,framework=org.apache.felix.framework,uuid=5335370f-9dee-449f-9b1c-cabe74432ed1
+2013-11-30 06:53:24,150 | INFO  | JMX OSGi Agent   | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering org.osgi.jmx.framework.ServiceStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.core:type=serviceState,version=1.7,framework=org.apache.felix.framework,uuid=5335370f-9dee-449f-9b1c-cabe74432ed1
+2013-11-30 06:53:24,152 | INFO  | JMX OSGi Agent   | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering org.osgi.jmx.framework.wiring.BundleWiringStateMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.core:type=wiringState,version=1.1,framework=org.apache.felix.framework,uuid=5335370f-9dee-449f-9b1c-cabe74432ed1
+2013-11-30 06:53:24,530 | INFO  | FelixStartLevel  | RegionsPersistenceImpl           | 78 - org.apache.karaf.region.persist - 3.0.0 | Loading region digraph persistence
+{code}
+
+You can also limit the number of entries stored and retain using the {{size}} property in {{etc/org.apache.karaf.log.cfg}} file:
+
+{code}
+#
+# The number of log statements to be displayed using log:display. It also defines the number
+# of lines searched for exceptions using log:display exception. You can override this value
+# at runtime using -n in log:display.
+#
+size = 500
+{code}
+
+By default, each log level is displayed with a different color: ERROR/FATAL are in red, DEBUG in purple, INFO in cyan, etc.
+You can disable the coloring using the {{--no-color}} option.
+
+The log entries format pattern doesn't use the conversion pattern define in {{etc/org.ops4j.pax.logging.cfg}} file.
+By default, it uses the {{pattern}} property defined in {{etc/org.apache.karaf.log.cfg}}.
+
+{code}
+#
+# The pattern used to format the log statement when using log:display. This pattern is according
+# to the log4j layout. You can override this parameter at runtime using log:display with -p.
+#
+pattern = %d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
+{code}
+
+You can also change the pattern dynamically (for one execution) using the {{-p}} option:
+
+{code}
+karaf@root()> log:display -p "%d - %c - %m%n"
+2013-11-30 07:01:58,007 - org.apache.sshd.common.util.SecurityUtils - BouncyCastle not registered, using the default JCE provider
+2013-11-30 07:01:58,725 - org.apache.aries.jmx.core - Starting JMX OSGi agent
+2013-11-30 07:01:58,744 - org.apache.aries.jmx.core - Registering MBean with ObjectName [osgi.compendium:service=cm,version=1.3,framework=org.apache.felix.framework,uuid=6361fc65-8df4-4886-b0a6-479df2d61c83] for service with service.id [13]
+2013-11-30 07:01:58,747 - org.apache.aries.jmx.core - Registering org.osgi.jmx.service.cm.ConfigurationAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.compendium:service=cm,version=1.3,framework=org.apache.felix.framework,uuid=6361fc65-8df4-4886-b0a6-479df2d61c83
+{code}
+
+The pattern is a regular Log4j pattern where you can use keywords like %d for the date, %c for the class, %m for the log
+message, etc.
+
+h3. {{log:exception-display}}
+
+The {{log:exception-display}} command displays the last occurred exception.
+
+As for {{log:display}} command, the {{log:exception-display}} command uses the {{rootLogger}} by default, but you can
+specify a logger with the {{logger}} argument.
+
+h3. {{log:get}}
+
+The {{log:get}} command show the current log level of a logger.
+
+By default, the log level showed is the one from the root logger:
+
+{code}
+karaf@root()> log:get
+INFO
+{code}
+
+You can specify a particular logger using the {{logger}} argument:
+
+{code}
+karaf@root()> log:get ssh
+INFO
+{code}
+
+The {{logger}} argument accepts the {{ALL}} keyword to display the log level of all logger (as a list).
+
+For instance, if you have defined your own logger in {{etc/org.ops4j.pax.logging.cfg}} file like this:
+
+{code}
+log4j.logger.my.logger = DEBUG
+{code}
+
+you can see the list of loggers with the corresponding log level:
+
+{code}
+karaf@root()> log:get ALL
+ROOT: INFO
+my.logger: DEBUG
+{code}
+
+The {{log:list}} command is an alias to {{log:get ALL}}.
+
+h3. {{log:log}}
+
+The {{log:log}} command allows you to manually add a message in the log. It's interesting when you create Apache Karaf
+scripts:
+
+{code}
+karaf@root()> log:log "Hello World"
+karaf@root()> log:display
+2013-11-30 07:20:16,544 | INFO  | Local user karaf | command                          | 59 - org.apache.karaf.log.command - 3.0.0 | Hello World
+{code}
+
+By default, the log level is INFO, but you can specify a different log level using the {{-l}} option:
+
+{code}
+karaf@root()> log:log -l ERROR "Hello World"
+karaf@root()> log:display
+2013-11-30 07:21:38,902 | ERROR | Local user karaf | command                          | 59 - org.apache.karaf.log.command - 3.0.0 | Hello World
+{code}
+
+h3. {{log:set}}
+
+The {{log:set}} command sets the log level of a logger.
+
+By default, it changes the log level of the {{rootLogger}}:
+
+{code}
+karaf@root()> log:set DEBUG
+karaf@root()> log:get
+DEBUG
+{code}
+
+You can specify a particular logger using the {{logger}} argument, after the {{level}} one:
+
+{code}
+karaf@root()> log:set INFO my.logger
+karaf@root()> log:get my.logger
+INFO
+{code}
 
-h2. Console Log Commands
+The {{level}} argument accepts any Log4j log level: TRACE, DEBUG, INFO, WARN, ERROR, FATAL.
+
+By it also accepts the DEFAULT special keyword.
+
+The purpose of the DEFAULT keyword is to delete the current level of the logger (and only the level, the other properties
+like appender are not deleted)
+in order to use the level of the logger parent (logger are hierarchical).
+
+For instance, you have defined the following loggers (in {{etc/org.ops4j.pax.logging.cfg}} file):
+
+{code}
+rootLogger=INFO,out,osgi:*
+my.logger=INFO,appender1
+my.logger.custom=DEBUG,appender2
+{code}
 
-The log subshell comes with the following commands:
-* [{{log:clear}}|/commands/log-clear]: clear the log
-* [{{log:display}}|/commands/log-display]: display the last log entries
-* [{{log:display-exception}}|/commands/log-display-exception]: display the last exception from the log
-* [{{log:get}}|/commands/log-get]: show the log levels. {{log:get ALL}} displays the level of all loggers.
-* {{log:list}}: is an alias to {{log:get ALL}}.
-* [{{log:set}}|/commands/log-set]: set the log levels. NB: this command doesn't update {{etc/org.ops4j.pax.logging.cfg}} file. You have to use {{config:edit}} to do so. It's possible to reload the log level from the configuration file using {{log:set DEFAULT}}.
-* [{{log:tail}}|/commands/log-tail]: continuous display of the log entries
+You can change the level of {{my.logger.custom}} logger:
 
-For example, if you want to debug something, you might want to run the following commands:
 {code}
-> log:set DEBUG
-... do something ...
-> log:display
+karaf@root()> log:set INFO my.logger.custom
 {code}
 
-Note that the log levels set using the {{log:set}} commands are not persistent and will be lost upon restart.
-To configure those in a persistent way, you should edit the configuration file mentioned above using the config commands or directly using a text editor of your choice.
+Now we have:
 
-The log commands has a separate configure file:
 {code}
-[karaf_install_dir]/etc/org.apache.karaf.log.cfg
+rootLogger=INFO,out,osgi:*
+my.logger=INFO,appender1
+my.logger.custom=INFO,appender2
 {code}
 
-h2. JMX
+You can use the DEFAULT keyword on {{my.logger.custom}} logger to remove the level:
 
-Karaf provides a Log MBean (org.apache.karaf:type=log) providing quite the same actions that can be performed using
-the log:* shell commands.
+{code}
+karaf@root()> log:set DEFAULT my.logger.custom
+{code}
+
+Now we have:
+
+{code}
+rootLogger=INFO,out,osgi:*
+my.logger=INFO,appender1
+my.logger.custom=appender2
+{code}
+
+It means that, at runtime, the {{my.logger.custom}} logger uses the level of its parent {{my.logger}}, so {{INFO}}.
+
+Now, if we use DEFAULT keyword with the {{my.logger}} logger:
+
+{code}
+karaf@root()> log:set DEFAULT my.logger
+{code}
+
+We have:
+
+{code}
+rootLogger=INFO,out,osgi:*
+my.logger=appender1
+my.logger.custom=appender2
+{code}
+
+So, both {{my.logger.custom}} and {{my.logger}} use the log level of the parent {{rootLogger}}.
+
+It's not posible to use DEFAULT keyword with the {{rootLogger}} and it doesn't have parent.
+
+h3. {{log:tail}}
+
+The {{log:tail}} is exactly the same as {{log:display}} but it continuously displays the log entries.
+
+You can use the same options and arguments as for the {{log:display}} command.
+
+By default, it displays the entries from the {{rootLogger}}:
+
+{code}
+karaf@root()> log:tail
+2013-11-30 07:40:28,152 | INFO  | FelixStartLevel  | SecurityUtils                    | 16 - org.apache.sshd.core - 0.9.0 | BouncyCastle not registered, using the default JCE provider
+2013-11-30 07:40:28,909 | INFO  | FelixStartLevel  | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Starting JMX OSGi agent
+2013-11-30 07:40:28,928 | INFO  | FelixStartLevel  | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering MBean with ObjectName [osgi.compendium:service=cm,version=1.3,framework=org.apache.felix.framework,uuid=b44a44b7-41cd-498f-936d-3b12d7aafa7b] for service with service.id [13]
+2013-11-30 07:40:28,936 | INFO  | JMX OSGi Agent   | core                             | 68 - org.apache.aries.jmx.core - 1.1.1 | Registering org.osgi.jmx.service.cm.ConfigurationAdminMBean to MBeanServer com.sun.jmx.mbeanserver.JmxMBeanServer@27cc75cb with name osgi.compendium:service=cm,version=1.3,framework=org.apache.felix.framework,uuid=b44a44b7-41cd-498f-936d-3b12d7aafa7b
+{code}
+
+To exit from the {{log:tail}} command, just type CTRL-C.
+
+h2. JMX LogMBean
+
+All actions that you can perform with the {{log:*}} command can be performed using the LogMBean.
+
+The LogMBean object name is {{org.apache.karaf:type=log,name=*}}.
+
+h3. Attributes
+
+The LogMBean doesn't provide any attribute.
+
+h3. Operations
+
+* {{getLevel()}} to get the log level of the root logger.
+* {{getLevel(logger)}} to get the log level of a specific logger.
+* {{setLevel(level)}} to set the log level of the root logger.
+* {{setLevel(level, logger)}} to set the log level of a specific logger.
 
 h2. Advanced configuration
 
-The logging backend uses Log4j, but offer a number of additional features.
+h3. Filters
+
+You can use filters on appender. Filters allow log events to be evaluated to determine if or how they should be published.
 
-h3. Nested filters, appenders and error handlers
+Log4j provides ready to use filters:
 
-h4. Filters
+* The DenyAllFilter ({{org.apache.log4j.varia.DenyAllFilter}}) drops all logging events.
+ You can add this filter to the end of a filter chain to switch from the default "accept all unless instructed otherwise"
+ filtering behaviour to a "deny all unless instructed otherwise" behaviour.
+* The LevelMatchFilter ({{org.apache.log4j.varia.LevelMatchFilter}} is a very simple filter based on level matching.
+ The filter admits two options {{LevelToMatch}} and {{AcceptOnMatch}}. If there is an exact match between the value of
+ the {{LevelToMatch}} option and the level of the logging event, then the event is accepted in case the {{AcceptOnMatch}}
+ option value is set to {{true}}. Else, if the {{AcceptOnMatch}} option value is set to {{false}}, the log event is rejected.
+* The LevelRangeFilter ({{org.apache.log4j.varia.LevelRangeFilter}} is a very simple filter based on level matching,
+ which can be used to reject messages with priorities outside a certain range. The filter admits three options {{LevelMin}},
+ {{LevelMax}} and {{AcceptOnMatch}}. If the log event level is between {{LevelMin}} and {{LevelMax}}, the log event is
+ accepted if {{AcceptOnMatch}} is true, or rejected if {{AcceptOnMatch}} is false.
+* The StringMatchFilter ({{org.apache.log4j.varia.StringMatchFilter}}) is a very simple filter based on string matching.
+ The filter admits two options {{StringToMatch}} and {{AcceptOnMatch}}. If there is a match between the {{StringToMatch}}
+ and the log event message, the log event is accepted if {{AcceptOnMatch}} is true, or rejected if {{AcceptOnMatch}} is false.
 
-Appender filters can be added using the following syntax:
-{pygmentize:text}
+The filter is defined directly on the appender, in the {{etc/org.ops4j.pax.logging.cfg}} configuration file.
+
+The format to use it:
+
+{code}
 log4j.appender.[appender-name].filter.[filter-name]=[filter-class]
 log4j.appender.[appender-name].filter.[filter-name].[option]=[value]
-{pygmentize}
+{code}
+
+For instance, you can use the {{f1}} LevelRangeFilter on the {{out}} default appender:
 
-Below is a real example:
-{pygmentize:text}
+{code}
 log4j.appender.out.filter.f1=org.apache.log4j.varia.LevelRangeFilter
 log4j.appender.out.filter.f1.LevelMax=FATAL
 log4j.appender.out.filter.f1.LevelMin=DEBUG
-{pygmentize}
+{code}
+
+Thanks to this filter, the log files generated by the {{out}} appender will contain only log messages with a level
+between DEBUG and FATAL (the log events with TRACE as level are rejected).
+
+h3. Nested appenders
+
+A nested appender is a special kind of appender that you use "inside" another appender.
+It allows you to create some kind of "routing" between a chain of appenders.
+
+The most used "nested compliant" appender are:
 
-h4. Nested appenders
+* The AsyncAppender ({{org.apache.log4j.AsyncAppender}}) logs events asynchronously. This appender collects the events
+ and dispatch them to all the appenders that are attached to it.
+* The RewriteAppender ({{org.apache.log4j.rewrite.RewriteAppender}}) forwards log events to another appender after possibly
+ rewriting the log event.
 
-Nested appenders can be added using the following syntax:
-{pygmentize:text}
+This kind of appender accepts an {{appenders}} property in the appender definition:
+
+{code}
 log4j.appender.[appender-name].appenders=[comma-separated-list-of-appender-names]
-{pygmentize}
+{code}
 
-Below is a real example:
-{pygmentize:text}
+For instance, you can create a AsyncAppender named {{async}} and asynchronously dispatch the log events to a JMS appender:
+
+{code}
 log4j.appender.async=org.apache.log4j.AsyncAppender
 log4j.appender.async.appenders=jms
 
 log4j.appender.jms=org.apache.log4j.net.JMSAppender
 ...
-{pygmentize}
+{code}
+
+h3. Error handlers
+
+Sometime, appenders can fail. For instance, a RollingFileAppender tries to write on the filesystem but the filesystem is full, or a JMS appender tries to send a message but the JMS broker is not there.
+
+As log can be very critical to you, you have to be inform that the log appender failed.
+
+It's the purpose of the error handlers. Appenders may delegate their error handling to error handlers, giving a chance to react to this appender errors.
+
+You have two error handlers available:
 
-h4. Error handlers
+* The OnlyOnceErrorHandler ({{org.apache.log4j.helpers.OnlyOnceErrorHandler}}) implements log4j's default error handling policy
+ which consists of emitting a message for the first error in an appender and ignoring all following errors. The error message
+ is printed on {{System.err}}.
+ This policy aims at protecting an otherwise working application from being flooded with error messages when logging fails.
+* The FallbackErrorHandler ({{org.apache.log4j.varia.FallbackErrorHandler}}) allows a secondary appender to take over if the primary appender fails.
+ The error message is printed on {{System.err}}, and logged in the secondary appender.
 
-Error handlers can be added using the following syntax:
-{pygmentize:text}
+You can define the error handler that you want to use for each appender using the {{errorhandler}} property on the appender definition itself:
+
+{code}
 log4j.appender.[appender-name].errorhandler=[error-handler-class]
 log4j.appender.[appender-name].errorhandler.root-ref=[true|false]
 log4j.appender.[appender-name].errorhandler.logger-ref=[logger-ref]
 log4j.appender.[appender-name].errorhandler.appender-ref=[appender-ref]
-{pygmentize}
+{code}
 
 h3. OSGi specific MDC attributes
 
-Pax-Logging provides the following attributes by default:
-* {{bundle.id}}: the id of the bundle from which the class is loaded
-* {{bundle.name}}: the symbolic-name of the bundle
-* {{bundle.version}}: the version of the bundle
+The {{sift}} appender is a OSGi oriented appender allowing you to split the log events based on MDC (Mapped Diagnostic Context) attributes.
+
+MDC allows you to distinguish the different source of log events.
+
+The {{sift}} appender provides OSGi oritend MDC attributes by default:
+
+* {{bundle.id}} is the bundle ID
+* {{bundle.name}} is the bundle symbolic name
+* {{bundle.version}} is the bundle version
 
-An MDC sifting appender is available to split the log events based on MDC attributes.  Below is a configuration example for this appender:
-{pygmentize:text}
+You can use these MDC properties to create a log file per bundle:
+
+{code}
 log4j.appender.sift=org.apache.log4j.sift.MDCSiftingAppender
 log4j.appender.sift.key=bundle.name
 log4j.appender.sift.default=karaf
@@ -139,45 +483,61 @@ log4j.appender.sift.appender.layout=org.
 log4j.appender.sift.appender.layout.ConversionPattern=%d{ABSOLUTE} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
 log4j.appender.sift.appender.file=${karaf.data}/log/$\\{bundle.name\\}.log
 log4j.appender.sift.appender.append=true
-{pygmentize}
+{code}
 
 h3. Enhanced OSGi stack trace renderer
 
-This renderer is configured by default in Karaf and will give additional informations when printing stack traces.
-For each line of the stack trace, it will display OSGi specific informations related to the class on that line: the bundle id, the bundle symbolic name and the bundle version.  This information can greatly help diagnosing problems in some cases.
-The information is appended at the end of each line in the following format {{[id:name:version]}} as shown below
-{pygmentize:text}
+By default, Apache Karaf provides a special stack trace renderer, adding some OSGi specific specific information.
+
+In the stack trace, in addition of the class throwing the exception, you can find a pattern {{[id:name:version]}} at the
+end of each stack trace line, where:
+
+* {{id}} is the bundle ID
+* {{name}} is the bundle name
+* {{version}} is the bundle version
+
+It's very helpful to diagnosing the source of an issue.
+
+For instance, in the following IllegalArgumentException stack trace, we can see the OSGi details about the source of the exception:
+
+{code}
 java.lang.IllegalArgumentException: Command not found:  *:foo
-	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:225)[21:org.apache.karaf.shell.console:2.1.0]
-	at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:162)[21:org.apache.karaf.shell.console:2.1.0]
-	at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:101)[21:org.apache.karaf.shell.console:2.1.0]
-	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:79)[21:org.apache.karaf.shell.console:2.1.0]
-	at org.apache.felix.gogo.runtime.shell.CommandSessionImpl.execute(CommandSessionImpl.java:71)[21:org.apache.karaf.shell.console:2.1.0]
-	at org.apache.karaf.shell.console.jline.Console.run(Console.java:169)[21:org.apache.karaf.shell.console:2.1.0]
-	at java.lang.Thread.run(Thread.java:637)[:1.6.0_20]
-{pygmentize}
+	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:225)[21:org.apache.karaf.shell.console:3.0.0]
+	at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:162)[21:org.apache.karaf.shell.console:3.0.0]
+	at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:101)[21:org.apache.karaf.shell.console:3.0.0]
+	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:79)[21:org.apache.karaf.shell.console:3.0.0]
+	at org.apache.felix.gogo.runtime.shell.CommandSessionImpl.execute(CommandSessionImpl.java:71)[21:org.apache.karaf.shell.console:3.0.0]
+	at org.apache.karaf.shell.console.jline.Console.run(Console.java:169)[21:org.apache.karaf.shell.console:3.0.0]
+	at java.lang.Thread.run(Thread.java:637)[:1.7.0_21]
+{code}
+
+h3. Custom appenders
 
-h3. Using your own appenders
+You can use your own appenders in Apache Karaf.
 
-If you plan to use your own appenders, you need to create an OSGi bundle and attach it as a fragment to the bundle with a symbolic name of 
-{{org.ops4j.pax.logging.pax-logging-service}}.  This way, the underlying logging system will be able to see and use your appenders.
+The easiest way to do that is to package your appender as an OSGi bundle and attach it as a fragment of the
+{{org.ops4j.pax.logging.pax-logging-service}} bundle.
 
-So for example you write a log4j appender:
-class MyAppender extends AppenderSkeleton {
+For instance, you create {{MyAppender}}:
+
+{code}
+public class MyAppender extends AppenderSkeleton {
 ...
 }
+{code}
 
-Then you need to package the appender in a jar with a Manifest like this:
+You compile and package as an OSGi bundle containing a MANIFEST looking like:
 
+{code}
 Manifest:
 Bundle-SymbolicName: org.mydomain.myappender       
 Fragment-Host: org.ops4j.pax.logging.pax-logging-service
 ...
+{code}
 
-Copy the new appender fragment into the ${karaf.home}/system directory. Karaf uses a virtual maven repository to access resources in the system
-directory, so the jar path should use the standard maven groupId/artifactId/version/ convention, where the groupId is a directory structure.
+Copy your bundle in the Apache Karaf {{system}} folder. The {{system}} folder uses a standard Maven directory layout: groupId/artifactId/version.
 
-Edit ${karaf.home}/etc/startup.properties and add the new fragment bundle to the list before the pax-logging-service bundle.
+In the {{etc/startup.properties}} configuration file, you define your bundle in the list before the pax-logging-service bundle.
 
-Restart karaf with a clean run to reload the system bundles, and now you can use the appender in your log4j config file like shown in the config
-examples above.
+You have to restart Apache Karaf with a clean run (purging the {{data}} folder) in order to reload the system bundles.
+You can now use your appender directly in {{etc/org.ops4j.pax.logging.cfg}} configuration file.