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
        }
  }
  
  
  
  

Reply via email to