/// <summary> /// Gets a child printer with the given name, either constructing a new one or using one that was already made. /// </summary> /// <param name="name"></param> /// <returns>a child <see cref="StandardLogger"/> with the given sub-name</returns> internal StandardLogger GetChild(string name) { if (!children.TryGetValue(name, out var child)) { child = new StandardLogger(this, name); children.Add(name, child); } return(child); }
internal StandardLogger GetChild(string name) { if (!children.TryGetValue(name, out StandardLogger chld)) { chld = new StandardLogger(logName, name, printers.ToArray()); children.Add(name, chld); } return(chld); }
private StandardLogger(StandardLogger parent, string subName) { logName = $"{parent.logName}/{subName}"; this.parent = parent; printers = new List <LogPrinter>() { new PluginSubLogPrinter(parent.logName, subName) }; if (logThread == null || !logThread.IsAlive) { logThread = new Thread(LogThread); logThread.Start(); } }
private StandardLogger(StandardLogger parent, string subName) { logName = $"{parent.logName}/{subName}"; this.parent = parent; printers = new List <LogPrinter>(); if (SelfConfig.Debug_.CondenseModLogs_) { printers.Add(new PluginSubLogPrinter(parent.logName, subName)); } 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)) { 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 = DateTime.Now; 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}"); } } if (logQueue.Count > 512) { // 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 = DateTime.Now }); // resume log calls logWaitEvent.Set(); } var now = DateTime.Now; 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(); } } }
private StandardLogger(StandardLogger parent, string subName) { logName = $"{parent.logName}/{subName}"; BepInExLogger = BepInEx.Logging.Logger.CreateLogSource(logName); this.parent = parent; }