| <!-- |
| 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. |
| |
| --> |
| <document> |
| <properties> |
| <title>How to use Apache log4cxx</title> |
| </properties> |
| |
| <body> |
| <section name="Loggers"> |
| <p> |
| Log4cxx has three main components: <em>loggers</em>, |
| <em>appenders</em> and <em>layouts</em>. These three types of |
| components work together to enable developers to log messages according |
| to message type and level, and to control at runtime how these |
| messages are formatted and where they are reported. |
| </p> |
| |
| <subsection name="Hierarchy"> |
| <p> |
| The first and foremost advantage of any logging API over plain |
| <code>std::cout</code> resides in its ability to disable |
| certain log statements while allowing others to print unhindered. This |
| capability assumes that the logging space, that is, the space of all |
| possible logging statements, is categorized according to some |
| developer-chosen criteria. |
| </p> |
| |
| <p> |
| Loggers are named entities. Logger names are case-sensitive and |
| they follow the hierarchical naming rule: |
| </p> |
| |
| <dl> |
| <dt><strong>Named Hierarchy</strong></dt> |
| <dd> |
| A logger is said to be an <em>ancestor</em> of another |
| logger if its name followed by a dot is a prefix of the |
| <em>descendant</em> logger name. A logger is said to be a |
| <em>parent</em> of a <em>child</em> logger if there are no |
| ancestors between itself and the descendant logger. |
| </dd> |
| </dl> |
| |
| <p> |
| For example, the logger named <code>"com.foo"</code> is a parent |
| of the logger named <code>"com.foo.Bar"</code>. Similarly, |
| <code>"java"</code> is a parent of <code>"java.util"</code> and an |
| ancestor of <code>"java.util.Vector"</code>. This naming scheme |
| should be familiar to most developers. |
| </p> |
| |
| <p> |
| The root logger resides at the top of the logger hierarchy. It |
| is exceptional in two ways: |
| </p> |
| |
| <ol> |
| <li> it always exists,</li> |
| <li> it cannot be retrieved by name.</li> |
| </ol> |
| |
| <p> |
| Invoking the class static <a href="apidocs/classlog4cxx_1_1_logger.html#afc0e4d99cab7c38a2851d41e6edc1dee">log4cxx::Logger::getRootLogger</a> |
| method retrieves it. All other loggers are instantiated and retrieved with the class static |
| <a href="apidocs/classlog4cxx_1_1_logger.html#a76017df17da02bc11bfe50e47de703a3">log4cxx::Logger::getLogger</a> |
| method. This method takes the name of the desired logger as a parameter. Some of the basic methods in the Logger |
| class are listed below. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| namespace log4cxx { |
| class <strong>Logger</strong> { |
| public: |
| // Creation & retrieval methods: |
| static LoggerPtr getRootLogger(); |
| static LoggerPtr getLogger(const std::string& name); |
| static LoggerPtr getLogger(const std::wstring& name); |
| } |
| } |
| |
| // |
| // Use these macros instead of calling Logger methods directly. |
| // Macros will handle char or wchar_t pointers or strings |
| // or most right-hand side expressions of an |
| // std::basic_string::operator<<. |
| // |
| #define LOG4CXX_TRACE(logger, expression) ... |
| #define LOG4CXX_DEBUG(logger, expression) ... |
| #define LOG4CXX_INFO(logger, expression) ... |
| #define LOG4CXX_WARN(logger, expression) ... |
| #define LOG4CXX_ERROR(logger, expression) ... |
| #define LOG4CXX_FATAL(logger, expression) ...</pre> |
| </subsection> |
| |
| <subsection name="Levels"> |
| <p> |
| Loggers <em>may</em> be assigned levels. The pre-defined |
| levels: TRACE, DEBUG, INFO, WARN, ERROR and FATAL are defined in the |
| <code><a href="apidocs/classlog4cxx_1_1_level.html">log4cxx::Level</a></code> |
| class which provides accessor functions. |
| </p> |
| |
| <p> |
| If a given logger is not assigned a level, then it inherits |
| one from its closest ancestor with an assigned level. More |
| formally: |
| </p> |
| |
| <dl> |
| <dt><strong>Level Inheritance</strong></dt> |
| |
| <dd> |
| The <em>inherited level</em> for a given logger <i>C</i>, is equal to the |
| first non-null level in the logger hierarchy, starting at <i>C</i> and |
| proceeding upwards in the hierarchy towards the <code>root</code> logger. |
| </dd> |
| </dl> |
| |
| <p> |
| To ensure that all loggers can eventually inherit a level, |
| the root logger always has an assigned level. |
| </p> |
| |
| <p> |
| Below are four tables with various assigned level values and the |
| resulting inherited levels according to the above rule. |
| </p> |
| |
| <table border="1"> |
| <tr> |
| <th>Logger name</th> |
| <th>Assigned level</th> |
| <th>Inherited level</th> |
| </tr> |
| <tr align="left"> |
| <td>root</td> |
| <td>Proot</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X </td> |
| <td>none</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y </td> |
| <td>none</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y.Z</td> |
| <td>none</td> |
| <td>Proot</td> |
| </tr> |
| <caption align="bottom">Example 1</caption> |
| </table> |
| |
| <p> |
| In example 1 above, only the root logger is assigned a |
| level. This level value, <code>Proot</code>, is inherited by the |
| other loggers <code>X</code>, <code>X.Y</code> and |
| <code>X.Y.Z</code>. |
| </p> |
| |
| <table border="1"> |
| <tr> |
| <th>Logger name</th> |
| <th>Assigned level</th> |
| <th>Inherited level</th> |
| </tr> |
| <tr align="left"> |
| <td>root</td> |
| <td>Proot</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X </td> |
| <td>Px</td> |
| <td>Px</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y </td> |
| <td>Pxy</td> |
| <td>Pxy</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y.Z</td> |
| <td>Pxyz</td> |
| <td>Pxyz</td> |
| </tr> |
| <caption align="bottom">Example 2</caption> |
| </table> |
| |
| <p> |
| In example 2, all loggers have an assigned level value. There |
| is no need for level inheritence. |
| </p> |
| |
| <table border="1"> |
| <tr> |
| <th>Logger name</th> |
| <th>Assigned level</th> |
| <th>Inherited level</th> |
| </tr> |
| <tr align="left"> |
| <td>root</td> |
| <td>Proot</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X </td> |
| <td>Px</td> |
| <td>Px</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y </td> |
| <td>none</td> |
| <td>Px</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y.Z</td> |
| <td>Pxyz</td> |
| <td>Pxyz</td> |
| </tr> |
| <caption align="bottom">Example 3</caption> |
| </table> |
| |
| <p> |
| In example 3, the loggers <code>root</code>, <code>X</code> and |
| <code>X.Y.Z</code> are assigned the levels <code>Proot</code>, |
| <code>Px</code> and <code>Pxyz</code> respectively. The logger |
| <code>X.Y</code> inherits its level value from its parent |
| <code>X</code>. |
| </p> |
| |
| <table border="1"> |
| <tr> |
| <th>Logger name</th> |
| <th>Assigned level</th> |
| <th>Inherited level</th> |
| </tr> |
| <tr align="left"> |
| <td>root</td> |
| <td>Proot</td> |
| <td>Proot</td> |
| </tr> |
| <tr align="left"> |
| <td>X </td> |
| <td>Px</td> |
| <td>Px</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y </td> |
| <td>none</td> |
| <td>Px</td> |
| </tr> |
| <tr align="left"> |
| <td>X.Y.Z</td> |
| <td>none</td> |
| <td>Px</td> |
| </tr> |
| <caption align="bottom">Example 4</caption> |
| </table> |
| |
| <p> |
| In example 4, the loggers <code>root</code> and <code>X</code> |
| and are assigned the levels <code>Proot</code> and <code>Px</code> |
| respectively. The loggers <code>X.Y</code> and <code>X.Y.Z</code> |
| inherits their level value from their nearest parent <code>X</code> |
| having an assigned level. |
| </p> |
| </subsection> |
| |
| <subsection name="Requests"> |
| <p> |
| Logging requests are made by invoking a method of |
| a logger instance, preferrably through the use of LOG4CXX_INFO or similar |
| macros which support short-circuiting if the threshold is not satisfied |
| and use of the insertion operator (<<) in the message parameter. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(<strong>"com.foo"</strong>)); |
| const char* region = "World"; |
| LOG4CXX_INFO(logger, "Simple message text.") |
| LOG4CXX_INFO(logger, "Hello, " << region) |
| LOG4CXX_DEBUG(logger, L"Iteration " << i) |
| LOG4CXX_DEBUG(logger, "e^10 = " << std::scientific << exp(10.0)) |
| // |
| // Use a wchar_t first operand to force use of wchar_t based stream. |
| // |
| LOG4CXX_WARN(logger, L"" << i << L" is the number of the iteration.")</pre> |
| |
| <p> |
| A logging request is said to be <em>enabled</em> if its level is |
| higher than or equal to the level of its logger. Otherwise, the |
| request is said to be <em>disabled</em>. A logger without an |
| assigned level will inherit one from the hierarchy. This rule is |
| summarized below. |
| </p> |
| |
| <dl> |
| <dt><strong>Basic Selection Rule</strong></dt> |
| |
| <dd> |
| A log request of level <i>p</i> in a logger with (either assigned or |
| inherited, whichever is appropriate) level <i>q</i>, is enabled if |
| <i>p >= q</i>. |
| </dd> |
| </dl> |
| |
| <p> |
| This rule is at the heart of log4cxx. It assumes that levels are |
| ordered. For the standard levels, we have <code>TRACE < DEBUG < INFO |
| < WARN < ERROR < FATAL</code>. |
| </p> |
| |
| <p> |
| Here is an example of this rule. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| // get a logger instance named "com.foo" |
| log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(<strong>"com.foo"</strong>)); |
| |
| // Now set its level. Normally you do not need to set the |
| // level of a logger programmatically. This is usually done |
| // in configuration files. |
| <strong>logger</strong>->setLevel(<strong class="set-level-highlight">log4cxx::Level::getInfo()</strong>); |
| |
| log4cxx::LoggerPtr barlogger(log4cxx::Logger::getLogger(<strong>"com.foo.Bar"</strong>)); |
| |
| // This request is enabled, because <strong class="log-level compare-a">WARN</strong> >= <strong class="log-level compare-b">INFO</strong>. |
| LOG4CXX_WARN(logger, "Low fuel level.") |
| |
| // This request is disabled, because <strong class="log-level compare-a">DEBUG</strong> < <strong class="log-level compare-b">INFO</strong>. |
| LOG4CXX_DEBUG(logger, "Starting search for nearest gas station.") |
| |
| // The logger instance barlogger, named "com.foo.Bar", |
| // will inherit its level from the logger named |
| // "com.foo" Thus, the following request is enabled |
| // because <strong class="log-level compare-a">INFO</strong> >= <strong class="log-level compare-b">INFO</strong>. |
| LOG4CXX_INFO(barlogger. "Located nearest gas station.") |
| |
| // This request is disabled, because <strong class="log-level compare-a">DEBUG</strong> < <strong class="log-level compare-b">INFO</strong>. |
| LOG4CXX_DEBUG(barlogger, "Exiting gas station search")</pre> |
| |
| <p> |
| Calling the <code>getLogger</code> method with the same name will |
| always return a reference to the exact same logger object. |
| </p> |
| |
| <p> |
| For example, in |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| log4cxx::LoggerPtr x = log4cxx::Logger::getLogger("wombat"); |
| log4cxx::LoggerPtr y = log4cxx::Logger::getLogger("wombat");</pre> |
| <p> |
| <code>x</code> and <code>y</code> refer to <em>exactly</em> the same logger object. |
| </p> |
| |
| <p> |
| Thus, it is possible to configure a logger and then to retrieve |
| the same instance somewhere else in the code without passing around |
| references. In fundamental contradiction to biological parenthood, |
| where parents always preceed their children, log4cxx loggers can be |
| created and configured in any order. In particular, a "parent" |
| logger will find and link to its descendants even if it is |
| instantiated after them. |
| </p> |
| |
| <p> |
| Configuration of the log4cxx environment is typically done at |
| application initialization. The preferred way is by reading a |
| configuration file. This approach will be discussed shortly. |
| </p> |
| |
| <p> |
| Log4cxx makes it easy to name loggers by <em>software |
| component</em>. This can be accomplished by statically instantiating |
| a logger in each class, with the logger name equal to the fully |
| qualified name of the class. This is a useful and straightforward |
| method of defining loggers. As the log output bears the name of the |
| generating logger, this naming strategy makes it easy to identify |
| the origin of a log message. However, this is only one possible, |
| albeit common, strategy for naming loggers. Log4cxx does not restrict |
| the possible set of loggers. The developer is free to name the |
| loggers as desired. |
| </p> |
| |
| <p> |
| Nevertheless, naming loggers after the class where they are |
| located seems to be the best strategy known so far. |
| </p> |
| </subsection> |
| </section> |
| |
| <section name="Appenders and Layouts"> |
| <p> |
| The ability to selectively enable or disable logging requests based |
| on their logger is only part of the picture. Log4cxx allows logging |
| requests to print to multiple destinations. In log4cxx speak, an output |
| destination is called an <em>appender</em>. Currently, appenders exist |
| for the <a href="apidocs/classlog4cxx_1_1_console_appender.html">console</a>, |
| <a href="apidocs/classlog4cxx_1_1_file_appender.html">files</a>, GUI |
| components, <a href="apidocs/classlog4cxx_1_1net_1_1_socket_appender.html">remote socket</a> |
| servers, <a href="apidocs/classlog4cxx_1_1nt_1_1_n_t_event_log_appender.html"> NT Event Loggers</a>, and remote UNIX |
| <a href="apidocs/classlog4cxx_1_1net_1_1_syslog_appender.html">Syslog</a> |
| daemons. It is also possible to log <a href="apidocs/classlog4cxx_1_1_async_appender.html">asynchronously</a>. |
| </p> |
| |
| <p>More than one appender can be attached to a logger.</p> |
| |
| <p> |
| The <a href="apidocs/classlog4cxx_1_1_logger.html#a7c0629acee8dbd1251474bea15d7c9e2">addAppender</a> |
| method adds an appender to a given logger. |
| |
| <strong> |
| Each enabled logging request for a given logger will be forwarded to all the |
| appenders in that logger as well as the appenders higher in the hierarchy. |
| </strong> |
| In other words, appenders are inherited additively from the logger hierarchy. |
| For example, if a console appender is added to the root logger, then all enabled |
| logging requests will at least print on the console. If in addition a file appender |
| is added to a logger, say <em>C</em>, then enabled logging requests for <em>C</em> and |
| <em>C</em>'s children will print on a file <em>and</em> on the console. It is possible |
| to override this default behavior so that appender accumulation is no longer additive |
| by <a href="apidocs/classlog4cxx_1_1_logger.html#a80f9397947dba9071ad485f178257c17">setting the additivity flag</a> to |
| <code>false</code>. |
| </p> |
| |
| <p>The rules governing appender additivity are summarized below.</p> |
| |
| <dl> |
| <dt><strong>Appender Additivity</strong></dt> |
| |
| <dd> |
| The output of a log statement of logger <i>C</i> will go to all the appenders |
| in <i>C</i> and its ancestors. This is the meaning of the term "appender |
| additivity". However, if an ancestor of logger <i>C</i>, say <i>P</i>, has the |
| additivity flag set to <code>false</code>, then <i>C</i>'s output will be |
| directed to all the appenders in <i>C</i> and it's ancestors up to and |
| including <i>P</i> but, not the appenders in any of the ancestors of <i>P</i>. |
| <br /><br /> |
| Loggers have their additivity flag set to <code>true</code> by default. |
| </dd> |
| </dl> |
| |
| <p>The table below shows an example:</p> |
| |
| <table align="center" border="3" cellpadding="10"> |
| <tr rowspan="2"> |
| <th>Logger Name </th> |
| <th>Added Appenders</th> |
| <th>Additivity Flag</th> |
| <th>Output Targets</th> |
| <th>Comment</th> |
| </tr> |
| <tr> |
| <td>root</td> |
| <td>A1</td> |
| <td>not applicable</td> |
| <td>A1</td> |
| <td> |
| The root logger is anonymous but can be accessed with the |
| log4cxx::Logger::getRootLogger() method. There is no default appender |
| attached to root. |
| </td> |
| </tr> |
| <tr> |
| <td>x</td> |
| <td>A-x1, A-x2</td> |
| <td>true</td> |
| <td>A1, A-x1, A-x2</td> |
| <td>Appenders of "x" and root.</td> |
| </tr> |
| <tr> |
| <td>x.y</td> |
| <td>none</td> |
| <td>true</td> |
| <td>A1, A-x1, A-x2</td> |
| <td>Appenders of "x" and root.</td> |
| </tr> |
| <tr> |
| <td>x.y.z</td> |
| <td>A-xyz1</td> |
| <td>true</td> |
| <td>A1, A-x1, A-x2, A-xyz1</td> |
| <td>Appenders in "x.y.z", "x" and root.</td> |
| </tr> |
| <tr> |
| <td>security</td> |
| <td>A-sec</td> |
| <td> |
| <span class="activity-flag-highlight">false</span> |
| </td> |
| <td>A-sec</td> |
| <td> |
| No appender accumulation since the additivity flag is set to <code>false</code>. |
| </td> |
| </tr> |
| <tr> |
| <td>security.access</td> |
| <td>none</td> |
| <td>true</td> |
| <td>A-sec</td> |
| <td> |
| Only appenders of "security" because the additivity flag in "security" is |
| set to <code>false</code>. |
| </td> |
| </tr> |
| </table> |
| |
| <p> |
| More often than not, users wish to customize not only the output |
| destination but also the output format. This is accomplished by |
| associating a <em>layout</em> with an appender. The layout is |
| responsible for formatting the logging request according to the user's |
| wishes, whereas an appender takes care of sending the formatted output |
| to its destination. |
| </p> |
| |
| <p> |
| The <a href="apidocs/classlog4cxx_1_1_pattern_layout.html">PatternLayout</a>, part |
| of the standard log4cxx distribution, lets the user specify the output |
| format according to conversion patterns similar to the C language |
| <code>printf</code> function. |
| </p> |
| |
| <p> |
| For example, the PatternLayout with the conversion pattern "%r [%t] |
| %-5p %c - %m%n" will output something akin to: |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| 176 [main] INFO org.foo.Bar - Located nearest gas station.</pre> |
| |
| <p> |
| The first field is the number of milliseconds elapsed since the |
| start of the program. The second field is the thread making the log |
| request. The third field is the level of the log statement. The |
| fourth field is the name of the logger associated with the log |
| request. The text after the '-' is the message of the statement. |
| </p> |
| </section> |
| |
| <section name="Configuration"> |
| <p> |
| Inserting log requests into the application code requires a fair |
| amount of planning and effort. Observation shows that approximately 4 |
| percent of code is dedicated to logging. Consequently, even moderately |
| sized applications will have thousands of logging statements embedded |
| within their code. Given their number, it becomes imperative to |
| manage these log statements without the need to modify them manually. |
| </p> |
| |
| <p> |
| The log4cxx environment is fully configurable programmatically. |
| However, it is far more flexible to configure log4cxx using |
| configuration files. Currently, configuration files can be written in |
| XML or in Java properties (key=value) format. |
| </p> |
| |
| <p> |
| Let us give a taste of how this is done with the help of an |
| imaginary application <code>MyApp</code> that uses log4cxx. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| #include "com/foo/bar.h" |
| using namespace com::foo; |
| |
| // include log4cxx header files. |
| #include "log4cxx/logger.h" |
| #include "log4cxx/basicconfigurator.h" |
| #include "log4cxx/helpers/exception.h" |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| |
| LoggerPtr logger(Logger::getLogger("MyApp")); |
| |
| int main(int argc, char **argv) |
| { |
| int result = EXIT_SUCCESS; |
| try |
| { |
| // Set up a simple configuration that logs on the console. |
| BasicConfigurator::configure(); |
| |
| LOG4CXX_INFO(logger, "Entering application.") |
| Bar bar; |
| bar.doIt(); |
| LOG4CXX_INFO(logger, "Exiting application.") |
| } |
| catch(Exception&) |
| { |
| result = EXIT_FAILURE; |
| } |
| |
| return result; |
| }</pre> |
| |
| <p> |
| <code>MyApp</code> begins by including log4cxx headers. It |
| then defines a static logger variable with the name <code>MyApp</code> |
| which happens to be the fully qualified name of the |
| class. |
| </p> |
| |
| <p> |
| <code>MyApp</code> uses the <code>Bar</code> class defined in header |
| file <code>com/foo/bar.h</code>. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| // file com/foo/bar.h |
| #include "log4cxx/logger.h" |
| |
| namespace com { |
| namespace foo { |
| class Bar { |
| static log4cxx::LoggerPtr logger; |
| |
| public: |
| void doIt(); |
| } |
| } |
| }</pre> |
| |
| <pre class="prettyprint linenums"> |
| // file bar.cpp |
| #include "com/foo/bar.h" |
| |
| using namespace com::foo; |
| using namespace log4cxx; |
| |
| LoggerPtr Bar::logger(Logger::getLogger("com.foo.bar")); |
| |
| void Bar::doIt() { |
| LOG4CXX_DEBUG(logger, "Did it again!") |
| }</pre> |
| |
| <p> |
| The invocation of the <a href="apidocs/classlog4cxx_1_1_basic_configurator.html#a4f96a09e1372664e3556ce94ace4a70c">BasicConfigurator::configure</a> |
| method creates a rather simple log4cxx setup. This method is hardwired |
| to add to the root logger a <a href="apidocs/classlog4cxx_1_1_console_appender.html"> |
| ConsoleAppender</a>. The output will be formatted using a |
| <a href="apidocs/classlog4cxx_1_1_pattern_layout.html">PatternLayout</a> set |
| to the pattern "%-4r [%t] %-5p %c %x - %m%n". |
| </p> |
| |
| <p> |
| Note that by default, the root logger is assigned to |
| <code>Level::getDebug()</code>. |
| </p> |
| |
| <p> |
| The output of MyApp is: |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| 0 [12345] INFO MyApp - Entering application. |
| 36 [12345] DEBUG com.foo.Bar - Did it again! |
| 51 [12345] INFO MyApp - Exiting application.</pre> |
| |
| <p> |
| The previous example always outputs the same log information. |
| Fortunately, it is easy to modify <code>MyApp</code> so that the log |
| output can be controlled at run-time. Here is a slightly modified |
| version. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| // file MyApp2.cpp |
| |
| #include "com/foo/bar.h" |
| using namespace com::foo; |
| |
| // include log4cxx header files. |
| #include "log4cxx/logger.h" |
| #include "log4cxx/basicconfigurator.h" |
| #include "log4cxx/propertyconfigurator.h" |
| #include "log4cxx/helpers/exception.h" |
| |
| using namespace log4cxx; |
| using namespace log4cxx::helpers; |
| // Define a static logger variable so that it references the |
| // Logger instance named "MyApp". |
| LoggerPtr logger(Logger::getLogger("MyApp")); |
| |
| int main(int argc, char **argv) |
| { |
| int result = EXIT_SUCCESS; |
| try |
| { |
| if (argc > 1) |
| { |
| // BasicConfigurator replaced with PropertyConfigurator. |
| PropertyConfigurator::configure(argv[1]); |
| } |
| else |
| { |
| BasicConfigurator::configure(); |
| } |
| |
| LOG4CXX_INFO(logger, "Entering application.") |
| Bar bar |
| bar.doIt(); |
| LOG4CXX_INFO(logger, "Exiting application.") |
| } |
| catch(Exception&) |
| { |
| result = EXIT_FAILURE; |
| } |
| |
| return result; |
| }</pre> |
| |
| <p> |
| This version of <code>MyApp</code> instructs |
| <code>PropertyConfigurator</code> to parse a configuration file and |
| set up logging accordingly. |
| </p> |
| |
| <p> |
| Here is a sample configuration file that results in exactly same |
| output as the previous <code>BasicConfigurator</code> based example. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| # Set root logger level to DEBUG and its only appender to A1. |
| log4j.rootLogger=DEBUG, A1 |
| |
| # A1 is set to be a ConsoleAppender. |
| log4j.appender.A1=org.apache.log4j.ConsoleAppender |
| |
| # A1 uses PatternLayout. |
| log4j.appender.A1.layout=org.apache.log4j.PatternLayout |
| log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n</pre> |
| |
| <p> |
| It can be noticed that the PropertyConfigurator file format is the same as log4j. |
| </p> |
| |
| <p> |
| Suppose we are no longer interested in seeing the output of any |
| component belonging to the <code>com::foo</code> package. The following |
| configuration file shows one possible way of achieving this. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| log4j.rootLogger=DEBUG, A1 |
| log4j.appender.A1=org.apache.log4j.ConsoleAppender |
| log4j.appender.A1.layout=org.apache.log4j.PatternLayout |
| |
| # <strong>Print the date in ISO 8601 format</strong> |
| log4j.appender.A1.layout.ConversionPattern=<strong>%d</strong> [%t] %-5p %c - %m%n |
| |
| # Print only messages of level WARN or above in the package com.foo. |
| <strong>log4j.logger.com.foo=WARN</strong></pre> |
| |
| <p> |
| The output of <code>MyApp</code> configured with this file is shown below. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| <strong>2000-09-07 14:07:41,508</strong> [12345] INFO MyApp - Entering application. |
| <strong>2000-09-07 14:07:41,529</strong> [12345] INFO MyApp - Exiting application.</pre> |
| |
| <p> |
| As the logger <code>com.foo.Bar</code> does not have an assigned |
| level, it inherits its level from <code>com.foo</code>, which |
| was set to WARN in the configuration file. The log statement from the |
| <code>Bar::doIt</code> method has the level DEBUG, lower than the |
| logger level WARN. Consequently, <code>doIt()</code> method's log |
| request is suppressed. |
| </p> |
| |
| <p> |
| Here is another configuration file that uses multiple appenders. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| log4j.rootLogger=debug, <strong>stdout, R</strong> |
| |
| log4j.appender.<strong>stdout</strong>=org.apache.log4j.ConsoleAppender |
| log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
| |
| # Pattern to output the caller's file name and line number. |
| log4j.appender.stdout.layout.ConversionPattern=%5p [%t] <strong>(%F:%L)</strong> - %m%n |
| |
| log4j.appender.<strong>R</strong>=org.apache.log4j.RollingFileAppender |
| log4j.appender.R.File=example.log |
| |
| log4j.appender.R.MaxFileSize=<strong>100KB</strong> |
| # Keep one backup file |
| log4j.appender.R.MaxBackupIndex=1 |
| |
| log4j.appender.R.layout=org.apache.log4j.PatternLayout |
| log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n</pre> |
| |
| <p> |
| Calling the enhanced MyApp with the this configuration file will |
| output the following on the console. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| INFO [12345] <strong>(MyApp2.cpp:31)</strong> - Entering application. |
| DEBUG [12345] (Bar.h:16) - Doing it again! |
| INFO [12345] (MyApp2.cpp:34) - Exiting application.</pre> |
| |
| <p> |
| In addition, as the root logger has been allocated a second |
| appender, output will also be directed to the <code>example.log</code> |
| file. This file will be rolled over when it reaches 100KB. When |
| roll-over occurs, the old version of <code>example.log</code> is |
| automatically moved to <code>example.log.1</code>. |
| </p> |
| |
| <p> |
| Note that to obtain these different logging behaviors we did not |
| need to recompile code. We could just as easily have logged to a UNIX |
| Syslog daemon, redirected all <code>com.foo</code> output to an NT |
| Event logger, or forwarded logging events to a remote log4cxx server, |
| which would log according to local server policy, for example by |
| forwarding the log event to a second log4cxx server. |
| </p> |
| </section> |
| |
| <section name="Default Initialization Procedure"> |
| <p> |
| The log4cxx library does not make any assumptions about its |
| environment. In particular, there are no default log4cxx |
| appenders. Under certain well-defined circumstances however, the |
| static inializer of the <code>Logger</code> class will attempt to |
| automatically configure log4cxx. |
| </p> |
| |
| <p> |
| The exact default initialization algorithm is defined as follows: |
| </p> |
| |
| <ol> |
| <li> |
| <p> |
| Set the configurationOptionStr string variable to the value of the |
| <strong>LOG4CXX_CONFIGURATION</strong> environment variable if set, otherwise |
| the value of the <strong>log4j.configuration</strong> environment variable |
| if set, otherwise the first of the following file names which exist in the |
| current working directory, "log4cxx.xml", "log4cxx.properties", |
| "log4j.xml" and "log4j.properties". If configurationOptionStr has not been |
| set, then disable logging. |
| </p> |
| </li> |
| <li> |
| <p> |
| Unless a custom configurator is specified using the |
| <strong>LOG4CXX_CONFIGURATOR_CLASS</strong> or <strong>log4j.configuratorClass</strong> |
| environment variable, the PropertyConfigurator will be used to configure |
| log4cxx unless the file name ends with the ".xml" extension, |
| in which case the DOMConfigurator will be used. |
| If a custom configurator is specified, the environment variable |
| should contain a fully qualified class name of a class that |
| implements the Configurator interface. |
| </p> |
| </li> |
| </ol> |
| </section> |
| |
| <section name="Nested Diagnostic Contexts"> |
| <p> |
| Most real-world systems have to deal with multiple clients |
| simultaneously. In a typical multithreaded implementation of such a |
| system, different threads will handle different clients. Logging is |
| especially well suited to trace and debug complex distributed |
| applications. A common approach to differentiate the logging output of |
| one client from another is to instantiate a new separate logger for |
| each client. This promotes the proliferation of loggers and |
| increases the management overhead of logging. |
| </p> |
| |
| <p> |
| A lighter technique is to uniquely stamp each log request initiated |
| from the same client interaction. Neil Harrison described this method |
| in the book "Patterns for Logging Diagnostic Messages," in <em>Pattern |
| Languages of Program Design 3</em>, edited by R. Martin, D. Riehle, |
| and F. Buschmann (Addison-Wesley, 1997). |
| </p> |
| |
| <p> |
| To uniquely stamp each request, the |
| user pushes contextual information into the NDC, the abbreviation of |
| <em>Nested Diagnostic Context</em>. The NDC class is shown below. |
| </p> |
| |
| <pre class="prettyprint linenums"> |
| namespace log4cxx { |
| class NDC { |
| public: |
| // pushes the value on construction and pops on destruction. |
| NDC(const std::string& value); |
| NDC(const std::wstring& value); |
| |
| // Remove the top of the context from the NDC. |
| <strong>static</strong> LogString pop(); |
| |
| // Add diagnostic context for the current thread. |
| <strong>static</strong> void push(const std::string& message); |
| <strong>static</strong> void push(const std::wstring& message); |
| } |
| }</pre> |
| |
| <p> |
| The NDC is managed per thread as a <em>stack</em> of contextual |
| information. Note that all methods of the <code>log4cxx::NDC</code> |
| class are static. Assuming that NDC printing is turned on, every time |
| a log request is made, the appropriate log4cxx component will include |
| the <em>entire</em> NDC stack for the current thread in the log |
| output. This is done without the intervention of the user, who is |
| responsible only for placing the correct information in the NDC by |
| using the <code>push</code> and <code>pop</code> methods at a few |
| well-defined points in the code. In contrast, the per-client logger |
| approach commands extensive changes in the code. |
| </p> |
| |
| <p> |
| To illustrate this point, let us take the example of a servlet |
| delivering content to numerous clients. The servlet can build the NDC |
| at the very beginning of the request before executing other code. The |
| contextual information can be the client's host name and other |
| information inherent to the request, typically information contained |
| in cookies. Hence, even if the servlet is serving multiple clients |
| simultaneously, the logs initiated by the same code, i.e. belonging to |
| the same logger, can still be distinguished because each client |
| request will have a different NDC stack. Contrast this with the |
| complexity of passing a freshly instantiated logger to all code |
| exercised during the client's request. |
| </p> |
| |
| <p> |
| Nevertheless, some sophisticated applications, such as virtual |
| hosting web servers, must log differently depending on the virtual |
| host context and also depending on the software component issuing the |
| request. Recent log4cxx releases support multiple hierarchy trees. This |
| enhancement allows each virtual host to possess its own copy of the |
| logger hierarchy. |
| </p> |
| </section> |
| |
| <section name="Performance"> |
| <p> |
| One of the often-cited arguments against logging is its |
| computational cost. This is a legitimate concern as even moderately |
| sized applications can generate thousands of log requests. Much |
| effort was spent measuring and tweaking logging performance. Log4cxx |
| claims to be fast and flexible: speed first, flexibility second. |
| </p> |
| |
| <p> |
| The user should be aware of the following performance issues. |
| </p> |
| |
| <ol> |
| <li> |
| <p> |
| <strong>Logging performance when logging is turned off.</strong> |
| </p> |
| |
| <p> |
| When logging is turned off entirely or just for a set |
| of levels, the cost of a log request consists of a method |
| invocation plus an integer comparison. The LOG4CXX_DEBUG and similar |
| macros suppress unnecessary expression evaluation if the |
| request is not enabled. |
| </p> |
| </li> |
| |
| <li> |
| <p> |
| <strong>The performance of deciding whether to log or not to log when logging is turned on.</strong> |
| </p> |
| |
| <p> |
| This is essentially the performance of walking the logger |
| hierarchy. When logging is turned on, log4cxx still needs to compare |
| the level of the log request with the level of the request |
| logger. However, loggers may not have an assigned |
| level; they can inherit them from the logger hierarchy. Thus, |
| before inheriting a level, the logger may need to search its |
| ancestors. |
| </p> |
| |
| <p> |
| There has been a serious effort to make this hierarchy walk to |
| be as fast as possible. For example, child loggers link only to |
| their existing ancestors. In the <code>BasicConfigurator</code> |
| example shown earlier, the logger named <code>com.foo.Bar</code> is |
| linked directly to the root logger, thereby circumventing the |
| nonexistent <code>com</code> or <code>com.foo</code> loggers. This |
| significantly improves the speed of the walk, especially in "sparse" |
| hierarchies. |
| </p> |
| |
| <p> |
| The cost of walking the hierarchy is typically 3 |
| times slower than when logging is turned off entirely. |
| </p> |
| </li> |
| <li> |
| <p> |
| <strong>Actually outputting log messages</strong> |
| </p> |
| |
| <p> |
| This is the cost of formatting the log output and sending it to |
| its target destination. Here again, a serious effort was made to |
| make layouts (formatters) perform as quickly as possible. The same |
| is true for appenders. |
| </p> |
| </li> |
| </ol> |
| </section> |
| |
| <section name="Conclusions"> |
| <p> |
| Apache Log4cxx is a popular logging package written in C++. One of its |
| distinctive features is the notion of inheritance in loggers. Using |
| a logger hierarchy it is possible to control which log statements |
| are output at arbitrary granularity. This helps reduce the volume of |
| logged output and minimize the cost of logging. |
| </p> |
| |
| <p> |
| One of the advantages of the log4cxx API is its manageability. Once |
| the log statements have been inserted into the code, they can be |
| controlled with configuration files. They can be selectively enabled |
| or disabled, and sent to different and multiple output targets in |
| user-chosen formats. The log4cxx package is designed so that log |
| statements can remain in shipped code without incurring a heavy |
| performance cost. |
| </p> |
| </section> |
| </body> |
| </document> |