#region Apache License
|
//
|
// 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.
|
//
|
#endregion
|
|
using System;
|
|
#if !NETCF_1_0
|
using System.Collections;
|
#endif
|
|
using log4net.Core;
|
|
namespace log4net.Util
|
{
|
/// <summary>
|
/// Implementation of Stack for the <see cref="log4net.ThreadContext"/>
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Implementation of Stack for the <see cref="log4net.ThreadContext"/>
|
/// </para>
|
/// </remarks>
|
/// <author>Nicko Cadell</author>
|
public sealed class ThreadContextStack : IFixingRequired
|
{
|
#region Private Static Fields
|
|
/// <summary>
|
/// The stack store.
|
/// </summary>
|
private Stack m_stack = new Stack();
|
|
#endregion Private Static Fields
|
|
#region Public Instance Constructors
|
|
/// <summary>
|
/// Internal constructor
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="ThreadContextStack" /> class.
|
/// </para>
|
/// </remarks>
|
internal ThreadContextStack()
|
{
|
}
|
|
#endregion Public Instance Constructors
|
|
#region Public Properties
|
|
/// <summary>
|
/// The number of messages in the stack
|
/// </summary>
|
/// <value>
|
/// The current number of messages in the stack
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// The current number of messages in the stack. That is
|
/// the number of times <see cref="Push"/> has been called
|
/// minus the number of times <see cref="Pop"/> has been called.
|
/// </para>
|
/// </remarks>
|
public int Count
|
{
|
get { return m_stack.Count; }
|
}
|
|
#endregion // Public Properties
|
|
#region Public Methods
|
|
/// <summary>
|
/// Clears all the contextual information held in this stack.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Clears all the contextual information held in this stack.
|
/// Only call this if you think that this tread is being reused after
|
/// a previous call execution which may not have completed correctly.
|
/// You do not need to use this method if you always guarantee to call
|
/// the <see cref="IDisposable.Dispose"/> method of the <see cref="IDisposable"/>
|
/// returned from <see cref="Push"/> even in exceptional circumstances,
|
/// for example by using the <c>using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))</c>
|
/// syntax.
|
/// </para>
|
/// </remarks>
|
public void Clear()
|
{
|
m_stack.Clear();
|
}
|
|
/// <summary>
|
/// Removes the top context from this stack.
|
/// </summary>
|
/// <returns>The message in the context that was removed from the top of this stack.</returns>
|
/// <remarks>
|
/// <para>
|
/// Remove the top context from this stack, and return
|
/// it to the caller. If this stack is empty then an
|
/// empty string (not <see langword="null"/>) is returned.
|
/// </para>
|
/// </remarks>
|
public string Pop()
|
{
|
Stack stack = m_stack;
|
if (stack.Count > 0)
|
{
|
return ((StackFrame)(stack.Pop())).Message;
|
}
|
return "";
|
}
|
|
/// <summary>
|
/// Pushes a new context message into this stack.
|
/// </summary>
|
/// <param name="message">The new context message.</param>
|
/// <returns>
|
/// An <see cref="IDisposable"/> that can be used to clean up the context stack.
|
/// </returns>
|
/// <remarks>
|
/// <para>
|
/// Pushes a new context onto this stack. An <see cref="IDisposable"/>
|
/// is returned that can be used to clean up this stack. This
|
/// can be easily combined with the <c>using</c> keyword to scope the
|
/// context.
|
/// </para>
|
/// </remarks>
|
/// <example>Simple example of using the <c>Push</c> method with the <c>using</c> keyword.
|
/// <code lang="C#">
|
/// using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))
|
/// {
|
/// log.Warn("This should have an ThreadContext Stack message");
|
/// }
|
/// </code>
|
/// </example>
|
public IDisposable Push(string message)
|
{
|
Stack stack = m_stack;
|
stack.Push(new StackFrame(message, (stack.Count>0) ? (StackFrame)stack.Peek() : null));
|
|
return new AutoPopStackFrame(stack, stack.Count - 1);
|
}
|
|
#endregion Public Methods
|
|
#region Internal Methods
|
|
/// <summary>
|
/// Gets the current context information for this stack.
|
/// </summary>
|
/// <returns>The current context information.</returns>
|
internal string GetFullMessage()
|
{
|
Stack stack = m_stack;
|
if (stack.Count > 0)
|
{
|
return ((StackFrame)(stack.Peek())).FullMessage;
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// Gets and sets the internal stack used by this <see cref="ThreadContextStack"/>
|
/// </summary>
|
/// <value>The internal storage stack</value>
|
/// <remarks>
|
/// <para>
|
/// This property is provided only to support backward compatability
|
/// of the <see cref="NDC"/>. Tytpically the internal stack should not
|
/// be modified.
|
/// </para>
|
/// </remarks>
|
internal Stack InternalStack
|
{
|
get { return m_stack; }
|
set { m_stack = value; }
|
}
|
|
#endregion Internal Methods
|
|
/// <summary>
|
/// Gets the current context information for this stack.
|
/// </summary>
|
/// <returns>Gets the current context information</returns>
|
/// <remarks>
|
/// <para>
|
/// Gets the current context information for this stack.
|
/// </para>
|
/// </remarks>
|
public override string ToString()
|
{
|
return GetFullMessage();
|
}
|
|
/// <summary>
|
/// Get a portable version of this object
|
/// </summary>
|
/// <returns>the portable instance of this object</returns>
|
/// <remarks>
|
/// <para>
|
/// Get a cross thread portable version of this object
|
/// </para>
|
/// </remarks>
|
object IFixingRequired.GetFixedObject()
|
{
|
return GetFullMessage();
|
}
|
|
/// <summary>
|
/// Inner class used to represent a single context frame in the stack.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Inner class used to represent a single context frame in the stack.
|
/// </para>
|
/// </remarks>
|
private sealed class StackFrame
|
{
|
#region Private Instance Fields
|
|
private readonly string m_message;
|
private readonly StackFrame m_parent;
|
private string m_fullMessage = null;
|
|
#endregion
|
|
#region Internal Instance Constructors
|
|
/// <summary>
|
/// Constructor
|
/// </summary>
|
/// <param name="message">The message for this context.</param>
|
/// <param name="parent">The parent context in the chain.</param>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="StackFrame" /> class
|
/// with the specified message and parent context.
|
/// </para>
|
/// </remarks>
|
internal StackFrame(string message, StackFrame parent)
|
{
|
m_message = message;
|
m_parent = parent;
|
|
if (parent == null)
|
{
|
m_fullMessage = message;
|
}
|
}
|
|
#endregion Internal Instance Constructors
|
|
#region Internal Instance Properties
|
|
/// <summary>
|
/// Get the message.
|
/// </summary>
|
/// <value>The message.</value>
|
/// <remarks>
|
/// <para>
|
/// Get the message.
|
/// </para>
|
/// </remarks>
|
internal string Message
|
{
|
get { return m_message; }
|
}
|
|
/// <summary>
|
/// Gets the full text of the context down to the root level.
|
/// </summary>
|
/// <value>
|
/// The full text of the context down to the root level.
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Gets the full text of the context down to the root level.
|
/// </para>
|
/// </remarks>
|
internal string FullMessage
|
{
|
get
|
{
|
if (m_fullMessage == null && m_parent != null)
|
{
|
m_fullMessage = string.Concat(m_parent.FullMessage, " ", m_message);
|
}
|
return m_fullMessage;
|
}
|
}
|
|
#endregion Internal Instance Properties
|
}
|
|
/// <summary>
|
/// Struct returned from the <see cref="ThreadContextStack.Push"/> method.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// This struct implements the <see cref="IDisposable"/> and is designed to be used
|
/// with the <see langword="using"/> pattern to remove the stack frame at the end of the scope.
|
/// </para>
|
/// </remarks>
|
private struct AutoPopStackFrame : IDisposable
|
{
|
#region Private Instance Fields
|
|
/// <summary>
|
/// The ThreadContextStack internal stack
|
/// </summary>
|
private Stack m_frameStack;
|
|
/// <summary>
|
/// The depth to trim the stack to when this instance is disposed
|
/// </summary>
|
private int m_frameDepth;
|
|
#endregion Private Instance Fields
|
|
#region Internal Instance Constructors
|
|
/// <summary>
|
/// Constructor
|
/// </summary>
|
/// <param name="frameStack">The internal stack used by the ThreadContextStack.</param>
|
/// <param name="frameDepth">The depth to return the stack to when this object is disposed.</param>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="AutoPopStackFrame" /> class with
|
/// the specified stack and return depth.
|
/// </para>
|
/// </remarks>
|
internal AutoPopStackFrame(Stack frameStack, int frameDepth)
|
{
|
m_frameStack = frameStack;
|
m_frameDepth = frameDepth;
|
}
|
|
#endregion Internal Instance Constructors
|
|
#region Implementation of IDisposable
|
|
/// <summary>
|
/// Returns the stack to the correct depth.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Returns the stack to the correct depth.
|
/// </para>
|
/// </remarks>
|
public void Dispose()
|
{
|
if (m_frameDepth >= 0 && m_frameStack != null)
|
{
|
while(m_frameStack.Count > m_frameDepth)
|
{
|
m_frameStack.Pop();
|
}
|
}
|
}
|
|
#endregion Implementation of IDisposable
|
}
|
|
#if NETCF_1_0
|
/// <summary>
|
/// Subclass of <see cref="System.Collections.Stack"/> to
|
/// provide missing methods.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// The Compact Framework version of the <see cref="System.Collections.Stack"/>
|
/// class is missing the <c>Clear</c> and <c>Clone</c> methods.
|
/// This subclass adds implementations of those missing methods.
|
/// </para>
|
/// </remarks>
|
public class Stack : System.Collections.Stack
|
{
|
/// <summary>
|
/// Clears the stack of all elements.
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Clears the stack of all elements.
|
/// </para>
|
/// </remarks>
|
public void Clear()
|
{
|
while(Count > 0)
|
{
|
Pop();
|
}
|
}
|
|
/// <summary>
|
/// Makes a shallow copy of the stack's elements.
|
/// </summary>
|
/// <returns>A new stack that has a shallow copy of the stack's elements.</returns>
|
/// <remarks>
|
/// <para>
|
/// Makes a shallow copy of the stack's elements.
|
/// </para>
|
/// </remarks>
|
public Stack Clone()
|
{
|
Stack res = new Stack();
|
object[] items = ToArray();
|
foreach(object item in items)
|
{
|
res.Push(item);
|
}
|
return res;
|
}
|
}
|
#endif
|
}
|
}
|