PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/log4php/LoggerNDC.php

http://sabre-zarafa.googlecode.com/
PHP | 203 lines | 39 code | 10 blank | 154 comment | 5 complexity | a28934d3b053b80bb76798e91e11db79 MD5 | raw file
  1. <?php
  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. * @package log4php
  19. */
  20. /**
  21. * The NDC class implements <i>nested diagnostic contexts</i>.
  22. *
  23. * NDC was defined by Neil Harrison in the article "Patterns for Logging
  24. * Diagnostic Messages" part of the book <i>"Pattern Languages of
  25. * Program Design 3"</i> edited by Martin et al.
  26. *
  27. * A Nested Diagnostic Context, or NDC in short, is an instrument
  28. * to distinguish interleaved log output from different sources. Log
  29. * output is typically interleaved when a server handles multiple
  30. * clients near-simultaneously.
  31. *
  32. * This class is similar to the {@link LoggerMDC} class except that it is
  33. * based on a stack instead of a map.
  34. *
  35. * Interleaved log output can still be meaningful if each log entry
  36. * from different contexts had a distinctive stamp. This is where NDCs
  37. * come into play.
  38. *
  39. * <b>Note that NDCs are managed on a per thread basis</b>.
  40. *
  41. * NDC operations such as {@link push()}, {@link pop()},
  42. * {@link clear()}, {@link getDepth()} and {@link setMaxDepth()}
  43. * affect the NDC of the <i>current</i> thread only. NDCs of other
  44. * threads remain unaffected.
  45. *
  46. * For example, a servlet can build a per client request NDC
  47. * consisting the clients host name and other information contained in
  48. * the the request. <i>Cookies</i> are another source of distinctive
  49. * information. To build an NDC one uses the {@link push()}
  50. * operation.
  51. *
  52. * Simply put,
  53. *
  54. * - Contexts can be nested.
  55. * - When entering a context, call <kbd>LoggerNDC::push()</kbd>
  56. * As a side effect, if there is no nested diagnostic context for the
  57. * current thread, this method will create it.
  58. * - When leaving a context, call <kbd>LoggerNDC::pop()</kbd>
  59. * - <b>When exiting a thread make sure to call {@link remove()}</b>
  60. *
  61. * There is no penalty for forgetting to match each
  62. * <kbd>push</kbd> operation with a corresponding <kbd>pop</kbd>,
  63. * except the obvious mismatch between the real application context
  64. * and the context set in the NDC.
  65. *
  66. * If configured to do so, {@link LoggerPatternLayout} and {@link LoggerLayoutTTCC}
  67. * instances automatically retrieve the nested diagnostic
  68. * context for the current thread without any user intervention.
  69. * Hence, even if a servlet is serving multiple clients
  70. * simultaneously, the logs emanating from the same code (belonging to
  71. * the same category) can still be distinguished because each client
  72. * request will have a different NDC tag.
  73. *
  74. * Example:
  75. *
  76. * {@example ../../examples/php/ndc.php 19}<br>
  77. *
  78. * With the properties file:
  79. *
  80. * {@example ../../examples/resources/ndc.properties 18}<br>
  81. *
  82. * Will result in the following (notice the conn and client ids):
  83. *
  84. * <pre>
  85. * 2009-09-13 19:04:27 DEBUG root conn=1234: just received a new connection in src/examples/php/ndc.php at 23
  86. * 2009-09-13 19:04:27 DEBUG root conn=1234 client=ab23: some more messages that can in src/examples/php/ndc.php at 25
  87. * 2009-09-13 19:04:27 DEBUG root conn=1234 client=ab23: now related to a client in src/examples/php/ndc.php at 26
  88. * 2009-09-13 19:04:27 DEBUG root : back and waiting for new connections in src/examples/php/ndc.php at 29
  89. * </pre>
  90. *
  91. * @version $Revision: 31 $
  92. * @package log4php
  93. * @since 0.3
  94. */
  95. class LoggerNDC {
  96. /** This is the repository of NDC stack */
  97. private static $stack = array();
  98. /**
  99. * Clear any nested diagnostic information if any. This method is
  100. * useful in cases where the same thread can be potentially used
  101. * over and over in different unrelated contexts.
  102. *
  103. * <p>This method is equivalent to calling the {@link setMaxDepth()}
  104. * method with a zero <var>maxDepth</var> argument.
  105. */
  106. public static function clear() {
  107. self::$stack = array();
  108. }
  109. /**
  110. * Never use this method directly, use the {@link LoggerLoggingEvent::getNDC()} method instead.
  111. * @return array
  112. */
  113. public static function get() {
  114. return implode(' ', self::$stack);
  115. }
  116. /**
  117. * Get the current nesting depth of this diagnostic context.
  118. *
  119. * @see setMaxDepth()
  120. * @return integer
  121. */
  122. public static function getDepth() {
  123. return count(self::$stack);
  124. }
  125. /**
  126. * Clients should call this method before leaving a diagnostic
  127. * context.
  128. *
  129. * <p>The returned value is the value that was pushed last. If no
  130. * context is available, then the empty string "" is returned.</p>
  131. *
  132. * @return string The innermost diagnostic context.
  133. */
  134. public static function pop() {
  135. if(count(self::$stack) > 0) {
  136. return array_pop(self::$stack);
  137. } else {
  138. return '';
  139. }
  140. }
  141. /**
  142. * Looks at the last diagnostic context at the top of this NDC
  143. * without removing it.
  144. *
  145. * <p>The returned value is the value that was pushed last. If no
  146. * context is available, then the empty string "" is returned.</p>
  147. * @return string The innermost diagnostic context.
  148. */
  149. public static function peek(){
  150. if(count(self::$stack) > 0) {
  151. return end(self::$stack);
  152. } else {
  153. return '';
  154. }
  155. }
  156. /**
  157. * Push new diagnostic context information for the current thread.
  158. *
  159. * <p>The contents of the <var>message</var> parameter is
  160. * determined solely by the client.
  161. *
  162. * @param string $message The new diagnostic context information.
  163. */
  164. public static function push($message) {
  165. array_push(self::$stack, (string)$message);
  166. }
  167. /**
  168. * Remove the diagnostic context for this thread.
  169. */
  170. public static function remove() {
  171. LoggerNDC::clear();
  172. }
  173. /**
  174. * Set maximum depth of this diagnostic context. If the current
  175. * depth is smaller or equal to <var>maxDepth</var>, then no
  176. * action is taken.
  177. *
  178. * <p>This method is a convenient alternative to multiple
  179. * {@link pop()} calls. Moreover, it is often the case that at
  180. * the end of complex call sequences, the depth of the NDC is
  181. * unpredictable. The {@link setMaxDepth()} method circumvents
  182. * this problem.
  183. *
  184. * @param integer $maxDepth
  185. * @see getDepth()
  186. */
  187. public static function setMaxDepth($maxDepth) {
  188. $maxDepth = (int)$maxDepth;
  189. if(LoggerNDC::getDepth() > $maxDepth) {
  190. self::$stack = array_slice(self::$stack, 0, $maxDepth);
  191. }
  192. }
  193. }