StringLogObject.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #region --------------- Copyright Dresser Wayne Pignone -------------
  2. /*
  3. * $Log: /Wrk/WayneLibraries/Wrk/Log/StringLogObject.cs $
  4. *
  5. * 5 08-02-13 9:30 Mattias.larsson
  6. * FxCop fixes.
  7. *
  8. * 4 07-03-19 17:12 roger.månsson
  9. * Allow null as LogObject.
  10. */
  11. #endregion
  12. using System;
  13. using System.Text;
  14. using System.Diagnostics.CodeAnalysis;
  15. namespace Wayne.Lib.Log
  16. {
  17. /// <summary>
  18. /// The StringLogObject-class serves as a helpclass to convert one or more
  19. /// objects into one or more strings to log. Also provides format abilities.
  20. /// </summary>
  21. public class StringLogObject : ILogObject
  22. {
  23. #region Fields
  24. private object[] logObjects;
  25. private string format;
  26. private IFormatProvider provider;
  27. #endregion
  28. #region Construction
  29. /// <summary>
  30. /// Constructor.
  31. /// </summary>
  32. /// <param name="logObjects">A number of objects to log.</param>
  33. [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "objects")]
  34. public StringLogObject(params object[] logObjects)
  35. {
  36. this.logObjects = logObjects;
  37. }
  38. /// <summary>
  39. /// Constructor.
  40. /// </summary>
  41. /// <param name="format">A format-string to format the items of an array.</param>
  42. /// <param name="provider">An IFormatProvider to format the items of an array.</param>
  43. /// <param name="array">An array of objects to log.</param>
  44. public StringLogObject(string format, IFormatProvider provider, Array array)
  45. {
  46. this.format = format;
  47. this.provider = provider;
  48. this.logObjects = new object[] { array };
  49. }
  50. /// <summary>
  51. /// Constructor.
  52. /// </summary>
  53. /// <param name="format">A format-string to format the items of an array.</param>
  54. /// <param name="provider">An IFormatProvider to format the items of an array.</param>
  55. /// <param name="logObjects">A number of objects to log.</param>
  56. [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "objects")]
  57. public StringLogObject(string format, IFormatProvider provider, params object[] logObjects)
  58. {
  59. this.format = format;
  60. this.provider = provider;
  61. this.logObjects = logObjects;
  62. }
  63. #endregion
  64. #region Properties
  65. bool ILogObject.UsesFormat
  66. {
  67. get { return true; }
  68. }
  69. string ILogObject.Format
  70. {
  71. get { return format; }
  72. set { format = value; }
  73. }
  74. IFormatProvider ILogObject.Provider
  75. {
  76. get { return provider; }
  77. set { provider = value; }
  78. }
  79. #endregion
  80. #region Methods
  81. /// <summary>
  82. /// Appends this object's logObjects to a StringBuilder-output.
  83. /// </summary>
  84. /// <param name="output">The StringBuilder.</param>
  85. /// <param name="logWriter">The LogWriter to write the logObject.</param>
  86. /// <param name="indentLength">The indent to be used if many lines.</param>
  87. /// <param name="isFirstLine">Is this the first line to log?</param>
  88. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  89. void ILogObject.AppendToStringBuilder(LogWriter logWriter, StringBuilder output,
  90. int indentLength, ref bool isFirstLine, ref string indent)
  91. {
  92. foreach (object logObject in logObjects)
  93. AppendObjectToStringBuilder(logObject, output, logWriter, indentLength, ref isFirstLine, ref indent, format, provider);
  94. }
  95. #endregion
  96. #region Static Support Methods
  97. /// <summary>
  98. /// Appends an object to a StringBuilder-output.
  99. /// </summary>
  100. /// <param name="logObject">The object to log.</param>
  101. /// <param name="output">The StringBuilder.</param>
  102. /// <param name="logWriter">The LogWriter to write the logObject.</param>
  103. /// <param name="indentLength">The indent to be used if many lines.</param>
  104. /// <param name="isFirstLine">Is this the first line to log?</param>
  105. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  106. internal static void AppendObjectToStringBuilder(object logObject, StringBuilder output, LogWriter logWriter,
  107. int indentLength, ref bool isFirstLine, ref string indent)
  108. {
  109. AppendObjectToStringBuilder(logObject, output, logWriter, indentLength,
  110. ref isFirstLine, ref indent, null, null);
  111. }
  112. /// <summary>
  113. /// Appends an object to a StringBuilder-output.
  114. /// </summary>
  115. /// <param name="logObject">The object to log.</param>
  116. /// <param name="output">The StringBuilder.</param>
  117. /// <param name="logWriter">The LogWriter to write the logObject.</param>
  118. /// <param name="indentLength">The indent to be used if many lines.</param>
  119. /// <param name="isFirstLine">Is this the first line to log?</param>
  120. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  121. /// <param name="format">A format-string to format the objects.</param>
  122. /// <param name="provider">An IFormatProvider to format the objects.</param>
  123. private static void AppendObjectToStringBuilder(object logObject, StringBuilder output, LogWriter logWriter,
  124. int indentLength, ref bool isFirstLine, ref string indent, string format, IFormatProvider provider)
  125. {
  126. // Check if the logObject is an ILogObject.
  127. ILogObject iLogObject = logObject as ILogObject;
  128. if (iLogObject != null)
  129. {
  130. if (iLogObject.UsesFormat && (format != null) && (iLogObject.Format == null))
  131. {
  132. // Copy my format to the stringLogObject.
  133. iLogObject.Format = format;
  134. iLogObject.Provider = provider;
  135. }
  136. iLogObject.AppendToStringBuilder(logWriter, output, indentLength, ref isFirstLine, ref indent);
  137. }
  138. else
  139. {
  140. string[] logLines = logObject as string[];
  141. if (logLines != null)
  142. {
  143. // The logObject is an array of strings.
  144. AppendStringsToStringBuilder(logLines, output, logWriter, indentLength, ref isFirstLine, ref indent);
  145. }
  146. else
  147. {
  148. Array logObjectArray = logObject as Array;
  149. if (logObjectArray != null)
  150. {
  151. // This is an array. Was there a format provided?
  152. if (format != null)
  153. {
  154. // There is a format provided. In this case, write all the items in one string.
  155. StringBuilder arrayBuilder = new StringBuilder();
  156. bool firstItem = true;
  157. foreach (object logObjectItem in logObjectArray)
  158. {
  159. // Append a separator character.
  160. if (firstItem)
  161. {
  162. firstItem = false;
  163. arrayBuilder.Append(" ");
  164. }
  165. else
  166. arrayBuilder.Append(", ");
  167. // try to format the object with the provided format and IFormatProvider.
  168. IFormattable formattableItem = logObjectItem as IFormattable;
  169. if (formattableItem != null)
  170. arrayBuilder.Append(formattableItem.ToString(format, provider));
  171. else
  172. arrayBuilder.Append(logObjectItem.ToString());
  173. }
  174. AppendStringToStringBuilder(arrayBuilder.ToString(), output, logWriter, indentLength, ref isFirstLine, ref indent);
  175. }
  176. else
  177. {
  178. // No format provided. Just write the objects one by one in a normal fashion.
  179. foreach (object arrayItem in logObjectArray)
  180. AppendObjectToStringBuilder(arrayItem, output, logWriter, indentLength, ref isFirstLine, ref indent);
  181. }
  182. }
  183. else
  184. {
  185. if (format != null)
  186. {
  187. IFormattable formattableItem = logObject as IFormattable;
  188. if (formattableItem != null)
  189. {
  190. // Format the logObject with the given format-string and IFormatProvider.
  191. try
  192. {
  193. AppendStringToStringBuilder(formattableItem.ToString(format, provider), output, logWriter, indentLength, ref isFirstLine, ref indent);
  194. }
  195. catch (FormatException)
  196. {
  197. // Simply convert the logObject to a string.
  198. AppendStringToStringBuilder(logObject.ToString(), output, logWriter, indentLength, ref isFirstLine, ref indent);
  199. }
  200. }
  201. else
  202. {
  203. // Simply convert the logObject to a string.
  204. AppendStringToStringBuilder(logObject.ToString(), output, logWriter, indentLength, ref isFirstLine, ref indent);
  205. }
  206. }
  207. else
  208. {
  209. // Simply convert the logObject to a string.
  210. if (logObject != null)
  211. AppendStringToStringBuilder(logObject.ToString(), output, logWriter, indentLength, ref isFirstLine, ref indent);
  212. else
  213. AppendStringToStringBuilder("null", output, logWriter, indentLength, ref isFirstLine, ref indent);
  214. }
  215. }
  216. }
  217. }
  218. }
  219. /// <summary>
  220. /// Appends a string to a StringBuilder-output.
  221. /// </summary>
  222. /// <param name="logString">The string to log.</param>
  223. /// <param name="output">The StringBuilder.</param>
  224. /// <param name="logWriter">The LogWriter to write the logObject.</param>
  225. /// <param name="indentLength">The indent to be used if many lines.</param>
  226. /// <param name="isFirstLine">Is this the first line to log?</param>
  227. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  228. internal static void AppendStringToStringBuilder(string logString, StringBuilder output,
  229. LogWriter logWriter, int indentLength, ref bool isFirstLine, ref string indent)
  230. {
  231. // Check if the string contains new line-characters.
  232. if (logString.IndexOf("\r\n", StringComparison.Ordinal) > -1)
  233. {
  234. // Create an array of strings cutting after each new line-character.
  235. string[] logLines = logString.Replace("\r\n", "\uFFFF").Split('\uFFFF');
  236. AppendStringsToStringBuilder(logLines, output, logWriter, indentLength, ref isFirstLine, ref indent);
  237. }
  238. else
  239. {
  240. if (isFirstLine)
  241. isFirstLine = false;
  242. else
  243. AppendIndent(output, indentLength, ref indent);
  244. output.Append(logString); // A normal single line string.
  245. output.Append("\r\n");
  246. }
  247. }
  248. /// <summary>
  249. /// Appends a string-array to a StringBuilder-output.
  250. /// </summary>
  251. /// <param name="logLines">The array of strings.</param>
  252. /// <param name="output">The StringBuilder.</param>
  253. /// <param name="logWriter">The logwriter to be used for logging.</param>
  254. /// <param name="indentLength">The indent to be used if many lines.</param>
  255. /// <param name="isFirstLine">Is this the first line to log?</param>
  256. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  257. internal static void AppendStringsToStringBuilder(string[] logLines, StringBuilder output,
  258. LogWriter logWriter, int indentLength, ref bool isFirstLine, ref string indent)
  259. {
  260. // Remove any empty lines at the end.
  261. int logLinesLength = logLines.Length;
  262. for (int i = logLines.Length - 1; i >= 0; i--)
  263. {
  264. if (string.IsNullOrEmpty(logLines[i]))
  265. logLinesLength--;
  266. else
  267. break; // The first non-empty line from the end is found. Stop.
  268. }
  269. // Log an array of strings.
  270. if (logLinesLength > 1)
  271. {
  272. for (int i = 0; i < logLinesLength; i++)
  273. AppendStringToStringBuilder(logLines[i], output, logWriter, indentLength, ref isFirstLine, ref indent);
  274. }
  275. else if (logLinesLength == 1)
  276. AppendStringToStringBuilder(logLines[0], output, logWriter, indentLength, ref isFirstLine, ref indent);
  277. }
  278. /// <summary>
  279. /// Appends the indent to a StringBuilder-output.
  280. /// (After this call the 'indent' is defined.)
  281. /// </summary>
  282. /// <param name="indentLength">The indent to be used if many lines.</param>
  283. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  284. internal static void EnsureIndent(int indentLength, ref string indent)
  285. {
  286. if (indent == null)
  287. indent = Strings.Indent(indentLength, true);
  288. }
  289. /// <summary>
  290. /// Appends the indent to a StringBuilder-output.
  291. /// (After this call the 'indent' is defined.)
  292. /// </summary>
  293. /// <param name="output">The StringBuilder.</param>
  294. /// <param name="indentLength">The indent to be used if many lines.</param>
  295. /// <param name="indent">A string holding a generated indent-text (=a number of spaces). Use AppendIndent() to append the indent.</param>
  296. internal static void AppendIndent(StringBuilder output, int indentLength, ref string indent)
  297. {
  298. EnsureIndent(indentLength, ref indent);
  299. output.Append(indent);
  300. }
  301. #endregion
  302. }
  303. }