ThreadContextStack.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #region Apache License
  2. //
  3. // Licensed to the Apache Software Foundation (ASF) under one or more
  4. // contributor license agreements. See the NOTICE file distributed with
  5. // this work for additional information regarding copyright ownership.
  6. // The ASF licenses this file to you under the Apache License, Version 2.0
  7. // (the "License"); you may not use this file except in compliance with
  8. // the License. You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. using System;
  20. #if !NETCF_1_0
  21. using System.Collections;
  22. #endif
  23. using log4net.Core;
  24. namespace log4net.Util
  25. {
  26. /// <summary>
  27. /// Implementation of Stack for the <see cref="log4net.ThreadContext"/>
  28. /// </summary>
  29. /// <remarks>
  30. /// <para>
  31. /// Implementation of Stack for the <see cref="log4net.ThreadContext"/>
  32. /// </para>
  33. /// </remarks>
  34. /// <author>Nicko Cadell</author>
  35. public sealed class ThreadContextStack : IFixingRequired
  36. {
  37. #region Private Static Fields
  38. /// <summary>
  39. /// The stack store.
  40. /// </summary>
  41. private Stack m_stack = new Stack();
  42. #endregion Private Static Fields
  43. #region Public Instance Constructors
  44. /// <summary>
  45. /// Internal constructor
  46. /// </summary>
  47. /// <remarks>
  48. /// <para>
  49. /// Initializes a new instance of the <see cref="ThreadContextStack" /> class.
  50. /// </para>
  51. /// </remarks>
  52. internal ThreadContextStack()
  53. {
  54. }
  55. #endregion Public Instance Constructors
  56. #region Public Properties
  57. /// <summary>
  58. /// The number of messages in the stack
  59. /// </summary>
  60. /// <value>
  61. /// The current number of messages in the stack
  62. /// </value>
  63. /// <remarks>
  64. /// <para>
  65. /// The current number of messages in the stack. That is
  66. /// the number of times <see cref="Push"/> has been called
  67. /// minus the number of times <see cref="Pop"/> has been called.
  68. /// </para>
  69. /// </remarks>
  70. public int Count
  71. {
  72. get { return m_stack.Count; }
  73. }
  74. #endregion // Public Properties
  75. #region Public Methods
  76. /// <summary>
  77. /// Clears all the contextual information held in this stack.
  78. /// </summary>
  79. /// <remarks>
  80. /// <para>
  81. /// Clears all the contextual information held in this stack.
  82. /// Only call this if you think that this tread is being reused after
  83. /// a previous call execution which may not have completed correctly.
  84. /// You do not need to use this method if you always guarantee to call
  85. /// the <see cref="IDisposable.Dispose"/> method of the <see cref="IDisposable"/>
  86. /// returned from <see cref="Push"/> even in exceptional circumstances,
  87. /// for example by using the <c>using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))</c>
  88. /// syntax.
  89. /// </para>
  90. /// </remarks>
  91. public void Clear()
  92. {
  93. m_stack.Clear();
  94. }
  95. /// <summary>
  96. /// Removes the top context from this stack.
  97. /// </summary>
  98. /// <returns>The message in the context that was removed from the top of this stack.</returns>
  99. /// <remarks>
  100. /// <para>
  101. /// Remove the top context from this stack, and return
  102. /// it to the caller. If this stack is empty then an
  103. /// empty string (not <see langword="null"/>) is returned.
  104. /// </para>
  105. /// </remarks>
  106. public string Pop()
  107. {
  108. Stack stack = m_stack;
  109. if (stack.Count > 0)
  110. {
  111. return ((StackFrame)(stack.Pop())).Message;
  112. }
  113. return "";
  114. }
  115. /// <summary>
  116. /// Pushes a new context message into this stack.
  117. /// </summary>
  118. /// <param name="message">The new context message.</param>
  119. /// <returns>
  120. /// An <see cref="IDisposable"/> that can be used to clean up the context stack.
  121. /// </returns>
  122. /// <remarks>
  123. /// <para>
  124. /// Pushes a new context onto this stack. An <see cref="IDisposable"/>
  125. /// is returned that can be used to clean up this stack. This
  126. /// can be easily combined with the <c>using</c> keyword to scope the
  127. /// context.
  128. /// </para>
  129. /// </remarks>
  130. /// <example>Simple example of using the <c>Push</c> method with the <c>using</c> keyword.
  131. /// <code lang="C#">
  132. /// using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message"))
  133. /// {
  134. /// log.Warn("This should have an ThreadContext Stack message");
  135. /// }
  136. /// </code>
  137. /// </example>
  138. public IDisposable Push(string message)
  139. {
  140. Stack stack = m_stack;
  141. stack.Push(new StackFrame(message, (stack.Count>0) ? (StackFrame)stack.Peek() : null));
  142. return new AutoPopStackFrame(stack, stack.Count - 1);
  143. }
  144. #endregion Public Methods
  145. #region Internal Methods
  146. /// <summary>
  147. /// Gets the current context information for this stack.
  148. /// </summary>
  149. /// <returns>The current context information.</returns>
  150. internal string GetFullMessage()
  151. {
  152. Stack stack = m_stack;
  153. if (stack.Count > 0)
  154. {
  155. return ((StackFrame)(stack.Peek())).FullMessage;
  156. }
  157. return null;
  158. }
  159. /// <summary>
  160. /// Gets and sets the internal stack used by this <see cref="ThreadContextStack"/>
  161. /// </summary>
  162. /// <value>The internal storage stack</value>
  163. /// <remarks>
  164. /// <para>
  165. /// This property is provided only to support backward compatability
  166. /// of the <see cref="NDC"/>. Tytpically the internal stack should not
  167. /// be modified.
  168. /// </para>
  169. /// </remarks>
  170. internal Stack InternalStack
  171. {
  172. get { return m_stack; }
  173. set { m_stack = value; }
  174. }
  175. #endregion Internal Methods
  176. /// <summary>
  177. /// Gets the current context information for this stack.
  178. /// </summary>
  179. /// <returns>Gets the current context information</returns>
  180. /// <remarks>
  181. /// <para>
  182. /// Gets the current context information for this stack.
  183. /// </para>
  184. /// </remarks>
  185. public override string ToString()
  186. {
  187. return GetFullMessage();
  188. }
  189. /// <summary>
  190. /// Get a portable version of this object
  191. /// </summary>
  192. /// <returns>the portable instance of this object</returns>
  193. /// <remarks>
  194. /// <para>
  195. /// Get a cross thread portable version of this object
  196. /// </para>
  197. /// </remarks>
  198. object IFixingRequired.GetFixedObject()
  199. {
  200. return GetFullMessage();
  201. }
  202. /// <summary>
  203. /// Inner class used to represent a single context frame in the stack.
  204. /// </summary>
  205. /// <remarks>
  206. /// <para>
  207. /// Inner class used to represent a single context frame in the stack.
  208. /// </para>
  209. /// </remarks>
  210. private sealed class StackFrame
  211. {
  212. #region Private Instance Fields
  213. private readonly string m_message;
  214. private readonly StackFrame m_parent;
  215. private string m_fullMessage = null;
  216. #endregion
  217. #region Internal Instance Constructors
  218. /// <summary>
  219. /// Constructor
  220. /// </summary>
  221. /// <param name="message">The message for this context.</param>
  222. /// <param name="parent">The parent context in the chain.</param>
  223. /// <remarks>
  224. /// <para>
  225. /// Initializes a new instance of the <see cref="StackFrame" /> class
  226. /// with the specified message and parent context.
  227. /// </para>
  228. /// </remarks>
  229. internal StackFrame(string message, StackFrame parent)
  230. {
  231. m_message = message;
  232. m_parent = parent;
  233. if (parent == null)
  234. {
  235. m_fullMessage = message;
  236. }
  237. }
  238. #endregion Internal Instance Constructors
  239. #region Internal Instance Properties
  240. /// <summary>
  241. /// Get the message.
  242. /// </summary>
  243. /// <value>The message.</value>
  244. /// <remarks>
  245. /// <para>
  246. /// Get the message.
  247. /// </para>
  248. /// </remarks>
  249. internal string Message
  250. {
  251. get { return m_message; }
  252. }
  253. /// <summary>
  254. /// Gets the full text of the context down to the root level.
  255. /// </summary>
  256. /// <value>
  257. /// The full text of the context down to the root level.
  258. /// </value>
  259. /// <remarks>
  260. /// <para>
  261. /// Gets the full text of the context down to the root level.
  262. /// </para>
  263. /// </remarks>
  264. internal string FullMessage
  265. {
  266. get
  267. {
  268. if (m_fullMessage == null && m_parent != null)
  269. {
  270. m_fullMessage = string.Concat(m_parent.FullMessage, " ", m_message);
  271. }
  272. return m_fullMessage;
  273. }
  274. }
  275. #endregion Internal Instance Properties
  276. }
  277. /// <summary>
  278. /// Struct returned from the <see cref="ThreadContextStack.Push"/> method.
  279. /// </summary>
  280. /// <remarks>
  281. /// <para>
  282. /// This struct implements the <see cref="IDisposable"/> and is designed to be used
  283. /// with the <see langword="using"/> pattern to remove the stack frame at the end of the scope.
  284. /// </para>
  285. /// </remarks>
  286. private struct AutoPopStackFrame : IDisposable
  287. {
  288. #region Private Instance Fields
  289. /// <summary>
  290. /// The ThreadContextStack internal stack
  291. /// </summary>
  292. private Stack m_frameStack;
  293. /// <summary>
  294. /// The depth to trim the stack to when this instance is disposed
  295. /// </summary>
  296. private int m_frameDepth;
  297. #endregion Private Instance Fields
  298. #region Internal Instance Constructors
  299. /// <summary>
  300. /// Constructor
  301. /// </summary>
  302. /// <param name="frameStack">The internal stack used by the ThreadContextStack.</param>
  303. /// <param name="frameDepth">The depth to return the stack to when this object is disposed.</param>
  304. /// <remarks>
  305. /// <para>
  306. /// Initializes a new instance of the <see cref="AutoPopStackFrame" /> class with
  307. /// the specified stack and return depth.
  308. /// </para>
  309. /// </remarks>
  310. internal AutoPopStackFrame(Stack frameStack, int frameDepth)
  311. {
  312. m_frameStack = frameStack;
  313. m_frameDepth = frameDepth;
  314. }
  315. #endregion Internal Instance Constructors
  316. #region Implementation of IDisposable
  317. /// <summary>
  318. /// Returns the stack to the correct depth.
  319. /// </summary>
  320. /// <remarks>
  321. /// <para>
  322. /// Returns the stack to the correct depth.
  323. /// </para>
  324. /// </remarks>
  325. public void Dispose()
  326. {
  327. if (m_frameDepth >= 0 && m_frameStack != null)
  328. {
  329. while(m_frameStack.Count > m_frameDepth)
  330. {
  331. m_frameStack.Pop();
  332. }
  333. }
  334. }
  335. #endregion Implementation of IDisposable
  336. }
  337. #if NETCF_1_0
  338. /// <summary>
  339. /// Subclass of <see cref="System.Collections.Stack"/> to
  340. /// provide missing methods.
  341. /// </summary>
  342. /// <remarks>
  343. /// <para>
  344. /// The Compact Framework version of the <see cref="System.Collections.Stack"/>
  345. /// class is missing the <c>Clear</c> and <c>Clone</c> methods.
  346. /// This subclass adds implementations of those missing methods.
  347. /// </para>
  348. /// </remarks>
  349. public class Stack : System.Collections.Stack
  350. {
  351. /// <summary>
  352. /// Clears the stack of all elements.
  353. /// </summary>
  354. /// <remarks>
  355. /// <para>
  356. /// Clears the stack of all elements.
  357. /// </para>
  358. /// </remarks>
  359. public void Clear()
  360. {
  361. while(Count > 0)
  362. {
  363. Pop();
  364. }
  365. }
  366. /// <summary>
  367. /// Makes a shallow copy of the stack's elements.
  368. /// </summary>
  369. /// <returns>A new stack that has a shallow copy of the stack's elements.</returns>
  370. /// <remarks>
  371. /// <para>
  372. /// Makes a shallow copy of the stack's elements.
  373. /// </para>
  374. /// </remarks>
  375. public Stack Clone()
  376. {
  377. Stack res = new Stack();
  378. object[] items = ToArray();
  379. foreach(object item in items)
  380. {
  381. res.Push(item);
  382. }
  383. return res;
  384. }
  385. }
  386. #endif
  387. }
  388. }