Apache Log4cxx
Version 1.3.0
|
To uniquely stamp each request to relate it to a particular source, you can push contextual information into the Nested Diagnostic Context (NDC) using the log4cxx::NDC class or the Mapped Diagnostic Context provided by log4cxx::MDC class. For an example using log4cxx::NDC refer to ndc-example.cpp.
The NDC is managed per thread as a stack of contextual information. When the layout specifies that the NDC is to be included, each log entry will include the entire stack for the current thread. A log4cxx::PatternLayout allows named entries of the MDC to be included in the log message. The user is responsible for placing the correct information in the NDC/MDC by creating a log4cxx::NDC or log4cxx::MDC stack variable at a few well-defined points in the code. In contrast, the per-client logger approach commands extensive changes in the code.
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.
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.
When dealing with large amounts of logging information, it can be useful to filter on messages that we are interested in. This filtering only takes places after determining that the level of the current logger would log the message in the first place (as shown in detail by the flow chart). Note that filters can only be applied on a per-appender basis, they do not globally affect anything.
The filtering system is similar in concept to Linux iptables rules, in that there is a chain of filters that can accept a log message, deny the log message, or pass the message on to the next filter. Accepting a log message means that the message will be logged immediately without consulting other filters. Denying has the opposite affect, immediately dropping the log message and not consulting any other filters.
See the documentation for Filter for some more information, or view a configuration sample.
The following filters are available:
The MapFilter allows filtering against data elements that are in the Mapped Diagnostic Context (log4cxx::MDC).
Parameter Name | Type | Description |
---|---|---|
Operator | LogString | If the operator is AND then all the key/value pairs must match; any other value is implicitly an OR and a match by any one of the key/value pairs will be considered to be a match. The default value is OR . |
AcceptOnMatch | LogString | Action to take when the filter matches. May be true or false . The default value is false . |
MDC key | LogString | Any name other than Operator or AcceptOnMatch is considered a key to the MDC along with the value to match on. Keys may only be specified once; duplicate keys will replace earlier ones. |
In this configuration, the MapFilter can be used to filter based on system inserted values such as IP address and/or Username. In this example, we assume that the program has inserted appropriate values for user.ip
and user.name
into the MDC. In this case, when both the IP address is 127.0.0.1
and the Username is test
, the entry will not be logged.
If we wanted to exclude multiple IP addresses from the log, we need to define a separate filter for each one as we don’t support wildcards. Since the default AcceptOnMatch
value is false
, we can simplify to a single line per filter. In the configuration below we would skip logs for IP addresses matching 192.168.0.5 - 7.
In the case where we only want to log entries from a particular set of IP addresses (not recommended as this could be a security vulnerability), we need to have a final DenyAllFilter
to catch the fall through. In this configuration, we would only log entries from 192.168.0.251 and 192.168.0.252.
The LocationInfoFilter allows filtering against the location in the file that the log statement was made. Location information must not be disabled in order for this filter to be effective. Location information is disabled with the LOG4CXX_DISABLE_LOCATION_INFO
macro.
Parameter Name | Type | Description |
---|---|---|
Operator | LogString | If the operator is AND then all the parts of the location(line number and method name) must match. If set to OR then only one needs to match. The default value is OR . |
AcceptOnMatch | bool | If true , accept the message when it matches the parameters. If false , deny the message when it matches the parameters. |
LineNumber | int | The line number to match on. The default line number is -1. |
Method | LogString | The method to match on. The method name may be compiler-specific. On GCC, the method name will look like Class::methodName |
Assume that our code looks something like the following:
For various reasons, we may want to know that we are about to do something, but we don't want to know each iteration of the loop. In order to filter out this one message we can create a LocationInfoFilter in order to specifiy the line number that this message is on in order to filter it out:
Doing this allows us to still see the "About to do something!" message, but ignore each iteration of the loop.