mirror of
https://github.com/BepInEx/BepInEx.git
synced 2026-10-20 01:46:13 +00:00
Simplify ConsoleSetOut fix; redirect console messages to logging system
This commit is contained in:
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user