public static void Intercept() { if (!usingInterceptor) { usingInterceptor = true; if (harmony == null) { harmony = new Harmony("BSIPA Console Redirector Patcher"); } if (stdoutInterceptor == null) { stdoutInterceptor = new StdoutInterceptor(); } if (stderrInterceptor == null) { stderrInterceptor = new StdoutInterceptor() { isStdErr = true } } ; RedirectConsole(); ConsoleHarmonyPatches.Patch(harmony); } }
internal StandardLogger(string name) { ConsoleColorSupport(); if (!finalizedDefaultPrinters) { if (!addedConsolePrinters) { AddDefaultPrinter(new ColorlessConsolePrinter()); } StdoutInterceptor.Intercept(); finalizedDefaultPrinters = true; } logName = name; printers.Add(new PluginLogFilePrinter(name)); if (logThread == null || !logThread.IsAlive) { logThread = new Thread(LogThread); logThread.Start(); } }
/// <summary> /// The log printer thread for <see cref="StandardLogger"/>. /// </summary> private static void LogThread() { AppDomain.CurrentDomain.ProcessExit += (sender, args) => { StopLogThread(); }; loggerLogger = new StandardLogger("Log Subsystem"); loggerLogger.printers.Clear(); // don't need a log file for this one var timeout = TimeSpan.FromMilliseconds(LogCloseTimeout); var started = new HashSet <LogPrinter>(); while (logQueue.TryTake(out var msg, Timeout.Infinite)) { StdoutInterceptor.Intercept(); do { var logger = msg.Logger; IEnumerable <LogPrinter> printers = logger.printers; do { // aggregate all printers in the inheritance chain logger = logger.parent; if (logger != null) { printers = printers.Concat(logger.printers); } } while (logger != null); foreach (var printer in printers.Concat(defaultPrinters)) { try { // print to them all if (((byte)msg.Level & (byte)printer.Filter) != 0) { if (!started.Contains(printer)) { // start printer if not started printer.StartPrint(); started.Add(printer); } // update last use time and print printer.LastUse = Utils.CurrentTime(); printer.Print(msg.Level, msg.Time, msg.Logger.logName, msg.Message); } } catch (Exception e) { // do something sane in the face of an error Console.WriteLine($"printer errored: {e}"); } } var debugConfig = SelfConfig.SelfConfigRef?.Value?.Debug; if (debugConfig != null && debugConfig.HideMessagesForPerformance && logQueue.Count > debugConfig.HideLogThreshold) { // spam filtering (if queue has more tha 512 elements) logWaitEvent.Reset(); // pause incoming log requests // clear loggers for this instance, to print the message to all affected logs loggerLogger.printers.Clear(); var prints = new HashSet <LogPrinter>(); // clear the queue while (logQueue.TryTake(out var message)) { // aggregate loggers in the process var messageLogger = message.Logger; foreach (var print in messageLogger.printers) { prints.Add(print); } do { messageLogger = messageLogger.parent; if (messageLogger != null) { foreach (var print in messageLogger.printers) { prints.Add(print); } } } while (messageLogger != null); } // print using logging subsystem to all logger printers loggerLogger.printers.AddRange(prints); logQueue.Add(new LogMessage { // manually adding to the queue instead of using Warn() because calls to the logger are suspended here Level = Level.Warning, Logger = loggerLogger, Message = $"{loggerLogger.logName.ToUpper()}: Messages omitted to improve performance", Time = Utils.CurrentTime() }); // resume log calls logWaitEvent.Set(); } var now = Utils.CurrentTime(); var copy = new List <LogPrinter>(started); foreach (var printer in copy) { // close printer after 500ms from its last use if (now - printer.LastUse > timeout) { try { printer.EndPrint(); } catch (Exception e) { Console.WriteLine($"printer errored: {e}"); } started.Remove(printer); } } } // wait for messages for 500ms before ending the prints while (logQueue.TryTake(out msg, timeout)); if (logQueue.Count == 0) { // when the queue has been empty for 500ms, end all prints foreach (var printer in started) { try { printer.EndPrint(); } catch (Exception e) { Console.WriteLine($"printer errored: {e}"); } } started.Clear(); } } }