Simplify ConsoleSetOut fix; redirect console messages to logging system

This commit is contained in:
ghorsington committed 2020-07-05 12:02:23 +03:00
1 parent dc6c76b59f
commit f2b7b9993e
5 files changed
+30 -76

No files matched your search

@@ -1,29 +1,20 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using BepInEx.Logging;
using HarmonyLib; using HarmonyLib;
namespace BepInEx.Preloader.RuntimeFixes namespace BepInEx.Preloader.RuntimeFixes
{ {
/*
* By default, setting Console.Out removes the previous listener
* This can be a problem in Unity because it installs its own TextWriter while BepInEx needs to install it
* one too for the console. This runtime fix collects all Console.Out setters and aggregates them into a single
* text writer.
*
* This allows to both fix the old problem with log overwriting and problem with writing stdout when console is
* enabled.
*/
internal static class ConsoleSetOutFix internal static class ConsoleSetOutFix
{ {
private static AggregatedTextWriter aggregatedTextWriter; private static LoggedTextWriter loggedTextWriter;
internal static ManualLogSource ConsoleLogSource = Logger.CreateLogSource("Console");
public static void Apply() public static void Apply()
{ {
aggregatedTextWriter = new AggregatedTextWriter(Console.Out); loggedTextWriter = new LoggedTextWriter { Parent = Console.Out };
Console.SetOut(aggregatedTextWriter); Console.SetOut(loggedTextWriter);
HarmonyLib.Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix)); HarmonyLib.Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix));
} }
@@ -31,39 +22,29 @@ namespace BepInEx.Preloader.RuntimeFixes
[HarmonyPrefix] [HarmonyPrefix]
private static bool OnSetOut(TextWriter newOut) private static bool OnSetOut(TextWriter newOut)
{ {
if (newOut == TextWriter.Null) loggedTextWriter.Parent = newOut;
return false;
aggregatedTextWriter.Add(newOut);
return false; return false;
} }
} }
internal class AggregatedTextWriter : TextWriter internal class LoggedTextWriter : TextWriter
{ {
public override Encoding Encoding { get; } = Encoding.UTF8; public override Encoding Encoding { get; } = Encoding.UTF8;
private List<TextWriter> writers = new List<TextWriter>(); public TextWriter Parent { get; set; }
public AggregatedTextWriter(params TextWriter[] initialWriters) public override void Flush() => Parent.Flush();
public override void Write(string value)
{ {
writers.AddRange(initialWriters.Where(w => w != null)); ConsoleSetOutFix.ConsoleLogSource.LogInfo(value);
Parent.Write(value);
} }
public void Add(TextWriter tw) public override void WriteLine(string value)
{ {
if (writers.Any(t => t == tw)) ConsoleSetOutFix.ConsoleLogSource.LogInfo(value);
return; Parent.WriteLine(value);
writers.Add(tw);
} }
public override void Flush() => writers.ForEach(w => w.Flush());
public override void Write(object value) => writers.ForEach(w => w.Write(value));
public override void Write(string value) => writers.ForEach(w => w.Write(value));
public override void Write(char value) => writers.ForEach(w => w.Write(value));
public override void WriteLine(object value) => writers.ForEach(w => w.WriteLine(value));
public override void WriteLine(string value) => writers.ForEach(w => w.WriteLine(value));
public override void WriteLine(char value) => writers.ForEach(w => w.WriteLine(value));
} }
} }
+1 -11
View File
@@ -86,9 +86,7 @@ namespace BepInEx.Bootstrap
// Add Unity log source only after replaying to prevent duplication in console // Add Unity log source only after replaying to prevent duplication in console
if (ConfigUnityLogging.Value) if (ConfigUnityLogging.Value)
Logger.Sources.Add(new UnityLogSource()); Logger.Sources.Add(new UnityLogSource());
// Write to Unity logs directly only if console is not present (or user explicitly wants to) Logger.Listeners.Add(new UnityLogListener());
if (ConfigWriteToUnityLog.Value || !ConsoleManager.ConsoleActive)
Logger.Listeners.Add(new UnityLogListener());
if (Utility.CurrentOs == Platform.Linux) if (Utility.CurrentOs == Platform.Linux)
{ {
@@ -415,14 +413,6 @@ namespace BepInEx.Bootstrap
true, true,
"Enables showing unity log messages in the BepInEx logging system."); "Enables showing unity log messages in the BepInEx logging system.");
private static readonly ConfigEntry<bool> ConfigWriteToUnityLog = ConfigFile.CoreConfig.Bind(
"Logging", "WriteToUnityLog",
false,
new StringBuilder()
.AppendLine("Enables writing log messages to Unity's log system")
.AppendLine("NOTE: By default, Unity already writes BepInEx console output to Unity logs")
.Append("Use this setting only if no BepInEx log messages are present in Unity's output_log").ToString());
private static readonly ConfigEntry<bool> ConfigDiskWriteUnityLog = ConfigFile.CoreConfig.Bind( private static readonly ConfigEntry<bool> ConfigDiskWriteUnityLog = ConfigFile.CoreConfig.Bind(
"Logging.Disk", "WriteUnityLog", "Logging.Disk", "WriteUnityLog",
false, false,
-17
View File
@@ -56,7 +56,6 @@ namespace BepInEx
throw new InvalidOperationException("Driver has not been initialized"); throw new InvalidOperationException("Driver has not been initialized");
} }
public static void CreateConsole() public static void CreateConsole()
{ {
if (ConsoleActive) if (ConsoleActive)
@@ -70,7 +69,6 @@ namespace BepInEx
var codepage = ConfigConsoleShiftJis.Value ? SHIFT_JIS_CP: (uint)Encoding.UTF8.CodePage; var codepage = ConfigConsoleShiftJis.Value ? SHIFT_JIS_CP: (uint)Encoding.UTF8.CodePage;
Driver.CreateConsole(codepage); Driver.CreateConsole(codepage);
SetConsoleStreams();
} }
public static void DetachConsole() public static void DetachConsole()
@@ -81,7 +79,6 @@ namespace BepInEx
DriverCheck(); DriverCheck();
Driver.DetachConsole(); Driver.DetachConsole();
SetConsoleStreams();
} }
public static void SetConsoleTitle(string title) public static void SetConsoleTitle(string title)
@@ -98,20 +95,6 @@ namespace BepInEx
Driver.SetConsoleColor(color); Driver.SetConsoleColor(color);
} }
internal static void SetConsoleStreams()
{
if (ConsoleActive)
{
Console.SetOut(ConsoleStream);
Console.SetError(ConsoleStream);
}
else
{
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
}
}
public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind( public static readonly ConfigEntry<bool> ConfigConsoleEnabled = ConfigFile.CoreConfig.Bind(
"Logging.Console", "Enabled", "Logging.Console", "Enabled",
false, false,
+1 -11
View File
@@ -14,20 +14,10 @@ namespace BepInEx.Logging
return; return;
ConsoleManager.SetConsoleColor(eventArgs.Level.GetConsoleColor()); ConsoleManager.SetConsoleColor(eventArgs.Level.GetConsoleColor());
Log(eventArgs); ConsoleManager.ConsoleStream?.Write(eventArgs.ToStringLine());
ConsoleManager.SetConsoleColor(ConsoleColor.Gray); ConsoleManager.SetConsoleColor(ConsoleColor.Gray);
} }
private void Log(LogEventArgs eventArgs)
{
// Special case: if message comes from Unity log, it's already logged by Unity, in which case
// we replay it only in the visible console
if (eventArgs.Source is UnityLogSource)
ConsoleManager.ConsoleStream?.Write(eventArgs.ToStringLine());
else
Console.Write(eventArgs.ToStringLine());
}
public void Dispose() { } public void Dispose() { }
private static readonly ConfigEntry<LogLevel> ConfigConsoleDisplayedLevel = ConfigFile.CoreConfig.Bind( private static readonly ConfigEntry<LogLevel> ConfigConsoleDisplayedLevel = ConfigFile.CoreConfig.Bind(
+12 -2
View File
@@ -1,6 +1,8 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using BepInEx.Configuration;
namespace BepInEx.Logging namespace BepInEx.Logging
{ {
@@ -36,11 +38,19 @@ namespace BepInEx.Logging
{ {
if (eventArgs.Source is UnityLogSource) if (eventArgs.Source is UnityLogSource)
return; return;
WriteStringToUnityLog?.Invoke(eventArgs.ToStringLine()); // Special case: don't write console twice since Unity can already do that
if (LogConsoleToUnity.Value || eventArgs.Source.SourceName != "Console")
WriteStringToUnityLog?.Invoke(eventArgs.ToStringLine());
} }
public void Dispose() { } public void Dispose() { }
private ConfigEntry<bool> LogConsoleToUnity = ConfigFile.CoreConfig.Bind("Logging",
"LogConsoleToUnityLog", false,
new StringBuilder()
.AppendLine("If enabled, writes Standard Output messages to Unity log")
.AppendLine("NOTE: By default, Unity does so automatically. Only use this option if no console messages are visible in Unity log").ToString());
} }
} }