nicko 2004/09/26 16:21:53
Modified: src ThreadContext.cs log4net.csproj
src/Util GlobalContextProperties.cs ThreadContextLists.cs
ThreadContextProperties.cs ThreadContextStacks.cs
src/Core LoggingEvent.cs
src/Util/PatternStringConverters PropertyPatternConverter.cs
Added: src LogicalThreadContext.cs
src/Util ContextPropertiesBase.cs
LogicalThreadContextProperties.cs
Log:
Added LogicalThreadContext based on ideas by Ian Kundil.
The LogicalThreadContext stores properties in the
System.Runtime.Remoting.Messaging.CallContext which allows them to flow across
thread boundaries as a call is marshalled. This does not support flowing across
a Remoting boundary.
Reduced the times when a PropertiesDictionary is created just to support
reading.
Revision Changes Path
1.2 +8 -2 logging-log4net/src/ThreadContext.cs
Index: ThreadContext.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/ThreadContext.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadContext.cs 9 Sep 2004 21:53:13 -0000 1.1
+++ ThreadContext.cs 26 Sep 2004 23:21:52 -0000 1.2
@@ -30,6 +30,8 @@
/// <para>
/// The <c>ThreadContext</c> provides a location for thread specific
debugging
/// information to be stored.
+ /// The <c>ThreadContext</c> properties override any <see
cref="GlobalContext"/>
+ /// properties with the same name.
/// </para>
/// <para>
/// The thread context has a properties map and a stack.
@@ -87,6 +89,10 @@
/// <value>
/// The thread properties map
/// </value>
+ /// <remarks>
+ /// The <c>ThreadContext</c> properties override any <see
cref="GlobalContext"/>
+ /// properties with the same name.
+ /// </remarks>
public static ThreadContextProperties Properties
{
get { return s_properties; }
@@ -126,12 +132,12 @@
/// <summary>
/// The thread context stacks instance
/// </summary>
- private readonly static ThreadContextStacks s_stacks = new
ThreadContextStacks();
+ private readonly static ThreadContextStacks s_stacks = new
ThreadContextStacks(s_properties);
/// <summary>
/// The thread context lists instance
/// </summary>
- private readonly static ThreadContextLists s_lists = new
ThreadContextLists();
+ private readonly static ThreadContextLists s_lists = new
ThreadContextLists(s_properties);
#endregion Private Static Fields
}
1.12 +15 -0 logging-log4net/src/log4net.csproj
Index: log4net.csproj
===================================================================
RCS file: /home/cvs/logging-log4net/src/log4net.csproj,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- log4net.csproj 26 Sep 2004 18:06:53 -0000 1.11
+++ log4net.csproj 26 Sep 2004 23:21:52 -0000 1.12
@@ -98,6 +98,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "LogicalThreadContext.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "LogManager.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -783,6 +788,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "Util\ContextPropertiesBase.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "Util\CountingQuietTextWriter.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -819,6 +829,11 @@
/>
<File
RelPath = "Util\LevelMappingEntry.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Util\LogicalThreadContextProperties.cs"
SubType = "Code"
BuildAction = "Compile"
/>
1.1 logging-log4net/src/LogicalThreadContext.cs
Index: LogicalThreadContext.cs
===================================================================
#region Copyright & License
//
// Copyright 2001-2004 The Apache Software Foundation
//
// Licensed 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.
//
#endregion
// .NET Compact Framework 1.0 has no support for
System.Runtime.Remoting.Messaging.CallContext
#if !NETCF
using System;
using System.Collections;
using log4net.Util;
namespace log4net
{
/// <summary>
/// The log4net Logical Thread Context.
/// </summary>
/// <remarks>
/// <para>
/// The <c>LogicalThreadContext</c> provides a location for <see
cref="System.Runtime.Remoting.Messaging.CallContext"/> specific debugging
/// information to be stored.
/// The <c>LogicalThreadContext</c> properties override any <see
cref="ThreadContext"/> or <see cref="GlobalContext"/>
/// properties with the same name.
/// </para>
/// <para>
/// The Logical Thread Context has a properties map and a stack.
/// The properties and stack can
/// be included in the output of log messages. The <see
cref="log4net.Layout.PatternLayout"/>
/// supports selecting and outputting these properties.
/// </para>
/// <para>
/// The Logical Thread Context provides a diagnostic context for the
current call context.
/// This is an instrument for distinguishing interleaved log
/// output from different sources. Log output is typically interleaved
/// when a server handles multiple clients near-simultaneously.
/// </para>
/// <para>
/// The Logical Thread Context is managed on a per <see
cref="System.Runtime.Remoting.Messaging.CallContext"/> basis.
/// </para>
/// </remarks>
/// <example>Example of using the thread context properties to store a
username.
/// <code>
/// LogicalThreadContext.Properties["user"] = userName;
/// log.Info("This log message has a LogicalThreadContext Property
called 'user'");
/// </code>
/// </example>
/// <example>Example of how to push a message into the context stack
/// <code>
/// using(LogicalThreadContext.Stack.Push("my context message"))
/// {
/// log.Info("This log message has a LogicalThreadContext
Stack message that includes 'my context message'");
///
/// } // at the end of the using block the message is automatically
popped
/// </code>
/// </example>
/// <author>Nicko Cadell</author>
public sealed class LogicalThreadContext
{
#region Private Instance Constructors
/// <summary>
/// Private Constructor.
/// </summary>
/// <remarks>
/// Uses a private access modifier to prevent instantiation of
this class.
/// </remarks>
private LogicalThreadContext()
{
}
#endregion Private Instance Constructors
#region Public Static Properties
/// <summary>
/// The thread properties map
/// </summary>
/// <value>
/// The thread properties map
/// </value>
/// <remarks>
/// The <c>LogicalThreadContext</c> properties override any
<see cref="ThreadContext"/> or <see cref="GlobalContext"/>
/// properties with the same name.
/// </remarks>
public static LogicalThreadContextProperties Properties
{
get { return s_properties; }
}
/// <summary>
/// The thread stacks
/// </summary>
/// <value>
/// stack map
/// </value>
public static ThreadContextStacks Stacks
{
get { return s_stacks; }
}
/// <summary>
/// The thread lists
/// </summary>
/// <value>
/// list map
/// </value>
public static ThreadContextLists Lists
{
get { return s_lists; }
}
#endregion Public Static Properties
#region Private Static Fields
/// <summary>
/// The thread context properties instance
/// </summary>
private readonly static LogicalThreadContextProperties
s_properties = new LogicalThreadContextProperties();
/// <summary>
/// The thread context stacks instance
/// </summary>
private readonly static ThreadContextStacks s_stacks = new
ThreadContextStacks(s_properties);
/// <summary>
/// The thread context lists instance
/// </summary>
private readonly static ThreadContextLists s_lists = new
ThreadContextLists(s_properties);
#endregion Private Static Fields
}
}
#endif
1.4 +2 -2 logging-log4net/src/Util/GlobalContextProperties.cs
Index: GlobalContextProperties.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Util/GlobalContextProperties.cs,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- GlobalContextProperties.cs 9 Sep 2004 18:58:32 -0000 1.3
+++ GlobalContextProperties.cs 26 Sep 2004 23:21:52 -0000 1.4
@@ -35,7 +35,7 @@
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
- public sealed class GlobalContextProperties
+ public sealed class GlobalContextProperties : ContextPropertiesBase
{
#region Private Instance Fields
@@ -87,7 +87,7 @@
/// the properties is created.
/// </para>
/// </remarks>
- public object this[string key]
+ override public object this[string key]
{
get
{
1.2 +6 -3 logging-log4net/src/Util/ThreadContextLists.cs
Index: ThreadContextLists.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Util/ThreadContextLists.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadContextLists.cs 9 Sep 2004 21:53:14 -0000 1.1
+++ ThreadContextLists.cs 26 Sep 2004 23:21:52 -0000 1.2
@@ -31,13 +31,16 @@
/// <author>Nicko Cadell</author>
public sealed class ThreadContextLists
{
+ private readonly ContextPropertiesBase m_properties;
+
#region Public Instance Constructors
/// <summary>
/// Initializes a new instance of the <see
cref="ThreadContextLists" /> class.
/// </summary>
- internal ThreadContextLists()
+ internal ThreadContextLists(ContextPropertiesBase properties)
{
+ m_properties = properties;
}
#endregion Public Instance Constructors
@@ -56,12 +59,12 @@
{
ThreadContextList list = null;
- object propertyValue =
ThreadContext.Properties[key];
+ object propertyValue = m_properties[key];
if (propertyValue == null)
{
// List does not exist, create
list = new ThreadContextList();
- ThreadContext.Properties[key] = list;
+ m_properties[key] = list;
}
else
{
1.2 +29 -8 logging-log4net/src/Util/ThreadContextProperties.cs
Index: ThreadContextProperties.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Util/ThreadContextProperties.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadContextProperties.cs 9 Sep 2004 21:53:14 -0000 1.1
+++ ThreadContextProperties.cs 26 Sep 2004 23:21:52 -0000 1.2
@@ -31,7 +31,7 @@
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
- public sealed class ThreadContextProperties
+ public sealed class ThreadContextProperties : ContextPropertiesBase
{
#region Private Instance Fields
@@ -61,10 +61,21 @@
/// <value>
/// The value for the property with the specified key
/// </value>
- public object this[string key]
+ override public object this[string key]
{
- get { return GetProperties()[key]; }
- set { GetProperties()[key] = value; }
+ get
+ {
+ PropertiesDictionary dictionary =
GetProperties(false);
+ if (dictionary != null)
+ {
+ return dictionary[key];
+ }
+ return null;
+ }
+ set
+ {
+ GetProperties(true)[key] = value;
+ }
}
#endregion Public Instance Properties
@@ -77,7 +88,11 @@
/// <param name="key">the key for the entry to remove</param>
public void Remove(string key)
{
- GetProperties().Remove(key);
+ PropertiesDictionary dictionary = GetProperties(false);
+ if (dictionary != null)
+ {
+ dictionary.Remove(key);
+ }
}
/// <summary>
@@ -85,7 +100,11 @@
/// </summary>
public void Clear()
{
- GetProperties().Clear();
+ PropertiesDictionary dictionary = GetProperties(false);
+ if (dictionary != null)
+ {
+ dictionary.Clear();
+ }
}
#endregion Public Instance Methods
@@ -95,6 +114,7 @@
/// <summary>
/// Get the PropertiesDictionary stored in the
LocalDataStoreSlot for this thread.
/// </summary>
+ /// <param name="create">create the dictionary if it does not
exist, otherwise return null if is does not exist</param>
/// <returns>the properties for this thread</returns>
/// <remarks>
/// <para>
@@ -103,10 +123,10 @@
/// caller must clone the collection before doings so.
/// </para>
/// </remarks>
- internal PropertiesDictionary GetProperties()
+ internal PropertiesDictionary GetProperties(bool create)
{
PropertiesDictionary properties =
(PropertiesDictionary)System.Threading.Thread.GetData(s_threadLocalSlot);
- if (properties == null)
+ if (properties == null && create)
{
properties = new PropertiesDictionary();
System.Threading.Thread.SetData(s_threadLocalSlot, properties);
@@ -117,4 +137,5 @@
#endregion Internal Instance Methods
}
}
+
1.2 +6 -3 logging-log4net/src/Util/ThreadContextStacks.cs
Index: ThreadContextStacks.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Util/ThreadContextStacks.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadContextStacks.cs 9 Sep 2004 21:53:14 -0000 1.1
+++ ThreadContextStacks.cs 26 Sep 2004 23:21:52 -0000 1.2
@@ -31,13 +31,16 @@
/// <author>Nicko Cadell</author>
public sealed class ThreadContextStacks
{
+ private readonly ContextPropertiesBase m_properties;
+
#region Public Instance Constructors
/// <summary>
/// Initializes a new instance of the <see
cref="ThreadContextStacks" /> class.
/// </summary>
- internal ThreadContextStacks()
+ internal ThreadContextStacks(ContextPropertiesBase properties)
{
+ m_properties = properties;
}
#endregion Public Instance Constructors
@@ -56,12 +59,12 @@
{
ThreadContextStack stack = null;
- object propertyValue =
ThreadContext.Properties[key];
+ object propertyValue = m_properties[key];
if (propertyValue == null)
{
// Stack does not exist, create
stack = new ThreadContextStack();
- ThreadContext.Properties[key] = stack;
+ m_properties[key] = stack;
}
else
{
1.1 logging-log4net/src/Util/ContextPropertiesBase.cs
Index: ContextPropertiesBase.cs
===================================================================
#region Copyright & License
//
// Copyright 2001-2004 The Apache Software Foundation
//
// Licensed 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.
//
#endregion
using System;
using System.Collections;
namespace log4net.Util
{
/// <summary>
/// Base class for Context Properties implementations
/// </summary>
/// <remarks>
/// <para>
/// This class defines a basic property get set accessor
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
public abstract class ContextPropertiesBase
{
/// <summary>
/// Gets or sets the value of a property
/// </summary>
/// <value>
/// The value for the property with the specified key
/// </value>
public abstract object this[string key] { get; set; }
}
}
1.1
logging-log4net/src/Util/LogicalThreadContextProperties.cs
Index: LogicalThreadContextProperties.cs
===================================================================
#region Copyright & License
//
// Copyright 2001-2004 The Apache Software Foundation
//
// Licensed 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.
//
#endregion
// .NET Compact Framework 1.0 has no support for
System.Runtime.Remoting.Messaging.CallContext
#if !NETCF
using System;
using System.Collections;
using System.Runtime.Remoting.Messaging;
namespace log4net.Util
{
/// <summary>
/// Implementation of Properties collection for the <see
cref="log4net.LogicalThreadContext"/>
/// </summary>
/// <remarks>
/// <para>
/// Class implements a collection of properties that is specific to
each thread.
/// The class is not synchronized as each thread has its own <see
cref="PropertiesDictionary"/>.
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
public sealed class LogicalThreadContextProperties :
ContextPropertiesBase
{
#region Public Instance Constructors
/// <summary>
/// Initializes a new instance of the <see
cref="LogicalThreadContextProperties" /> class.
/// </summary>
internal LogicalThreadContextProperties()
{
}
#endregion Public Instance Constructors
#region Public Instance Properties
/// <summary>
/// Gets or sets the value of a property
/// </summary>
/// <value>
/// The value for the property with the specified key
/// </value>
override public object this[string key]
{
get
{
PropertiesDictionary dictionary =
GetProperties(false);
if (dictionary != null)
{
return dictionary[key];
}
return null;
}
set
{
GetProperties(true)[key] = value;
}
}
#endregion Public Instance Properties
#region Public Instance Methods
/// <summary>
/// Remove a property
/// </summary>
/// <param name="key">the key for the entry to remove</param>
public void Remove(string key)
{
PropertiesDictionary dictionary = GetProperties(false);
if (dictionary != null)
{
dictionary.Remove(key);
}
}
/// <summary>
/// Clear the global context properties
/// </summary>
public void Clear()
{
PropertiesDictionary dictionary = GetProperties(false);
if (dictionary != null)
{
dictionary.Clear();
}
}
#endregion Public Instance Methods
#region Internal Instance Methods
/// <summary>
/// Get the PropertiesDictionary stored in the
LocalDataStoreSlot for this thread.
/// </summary>
/// <param name="create">create the dictionary if it does not
exist, otherwise return null if is does not exist</param>
/// <returns>the properties for this thread</returns>
/// <remarks>
/// <para>
/// The collection returned is only to be used on the calling
thread. If the
/// caller needs to share the collection between different
threads then the
/// caller must clone the collection before doings so.
/// </para>
/// </remarks>
internal PropertiesDictionary GetProperties(bool create)
{
PropertiesDictionary properties =
(PropertiesDictionary)CallContext.GetData("log4net.Util.LogicalThreadContextProperties");
if (properties == null && create)
{
properties = new PropertiesDictionary();
CallContext.SetData("log4net.Util.LogicalThreadContextProperties", properties);
}
return properties;
}
#endregion Internal Instance Methods
}
}
#endif
1.12 +12 -1 logging-log4net/src/Core/LoggingEvent.cs
Index: LoggingEvent.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Core/LoggingEvent.cs,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- LoggingEvent.cs 19 Sep 2004 17:52:54 -0000 1.11
+++ LoggingEvent.cs 26 Sep 2004 23:21:52 -0000 1.12
@@ -1156,7 +1156,18 @@
{
m_compositeProperties.Add(m_eventProperties);
}
-
m_compositeProperties.Add(ThreadContext.Properties.GetProperties());
+#if !NETCF
+ PropertiesDictionary logicalThreadProperties =
LogicalThreadContext.Properties.GetProperties(false);
+ if (logicalThreadProperties != null)
+ {
+
m_compositeProperties.Add(logicalThreadProperties);
+ }
+#endif
+ PropertiesDictionary threadProperties =
ThreadContext.Properties.GetProperties(false);
+ if (threadProperties != null)
+ {
+ m_compositeProperties.Add(threadProperties);
+ }
// TODO: Add Repository Properties
1.2 +13 -1
logging-log4net/src/Util/PatternStringConverters/PropertyPatternConverter.cs
Index: PropertyPatternConverter.cs
===================================================================
RCS file:
/home/cvs/logging-log4net/src/Util/PatternStringConverters/PropertyPatternConverter.cs,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PropertyPatternConverter.cs 9 Sep 2004 21:53:14 -0000 1.1
+++ PropertyPatternConverter.cs 26 Sep 2004 23:21:52 -0000 1.2
@@ -57,7 +57,19 @@
{
CompositeProperties compositeProperties = new
CompositeProperties();
-
compositeProperties.Add(ThreadContext.Properties.GetProperties());
+#if !NETCF
+ PropertiesDictionary logicalThreadProperties =
LogicalThreadContext.Properties.GetProperties(false);
+ if (logicalThreadProperties != null)
+ {
+
compositeProperties.Add(logicalThreadProperties);
+ }
+#endif
+ PropertiesDictionary threadProperties =
ThreadContext.Properties.GetProperties(false);
+ if (threadProperties != null)
+ {
+ compositeProperties.Add(threadProperties);
+ }
+
// TODO: Add Repository Properties
compositeProperties.Add(GlobalContext.Properties.GetReadOnlyProperties());