SystemStringFormat.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. using System.Text;
  21. using System.Xml;
  22. using System.Text.RegularExpressions;
  23. namespace log4net.Util
  24. {
  25. /// <summary>
  26. /// Utility class that represents a format string.
  27. /// </summary>
  28. /// <remarks>
  29. /// <para>
  30. /// Utility class that represents a format string.
  31. /// </para>
  32. /// </remarks>
  33. /// <author>Nicko Cadell</author>
  34. public sealed class SystemStringFormat
  35. {
  36. private readonly IFormatProvider m_provider;
  37. private readonly string m_format;
  38. private readonly object[] m_args;
  39. #region Constructor
  40. /// <summary>
  41. /// Initialise the <see cref="SystemStringFormat"/>
  42. /// </summary>
  43. /// <param name="provider">An <see cref="System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
  44. /// <param name="format">A <see cref="System.String"/> containing zero or more format items.</param>
  45. /// <param name="args">An <see cref="System.Object"/> array containing zero or more objects to format.</param>
  46. public SystemStringFormat(IFormatProvider provider, string format, params object[] args)
  47. {
  48. m_provider = provider;
  49. m_format = format;
  50. m_args = args;
  51. }
  52. #endregion Constructor
  53. /// <summary>
  54. /// Format the string and arguments
  55. /// </summary>
  56. /// <returns>the formatted string</returns>
  57. public override string ToString()
  58. {
  59. return StringFormat(m_provider, m_format, m_args);
  60. }
  61. #region StringFormat
  62. /// <summary>
  63. /// Replaces the format item in a specified <see cref="System.String"/> with the text equivalent
  64. /// of the value of a corresponding <see cref="System.Object"/> instance in a specified array.
  65. /// A specified parameter supplies culture-specific formatting information.
  66. /// </summary>
  67. /// <param name="provider">An <see cref="System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
  68. /// <param name="format">A <see cref="System.String"/> containing zero or more format items.</param>
  69. /// <param name="args">An <see cref="System.Object"/> array containing zero or more objects to format.</param>
  70. /// <returns>
  71. /// A copy of format in which the format items have been replaced by the <see cref="System.String"/>
  72. /// equivalent of the corresponding instances of <see cref="System.Object"/> in args.
  73. /// </returns>
  74. /// <remarks>
  75. /// <para>
  76. /// This method does not throw exceptions. If an exception thrown while formatting the result the
  77. /// exception and arguments are returned in the result string.
  78. /// </para>
  79. /// </remarks>
  80. private static string StringFormat(IFormatProvider provider, string format, params object[] args)
  81. {
  82. try
  83. {
  84. // The format is missing, log null value
  85. if (format == null)
  86. {
  87. return null;
  88. }
  89. // The args are missing - should not happen unless we are called explicitly with a null array
  90. if (args == null)
  91. {
  92. return format;
  93. }
  94. // Try to format the string
  95. return String.Format(provider, format, args);
  96. }
  97. catch(Exception ex)
  98. {
  99. log4net.Util.LogLog.Warn(declaringType, "Exception while rendering format ["+format+"]", ex);
  100. return StringFormatError(ex, format, args);
  101. }
  102. #if !NET_2_0 && !MONO_2_0 && !MONO_3_5 && !MONO_4_0 && !NETSTANDARD1_3
  103. catch
  104. {
  105. log4net.Util.LogLog.Warn(declaringType, "Exception while rendering format ["+format+"]");
  106. return StringFormatError(null, format, args);
  107. }
  108. #endif
  109. }
  110. /// <summary>
  111. /// Process an error during StringFormat
  112. /// </summary>
  113. private static string StringFormatError(Exception formatException, string format, object[] args)
  114. {
  115. try
  116. {
  117. StringBuilder buf = new StringBuilder("<log4net.Error>");
  118. if (formatException != null)
  119. {
  120. buf.Append("Exception during StringFormat: ").Append(formatException.Message);
  121. }
  122. else
  123. {
  124. buf.Append("Exception during StringFormat");
  125. }
  126. buf.Append(" <format>").Append(format).Append("</format>");
  127. buf.Append("<args>");
  128. RenderArray(args, buf);
  129. buf.Append("</args>");
  130. buf.Append("</log4net.Error>");
  131. return buf.ToString();
  132. }
  133. catch(Exception ex)
  134. {
  135. log4net.Util.LogLog.Error(declaringType, "INTERNAL ERROR during StringFormat error handling", ex);
  136. return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>";
  137. }
  138. #if !NET_2_0 && !MONO_2_0 && !MONO_3_5 && !MONO_4_0 && !NETSTANDARD1_3
  139. catch
  140. {
  141. log4net.Util.LogLog.Error(declaringType, "INTERNAL ERROR during StringFormat error handling");
  142. return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>";
  143. }
  144. #endif
  145. }
  146. /// <summary>
  147. /// Dump the contents of an array into a string builder
  148. /// </summary>
  149. private static void RenderArray(Array array, StringBuilder buffer)
  150. {
  151. if (array == null)
  152. {
  153. buffer.Append(SystemInfo.NullText);
  154. }
  155. else
  156. {
  157. if (array.Rank != 1)
  158. {
  159. buffer.Append(array.ToString());
  160. }
  161. else
  162. {
  163. buffer.Append("{");
  164. int len = array.Length;
  165. if (len > 0)
  166. {
  167. RenderObject(array.GetValue(0), buffer);
  168. for (int i = 1; i < len; i++)
  169. {
  170. buffer.Append(", ");
  171. RenderObject(array.GetValue(i), buffer);
  172. }
  173. }
  174. buffer.Append("}");
  175. }
  176. }
  177. }
  178. /// <summary>
  179. /// Dump an object to a string
  180. /// </summary>
  181. private static void RenderObject(Object obj, StringBuilder buffer)
  182. {
  183. if (obj == null)
  184. {
  185. buffer.Append(SystemInfo.NullText);
  186. }
  187. else
  188. {
  189. try
  190. {
  191. buffer.Append(obj);
  192. }
  193. catch(Exception ex)
  194. {
  195. buffer.Append("<Exception: ").Append(ex.Message).Append(">");
  196. }
  197. #if !NET_2_0 && !MONO_2_0 && !MONO_3_5 && !MONO_4_0 && !NETSTANDARD1_3
  198. catch
  199. {
  200. buffer.Append("<Exception>");
  201. }
  202. #endif
  203. }
  204. }
  205. #endregion StringFormat
  206. #region Private Static Fields
  207. /// <summary>
  208. /// The fully qualified type of the SystemStringFormat class.
  209. /// </summary>
  210. /// <remarks>
  211. /// Used by the internal logger to record the Type of the
  212. /// log message.
  213. /// </remarks>
  214. private readonly static Type declaringType = typeof(SystemStringFormat);
  215. #endregion Private Static Fields
  216. }
  217. }