blob: 54cf328120d765c6e71ede77956035cf7902ad7e [file] [log] [blame]
<?xml version="1.0" ?>
<!--
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>
<author email="nicko at apache dot org">Nicko Cadell</author>
<title>Apache log4net Manual: Contexts</title>
</properties>
<meta name="keywords" content="building log4net, log4net" />
<body>
<section id="main" name="Apache log4net&#x2122; Manual - 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. An approach to differentiate the
logging output of one client from another is to instantiate a new separate
logger for each client. However 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.
</p>
<p>
Log4net supports different types of contextual logging and contexts with different scopes.
</p>
<section id="scopes" name="Scopes">
<p>
Contextual data can be set in different scopes. These contexts have progressively narrower visibility.
In the logging event itself the values from all of the contexts are combined together such that
values specified in a lower scoped context hide values from a higher context.
</p>
<div class="table">
<table>
<tr>
<th>Scope</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr align="left">
<td>Global</td>
<td><span class="code">log4net.GlobalContext</span></td>
<td>
The global context is shared by all threads in the current AppDomain.
This context is thread safe for use by multiple threads concurrently.
</td>
</tr>
<tr align="left">
<td>Thread</td>
<td><span class="code">log4net.ThreadContext</span></td>
<td>
The thread context is visible only to the current managed thread.
</td>
</tr>
<tr align="left">
<td>Logical Thread</td>
<td><span class="code">log4net.LogicalThreadContext</span></td>
<td>
The logical thread context is visible to a logical thread. Logical
threads can jump from one managed thread to another. For more details
see the .NET API <span
class="code">System.Runtime.Remoting.Messaging.CallContext</span>.<br></br>
For .NET Standard this uses <span
class="code">AsyncLocal</span> rather
than <span class="code">CallContext</span>.
</td>
</tr>
<tr align="left">
<td>Event</td>
<td><span class="code">log4net.Core.LoggingEvent</span></td>
<td>
Each event captures the current contextual state at the time the event
is generated. Contextual data can be set on the event itself. This context
is only visible to the code generating the event itself.
</td>
</tr>
</table>
</div>
</section>
<section id="properties" name="Context Properties">
<p>
The log4net contexts store properties, i.e. name value pairs. The name is a string
the value is any object. A property can be set as follows:
</p>
<source language="c#"><![CDATA[
log4net.GlobalContext.Properties["name"] = value;
]]></source>
<p>
If properties with the same name are set in more than one context scope then
the value in the narrowest scope (lower down in the list above) will hide the
other values.
</p>
<p>
The property values are stored as objects within the <span class="code">LoggingEvent</span>.
The <span class="code">PatternLayout</span> supports rendering the value of a named
property using the <span class="code">%property{name}</span> syntax. The value is
converted to a string by passing it to the <span class="code">log4net.ObjectRenderer.RendererMap</span>
which will locate any custom renderer for the value type. The default behavior for
custom types is to call the object's <span class="code">ToString()</span> method.
</p>
<section id="active" name="Active Property Values">
<p>
An active property value is one who's value changes over time.
</p>
<p>
For example, imagine a custom type that implemented the
<span class="code">ToString()</span> method to return the
number of bytes allocated by the runtime garbage collector.
</p>
<source language="c#"><![CDATA[
public class GCAllocatedBytesHelper
{
public override string ToString()
{
return GC.GetTotalMemory(true).ToString();
}
}]]></source>
<p>
An instance of this type can be added to the <span class="code">log4net.GlobalContext</span>
during application startup:
</p>
<source language="c#"><![CDATA[
log4net.GlobalContext.Properties["GCAllocatedBytes"] = new GCAllocatedBytesHelper();
]]></source>
<p>
Once this property is set in the context all subsequent logging events will have a property
called <i>GCAllocatedBytes</i>. The value of the property will be an instance of the
<span class="code">GCAllocatedBytesHelper</span> type. When this value is rendered to a
string by calling the <span class="code">ToString</span> method the current number of bytes
allocated by the garbage collector will be returned and included in the output.
</p>
</section>
</section>
<section id="stacks" name="Context Stacks">
<p>
Sometimes simple key value pairs are not the most convenient way of capturing contextual
information. A stack of information is a very convenient way of storing data especially
as our applications tend to be stack based.
</p>
<p>
The <span class="code">ThreadContext</span> and <span class="code">LogicalThreadContext</span>
also support storing contextual data in a stack. The stack is stored in context property,
therefore stacks have names and more than one stack can exist in the same context. A property
value set in a narrower context would override a stack with the same property name set in a
wider scoped context.
</p>
<p>
The stack supports <span class="code">Push</span> and <span class="code">Pop</span> methods.
As more contextual data is pushed onto the stack the stack grows. When the stack is rendered
all the data pushed onto the stack is output with the most recent data to the right hand
end of the string.
</p>
<p>
As the stack is just an object stored in the context properties it is also rendered
using the same <span class="code">PatternLayout</span> syntax: <span class="code">%property{name}</span>.
Where <i>name</i> is the name of the stack.
</p>
<p>
Calls the the stack's <span class="code">Push</span> and <span class="code">Pop</span>
methods must be matched up so that each push has a corresponding pop. The
<span class="code">Push</span> method also returns an <span class="code">IDisposable</span>
object that will perform the required pop operation when it is disposed. This allows
the C# <i>using</i> syntax to be used to automate the stack management.
</p>
<source language="c#"><![CDATA[
using(log4net.ThreadContext.Stacks["NDC"].Push("context"))
{
log.Info("Message");
}
]]></source>
<p>
The INFO level log has a stack stored in its <i>NDC</i> property. The top item in the
stack is the string <i>context</i>.
The <i>using</i> syntax ensures that the value <i>context</i> is popped off the stack
at the end of the block.
</p>
<p>
The <span class="code">using</span>
syntax is recommended because it removes some work load from the developer and
reduces errors in matching up the Push and Pop calls, especially when exceptions
can occur.
</p>
</section>
<section id="ndc" name="Nested Diagnostic Contexts">
<p>
The <span class="code">NDC</span> (Nested Diagnostic Context) exists for compatibility
with older versions of log4net. This helper class implements a stack which is stored
in the thread context property named <i>NDC</i>.
</p>
</section>
<section id="mdc" name="Mapped Diagnostic Contexts">
<p>
The <span class="code">MDC</span> (MappedDiagnostic Context) exists for compatibility
with older versions of log4net. This helper class implements a properties map which is
mapped directly through to the thread context properties.
</p>
</section>
<p>
To illustrate this point, let us take the example of a web service delivering
content to numerous clients. The web service can build the <span class="code">NDC</span> 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 web
service 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 <span class="code">NDC</span> 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. Log4net supports
multiple logger repositories. This would allow each virtual host to possess its own copy
of the logger hierarchy. Configuring multiple logger hierarchies is beyond the
scope of this document.
</p>
</section>
</body>
</document>