Logger.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #region License
  2. /*
  3. * Logger.cs
  4. *
  5. * The MIT License
  6. *
  7. * Copyright (c) 2013-2022 sta.blockhead
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #endregion
  28. using System;
  29. using System.Diagnostics;
  30. using System.IO;
  31. namespace WebSocketSharp
  32. {
  33. /// <summary>
  34. /// Provides a set of methods and properties for logging.
  35. /// </summary>
  36. /// <remarks>
  37. /// <para>
  38. /// If you output a log with lower than the current logging level,
  39. /// it cannot be outputted.
  40. /// </para>
  41. /// <para>
  42. /// The default output method writes a log to the standard output
  43. /// stream and the text file if it has a valid path.
  44. /// </para>
  45. /// <para>
  46. /// If you would like to use the custom output method, you should
  47. /// specify it with the constructor or the <see cref="Logger.Output"/>
  48. /// property.
  49. /// </para>
  50. /// </remarks>
  51. public class Logger
  52. {
  53. #region Private Fields
  54. private volatile string _file;
  55. private volatile LogLevel _level;
  56. private Action<LogData, string> _output;
  57. private object _sync;
  58. #endregion
  59. #region Public Constructors
  60. /// <summary>
  61. /// Initializes a new instance of the <see cref="Logger"/> class.
  62. /// </summary>
  63. /// <remarks>
  64. /// This constructor initializes the logging level with the Error level.
  65. /// </remarks>
  66. public Logger ()
  67. : this (LogLevel.Error, null, null)
  68. {
  69. }
  70. /// <summary>
  71. /// Initializes a new instance of the <see cref="Logger"/> class with
  72. /// the specified logging level.
  73. /// </summary>
  74. /// <param name="level">
  75. /// One of the <see cref="LogLevel"/> enum values that specifies
  76. /// the logging level.
  77. /// </param>
  78. public Logger (LogLevel level)
  79. : this (level, null, null)
  80. {
  81. }
  82. /// <summary>
  83. /// Initializes a new instance of the <see cref="Logger"/> class with
  84. /// the specified logging level, path to the log file, and delegate
  85. /// used to output a log.
  86. /// </summary>
  87. /// <param name="level">
  88. /// One of the <see cref="LogLevel"/> enum values that specifies
  89. /// the logging level.
  90. /// </param>
  91. /// <param name="file">
  92. /// A <see cref="string"/> that specifies the path to the log file.
  93. /// </param>
  94. /// <param name="output">
  95. /// An <see cref="T:System.Action{LogData, string}"/> that specifies
  96. /// the delegate used to output a log.
  97. /// </param>
  98. public Logger (LogLevel level, string file, Action<LogData, string> output)
  99. {
  100. _level = level;
  101. _file = file;
  102. _output = output ?? defaultOutput;
  103. _sync = new object ();
  104. }
  105. #endregion
  106. #region Public Properties
  107. /// <summary>
  108. /// Gets or sets the path to the log file.
  109. /// </summary>
  110. /// <value>
  111. /// A <see cref="string"/> that represents the path to the log file if any.
  112. /// </value>
  113. public string File {
  114. get {
  115. return _file;
  116. }
  117. set {
  118. lock (_sync)
  119. _file = value;
  120. }
  121. }
  122. /// <summary>
  123. /// Gets or sets the current logging level.
  124. /// </summary>
  125. /// <remarks>
  126. /// A log with lower than the value of this property cannot be outputted.
  127. /// </remarks>
  128. /// <value>
  129. /// <para>
  130. /// One of the <see cref="LogLevel"/> enum values.
  131. /// </para>
  132. /// <para>
  133. /// It represents the current logging level.
  134. /// </para>
  135. /// </value>
  136. public LogLevel Level {
  137. get {
  138. return _level;
  139. }
  140. set {
  141. lock (_sync)
  142. _level = value;
  143. }
  144. }
  145. /// <summary>
  146. /// Gets or sets the delegate used to output a log.
  147. /// </summary>
  148. /// <value>
  149. /// <para>
  150. /// An <see cref="T:System.Action{LogData, string}"/> delegate.
  151. /// </para>
  152. /// <para>
  153. /// It references the method used to output a log.
  154. /// </para>
  155. /// <para>
  156. /// The string parameter passed to the delegate is the value of
  157. /// the <see cref="Logger.File"/> property.
  158. /// </para>
  159. /// <para>
  160. /// If the value to set is <see langword="null"/>, the default
  161. /// output method is set.
  162. /// </para>
  163. /// </value>
  164. public Action<LogData, string> Output {
  165. get {
  166. return _output;
  167. }
  168. set {
  169. lock (_sync)
  170. _output = value ?? defaultOutput;
  171. }
  172. }
  173. #endregion
  174. #region Private Methods
  175. private static void defaultOutput (LogData data, string path)
  176. {
  177. var val = data.ToString ();
  178. Console.WriteLine (val);
  179. if (path != null && path.Length > 0)
  180. writeToFile (val, path);
  181. }
  182. private void output (string message, LogLevel level)
  183. {
  184. lock (_sync) {
  185. if (_level > level)
  186. return;
  187. try {
  188. var data = new LogData (level, new StackFrame (2, true), message);
  189. _output (data, _file);
  190. }
  191. catch (Exception ex) {
  192. var data = new LogData (
  193. LogLevel.Fatal, new StackFrame (0, true), ex.Message
  194. );
  195. Console.WriteLine (data.ToString ());
  196. }
  197. }
  198. }
  199. private static void writeToFile (string value, string path)
  200. {
  201. using (var writer = new StreamWriter (path, true))
  202. using (var syncWriter = TextWriter.Synchronized (writer))
  203. syncWriter.WriteLine (value);
  204. }
  205. #endregion
  206. #region Public Methods
  207. /// <summary>
  208. /// Outputs the specified message as a log with the Debug level.
  209. /// </summary>
  210. /// <remarks>
  211. /// If the current logging level is higher than the Debug level,
  212. /// this method does not output the message as a log.
  213. /// </remarks>
  214. /// <param name="message">
  215. /// A <see cref="string"/> that specifies the message to output.
  216. /// </param>
  217. public void Debug (string message)
  218. {
  219. if (_level > LogLevel.Debug)
  220. return;
  221. output (message, LogLevel.Debug);
  222. }
  223. /// <summary>
  224. /// Outputs the specified message as a log with the Error level.
  225. /// </summary>
  226. /// <remarks>
  227. /// If the current logging level is higher than the Error level,
  228. /// this method does not output the message as a log.
  229. /// </remarks>
  230. /// <param name="message">
  231. /// A <see cref="string"/> that specifies the message to output.
  232. /// </param>
  233. public void Error (string message)
  234. {
  235. if (_level > LogLevel.Error)
  236. return;
  237. output (message, LogLevel.Error);
  238. }
  239. /// <summary>
  240. /// Outputs the specified message as a log with the Fatal level.
  241. /// </summary>
  242. /// <param name="message">
  243. /// A <see cref="string"/> that specifies the message to output.
  244. /// </param>
  245. public void Fatal (string message)
  246. {
  247. if (_level > LogLevel.Fatal)
  248. return;
  249. output (message, LogLevel.Fatal);
  250. }
  251. /// <summary>
  252. /// Outputs the specified message as a log with the Info level.
  253. /// </summary>
  254. /// <remarks>
  255. /// If the current logging level is higher than the Info level,
  256. /// this method does not output the message as a log.
  257. /// </remarks>
  258. /// <param name="message">
  259. /// A <see cref="string"/> that specifies the message to output.
  260. /// </param>
  261. public void Info (string message)
  262. {
  263. if (_level > LogLevel.Info)
  264. return;
  265. output (message, LogLevel.Info);
  266. }
  267. /// <summary>
  268. /// Outputs the specified message as a log with the Trace level.
  269. /// </summary>
  270. /// <remarks>
  271. /// If the current logging level is higher than the Trace level,
  272. /// this method does not output the message as a log.
  273. /// </remarks>
  274. /// <param name="message">
  275. /// A <see cref="string"/> that specifies the message to output.
  276. /// </param>
  277. public void Trace (string message)
  278. {
  279. if (_level > LogLevel.Trace)
  280. return;
  281. output (message, LogLevel.Trace);
  282. }
  283. /// <summary>
  284. /// Outputs the specified message as a log with the Warn level.
  285. /// </summary>
  286. /// <remarks>
  287. /// If the current logging level is higher than the Warn level,
  288. /// this method does not output the message as a log.
  289. /// </remarks>
  290. /// <param name="message">
  291. /// A <see cref="string"/> that specifies the message to output.
  292. /// </param>
  293. public void Warn (string message)
  294. {
  295. if (_level > LogLevel.Warn)
  296. return;
  297. output (message, LogLevel.Warn);
  298. }
  299. #endregion
  300. }
  301. }