nicko 2004/07/30 10:42:36
Modified: src/Core LoggingEvent.cs
src/Layout PatternLayout.cs
Added: src GlobalContext.cs
src/Layout/Pattern GlobalPropertyPatternConverter.cs
src/Util GlobalContextProperties.cs
Log:
Added GlobalContext similar to MDC but not thread local.
GlobalContext.Properties is a shared properties dictionary that can be
included in the
output by using the %global pattern in the PatternLayout.
Revision Changes Path
1.1 logging-log4net/src/GlobalContext.cs
Index: GlobalContext.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;
using log4net.Util;
namespace log4net
{
/// <summary>
/// The log4net Global Context.
/// </summary>
/// <remarks>
/// <para>
/// The GlobalContext provides a global properties map. These
/// properties can be included in the output of log messages.
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
public sealed class GlobalContext
{
#region Private Instance Constructors
/// <summary>
/// Private Constructor.
/// </summary>
/// <remarks>
/// Uses a private access modifier to prevent instantiation of
this class.
/// </remarks>
private GlobalContext()
{
}
#endregion Private Instance Constructors
#region Public Static Properties
/// <summary>
/// Get the global properties map
/// </summary>
public static GlobalContextProperties Properties
{
get { return s_properties; }
}
#endregion Public Static Properties
#region Private Static Fields
/// <summary>
/// The global context properties instance
/// </summary>
private readonly static GlobalContextProperties s_properties =
new GlobalContextProperties();
#endregion Private Static Fields
}
}
1.7 +38 -0 logging-log4net/src/Core/LoggingEvent.cs
Index: LoggingEvent.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Core/LoggingEvent.cs,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- LoggingEvent.cs 7 Jun 2004 01:06:07 -0000 1.6
+++ LoggingEvent.cs 30 Jul 2004 17:42:35 -0000 1.7
@@ -110,6 +110,14 @@
/// </remarks>
public PropertiesDictionary Properties;
+ /// <summary>
+ /// Global properties
+ /// </summary>
+ /// <remarks>
+ /// Global properties are defined on the <see
cref="GlobalContext"/>
+ /// </remarks>
+ public ReadOnlyPropertiesDictionary GlobalProperties;
+
#endregion Public Instance Fields
}
@@ -266,6 +274,9 @@
m_data.LoggerName = loggerName;
m_data.Level = level;
m_data.TimeStamp = DateTime.Now;
+
+ // Lookup the global properties as soon as possible
+ m_data.GlobalProperties =
log4net.GlobalContext.Properties.GetReadOnlyProperties();
}
/// <summary>
@@ -344,6 +355,7 @@
m_data.UserName = info.GetString("UserName");
m_data.ExceptionString =
info.GetString("ExceptionString");
m_data.Properties = (PropertiesDictionary)
info.GetValue("Properties", typeof(PropertiesDictionary));
+ m_data.GlobalProperties =
(ReadOnlyPropertiesDictionary) info.GetValue("GlobalProperties",
typeof(ReadOnlyPropertiesDictionary));
m_data.Domain = info.GetString("Domain");
m_data.Identity = info.GetString("Identity");
}
@@ -812,6 +824,32 @@
m_data.Properties = new
PropertiesDictionary();
}
return m_data.Properties;
+ }
+ }
+
+ /// <summary>
+ /// Gets the global properties defined when this event was
created.
+ /// </summary>
+ /// <value>
+ /// Globally diefined properties.
+ /// </value>
+ /// <remarks>
+ /// Global properties are defined by the <see
cref="GlobalContext"/>
+ /// </remarks>
+ public ReadOnlyPropertiesDictionary GlobalProperties
+ {
+ get
+ {
+ // The global properties are captured in the
constructor
+ // because they are global shareed state they
must be captured as soon as possible
+
+ if (m_data.GlobalProperties == null)
+ {
+ // Just in case for some reason this is
null set it to an empty collection
+ // callers do not expect this property
to return null
+ m_data.GlobalProperties = new
ReadOnlyPropertiesDictionary();
+ }
+ return m_data.GlobalProperties;
}
}
1.8 +29 -1 logging-log4net/src/Layout/PatternLayout.cs
Index: PatternLayout.cs
===================================================================
RCS file: /home/cvs/logging-log4net/src/Layout/PatternLayout.cs,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- PatternLayout.cs 30 Jul 2004 14:19:11 -0000 1.7
+++ PatternLayout.cs 30 Jul 2004 17:42:35 -0000 1.8
@@ -164,6 +164,24 @@
/// </description>
/// </item>
/// <item>
+ /// <term>global</term>
+ /// <description>
+ /// <para>
+ /// Used to output the a global property. The key
to
+ /// lookup must be specified within braces and
directly following the
+ /// pattern specifier, e.g. <b>%global{user}</b>
would include the value
+ /// from the property that is keyed by the string
'user'. Each property value
+ /// that is to be included in the log must be
specified separately.
+ /// Properties are added to events by loggers or
appenders. By default
+ /// no properties are defined.
+ /// </para>
+ /// <para>
+ /// If no key is specified, e.g. <b>%global</b>
then all the keys and their
+ /// values are printed in a comma separated list.
+ /// </para>
+ /// </description>
+ /// </item>
+ /// <item>
/// <term>identity</term>
/// <description>
/// <para>
@@ -281,6 +299,10 @@
/// from the MDC that is keyed by the string
'user'. Each MDC value
/// that is to be included in the log must be
specified separately.
/// </para>
+ /// <para>
+ /// If no key is specified, e.g. <b>%mdc</b> then
all the keys and their
+ /// values are printed in a comma separated list.
+ /// </para>
/// </description>
/// </item>
/// <item>
@@ -347,6 +369,10 @@
/// Properties are added to events by loggers or
appenders. By default
/// no properties are defined.
/// </para>
+ /// <para>
+ /// If no key is specified, e.g. <b>%property</b>
then all the keys and their
+ /// values are printed in a comma separated list.
+ /// </para>
/// </description>
/// </item>
/// <item>
@@ -676,6 +702,8 @@
s_globalRulesRegistry.Add("F",
typeof(FileLocationPatternConverter));
s_globalRulesRegistry.Add("file",
typeof(FileLocationPatternConverter));
+ s_globalRulesRegistry.Add("global",
typeof(GlobalPropertyPatternConverter));
+
s_globalRulesRegistry.Add("l",
typeof(FullLocationPatternConverter));
s_globalRulesRegistry.Add("location",
typeof(FullLocationPatternConverter));
@@ -863,7 +891,7 @@
/// <param name="converterInfo">the converter info</param>
/// <remarks>
/// This version of the method is used by the configurator.
- /// Programatic users should use the alternative <see
cref="AddConverter(string,Type)"/> method.
+ /// Programmatic users should use the alternative <see
cref="AddConverter(string,Type)"/> method.
/// </remarks>
public void AddConverter(ConverterInfo converterInfo)
{
1.1
logging-log4net/src/Layout/Pattern/GlobalPropertyPatternConverter.cs
Index: GlobalPropertyPatternConverter.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.Text;
using System.IO;
using log4net.Core;
namespace log4net.Layout.Pattern
{
/// <summary>
/// Global context property pattern converter
/// </summary>
/// <author>Nicko Cadell</author>
internal sealed class GlobalPropertyPatternConverter :
PatternLayoutConverter
{
/// <summary>
/// Convert the pattern to the rendered message
/// </summary>
/// <param name="writer"><see cref="TextWriter" /> that will
receive the formatted result.</param>
/// <param name="loggingEvent">the event being logged</param>
/// <returns>the result of converting the pattern</returns>
override protected void Convert(TextWriter writer, LoggingEvent
loggingEvent)
{
if (Option != null)
{
// Write the value for the specified key
WriteObject(writer, loggingEvent.Repository,
loggingEvent.GlobalProperties[Option]);
}
else
{
// Write all the key value pairs
WriteDictionary(writer,
loggingEvent.Repository, loggingEvent.GlobalProperties);
}
}
}
}
1.1 logging-log4net/src/Util/GlobalContextProperties.cs
Index: GlobalContextProperties.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>
/// </summary>
/// <remarks>
/// </remarks>
/// <author>Nicko Cadell</author>
public sealed class GlobalContextProperties
{
#region Private Instance Fields
/// <summary>
/// The read only copy of the properties.
/// </summary>
/// <remarks>
/// <para>
/// This variable is declared <c>volatile</c> to prevent the
compiler and JIT from
/// reordering reads and writes of this thread performed on
different threads.
/// </para>
/// </remarks>
private volatile ReadOnlyPropertiesDictionary
m_readOnlyProperties = new ReadOnlyPropertiesDictionary();
/// <summary>
/// Lock object used to synchronize updates within this instance
/// </summary>
private readonly object m_syncRoot = new object();
#endregion Private Instance Fields
#region Public Instance Constructors
/// <summary>
/// Initializes a new instance of the <see
cref="GlobalContextProperties" /> class.
/// </summary>
internal GlobalContextProperties()
{
}
#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>
/// <remarks>
/// <para>
/// Reading the value for a key is faster than setting the
value.
/// When the value is written a new read only copy of
/// the properties is created.
/// </para>
/// </remarks>
public object this[string key]
{
get
{
return m_readOnlyProperties[key];
}
set
{
lock(m_syncRoot)
{
PropertiesDictionary mutableProps = new
PropertiesDictionary(m_readOnlyProperties);
mutableProps[key] = value;
m_readOnlyProperties = new
ReadOnlyPropertiesDictionary(mutableProps);
}
}
}
#endregion Public Instance Properties
#region Public Instance Methods
/// <summary>
/// Remove a property from the global context
/// </summary>
/// <param name="key">the key for the entry to remove</param>
/// <remarks>
/// <para>
/// Removing an entry from the global context properties is
relatively expensive compared
/// with reading a value.
/// </para>
/// </remarks>
public void Remove(string key)
{
lock(m_syncRoot)
{
if (m_readOnlyProperties.Contains(key))
{
PropertiesDictionary mutableProps = new
PropertiesDictionary(m_readOnlyProperties);
mutableProps.Remove(key);
m_readOnlyProperties = new
ReadOnlyPropertiesDictionary(mutableProps);
}
}
}
/// <summary>
/// Clear the global context properties
/// </summary>
public void Clear()
{
lock(m_syncRoot)
{
m_readOnlyProperties = new
ReadOnlyPropertiesDictionary();
}
}
#endregion Public Instance Methods
#region Internal Instance Methods
/// <summary>
/// Get a readonly immutable copy of the properties
/// </summary>
/// <returns>the current global context properties</returns>
/// <remarks>
/// <para>
/// This implementation is fast because the
GlobalContextProperties class
/// stores a readonly copy of the properties.
/// </para>
/// </remarks>
internal ReadOnlyPropertiesDictionary GetReadOnlyProperties()
{
return m_readOnlyProperties;
}
#endregion Internal Instance Methods
}
}