You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.3 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. using IPA.Logging;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using IPA;
  11. using IPA.Logging.Printers;
  12. namespace IPA.Logging
  13. {
  14. /// <summary>
  15. /// The default <see cref="Logger"/> implimentation.
  16. /// </summary>
  17. public class StandardLogger : Logger
  18. {
  19. private static readonly IReadOnlyList<LogPrinter> defaultPrinters = new List<LogPrinter>()
  20. {
  21. new ColoredConsolePrinter()
  22. {
  23. Filter = LogLevel.DebugOnly,
  24. Color = ConsoleColor.Green,
  25. },
  26. new ColoredConsolePrinter()
  27. {
  28. Filter = LogLevel.InfoOnly,
  29. Color = ConsoleColor.White,
  30. },
  31. new ColoredConsolePrinter()
  32. {
  33. Filter = LogLevel.WarningOnly,
  34. Color = ConsoleColor.Yellow,
  35. },
  36. new ColoredConsolePrinter()
  37. {
  38. Filter = LogLevel.ErrorOnly,
  39. Color = ConsoleColor.Red,
  40. },
  41. new ColoredConsolePrinter()
  42. {
  43. Filter = LogLevel.CriticalOnly,
  44. Color = ConsoleColor.Magenta,
  45. },
  46. new GlobalLogFilePrinter()
  47. };
  48. private string logName;
  49. private static bool showSourceClass = true;
  50. /// <summary>
  51. /// All levels defined by this filter will be sent to loggers. All others will be ignored.
  52. /// </summary>
  53. public static LogLevel PrintFilter { get; set; } = LogLevel.InfoUp;
  54. private List<LogPrinter> printers = new List<LogPrinter>(defaultPrinters);
  55. static StandardLogger()
  56. {
  57. if (ModPrefs.GetBool("IPA", "PrintDebug", false, true))
  58. PrintFilter = LogLevel.All;
  59. showSourceClass = ModPrefs.GetBool("IPA", "DebugShowCallSource", false, true);
  60. }
  61. internal StandardLogger(string name)
  62. {
  63. logName = name;
  64. printers.Add(new PluginLogFilePrinter(name));
  65. if (_logThread == null || !_logThread.IsAlive)
  66. {
  67. _logThread = new Thread(LogThread);
  68. _logThread.Start();
  69. }
  70. }
  71. /// <summary>
  72. /// Logs a specific message at a given level.
  73. /// </summary>
  74. /// <param name="level">the message level</param>
  75. /// <param name="message">the message to log</param>
  76. public override void Log(Level level, string message)
  77. {
  78. _logQueue.Add(new LogMessage
  79. {
  80. level = level,
  81. message = message,
  82. logger = this,
  83. time = DateTime.Now
  84. });
  85. }
  86. /// <summary>
  87. /// An override to <see cref="Logger.Debug(string)"/> which shows the method that called it.
  88. /// </summary>
  89. /// <param name="message">the message to log</param>
  90. public override void Debug(string message)
  91. { // add source to message
  92. var stfm = new StackTrace().GetFrame(1).GetMethod();
  93. if (showSourceClass)
  94. base.Debug($"{{{stfm.DeclaringType.FullName}::{stfm.Name}}} {message}");
  95. else
  96. base.Debug(message);
  97. }
  98. internal struct LogMessage
  99. {
  100. public Level level;
  101. public StandardLogger logger;
  102. public string message;
  103. public DateTime time;
  104. }
  105. private static BlockingCollection<LogMessage> _logQueue = new BlockingCollection<LogMessage>();
  106. private static Thread _logThread;
  107. private static void LogThread()
  108. {
  109. HashSet<LogPrinter> started = new HashSet<LogPrinter>();
  110. while (_logQueue.TryTake(out LogMessage msg, Timeout.Infinite)) {
  111. foreach (var printer in msg.logger.printers)
  112. {
  113. try
  114. {
  115. if (((byte)msg.level & (byte)printer.Filter) != 0)
  116. {
  117. if (!started.Contains(printer))
  118. {
  119. printer.StartPrint();
  120. started.Add(printer);
  121. }
  122. printer.Print(msg.level, msg.time, msg.logger.logName, msg.message);
  123. }
  124. }
  125. catch (Exception e)
  126. {
  127. Console.WriteLine($"printer errored {e}");
  128. }
  129. }
  130. if (_logQueue.Count == 0)
  131. {
  132. foreach (var printer in started)
  133. {
  134. try
  135. {
  136. printer.EndPrint();
  137. }
  138. catch (Exception e)
  139. {
  140. Console.WriteLine($"printer errored {e}");
  141. }
  142. }
  143. started.Clear();
  144. }
  145. }
  146. }
  147. internal static void StopLogThread()
  148. {
  149. _logQueue.CompleteAdding();
  150. _logThread.Join();
  151. }
  152. }
  153. }