blob: 5e7bb293c21bc824d401acdd1ad6d1827cc9d74c [file] [log] [blame] [view]
Filtering Log Messages {#filters}
===
<!--
Note: License header cannot be first, as doxygen does not generate
cleanly if it before the '==='
-->
<!--
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.
-->
[TOC]
# Labeling Log Output {#labeling-log-output}
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 \ref 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.
# Excluding Log Output {#excluding-log-output}
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](@ref log4cxx.spi.Filter) for some more
information, or view a [configuration sample](@ref configuration-samples).
The following filters are available:
* [AndFilter](@ref log4cxx.filter.AndFilter) - Takes in a list of filters that must all match
* [DenyAllFilter](@ref log4cxx.filter.DenyAllFilter) - Drops all log messages that reach it
* [LevelMatchFilter](@ref log4cxx.filter.LevelMatchFilter) - Filter log messages based off of their level
* [LevelRangeFilter](@ref log4cxx.filter.LevelRangeFilter) - Filter log messages based off of their level in a given range
* [LocationInfoFilter](@ref log4cxx.filter.LocationInfoFilter) - Filter log messages based off of their location(line number and/or method name)
* [LoggerMatchFilter](@ref log4cxx.filter.LoggerMatchFilter) - Accept or deny depending on the logger that generated the message
* [MapFilter](@ref log4cxx.filter.MapFilter) - Based off of the log messages MDC, accept or deny the message
* [StringMatchFilter](@ref log4cxx.filter.StringMatchFilter) - If the given substring is found in the message, accept or deny
# Runtime Configuration {#configure-filter}
## Using MDC Values {#map-filter}
The [MapFilter](@ref log4cxx.filter.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](@ref log4cxx.filter.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.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://logging.apache.org/">
<appender name="SIMPLE" class="log4cxx.FileAppender">
<layout class="log4cxx.SimpleLayout">
<param name="File"
value="logs/app.log"
/>
<param name="Append"
value="true"
/>
</layout>
<filter class="log4cxx.MapFilter">
<param name="user.ip"
value="127.0.0.1"
/>
<param name="user.name"
value="test"
/>
<param name="Operator"
value="AND"
/>
<param name="AcceptOnMatch"
value="false"
/>
</filter>
</appender>
<root>
<priority value="all" />
<appender-ref ref="SIMPLE" />
</root>
</log4j:configuration>
```
If we wanted to exclude multiple IP addresses from the log, we need to define a separate filter for each one as we dont 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.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://logging.apache.org/">
<appender name="SIMPLE" class="log4cxx.FileAppender">
<layout class="log4cxx.SimpleLayout">
<param name="File"
value="logs/app.log"
/>
<param name="Append"
value="true"
/>
</layout>
<filter class="MapFilter">
<param name="user.ip"
value="192.168.0.5"
/>
</filter>
<filter class="MapFilter">
<param name="user.ip"
value="192.168.0.6"
/>
</filter>
<filter class="MapFilter">
<param name="user.ip"
value="192.168.0.7"
/>
</filter>
</appender>
<root>
<priority value="all" />
<appender-ref ref="SIMPLE" />
</root>
</log4j:configuration>
```
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.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://logging.apache.org/">
<appender name="SIMPLE" class="log4cxx.FileAppender">
<layout class="log4cxx.SimpleLayout">
<param name="File"
value="logs/app.log"
/>
<param name="Append"
value="true"
/>
</layout>
<filter class="MapFilter">
<param name="user.ip"
value="192.168.0.251"
/>
<param name="AcceptOnMatch"
value="true"
/>
</filter>
<filter class="MapFilter">
<param name="user.ip"
value="192.168.0.252"
/>
<param name="AcceptOnMatch"
value="true"
/>
</filter>
<filter class="DenyAllFilter" />
</appender>
<root>
<priority value="all" />
<appender-ref ref="SIMPLE" />
</root>
</log4j:configuration>
```
## Using the Request Location {#location-info-filter}
The [LocationInfoFilter](@ref log4cxx.filter.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:
~~~{.cpp}
LOG4CXX_TRACE(logger, "About to do something!");
for( int x = 0; x < 100; x++ ){
LOG4CXX_TRACE(logger, "Do something number " << x);
}
~~~
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:
~~~{.xml}
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://logging.apache.org/">
<appender name="SIMPLE" class="ConsoleAppender">
<param name="Target" value="System.err"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p - %m%n"/>
</layout>
<filter class="LocationInfoFilter">
<param name="LineNumber" value="182" />
<param name="Operator" value="OR" />
<param name="AcceptOnMatch" value="false" />
</filter>
</appender>
<root>
<priority value="all" />
<appender-ref ref="SIMPLE" />
</root>
</log4j:configuration>
~~~
Doing this allows us to still see the "About to do something!" message, but
ignore each iteration of the loop.
\example ndc-example.cpp
This example shows how to add a context string to each logging message using the NDC.
[the flow chart]:log-flow.html