From 293fa8d90cde9b9c20507bf752a3ddbc70d60f53 Mon Sep 17 00:00:00 2001 From: Cj Date: Sat, 16 Mar 2024 21:04:00 +0000 Subject: [PATCH] Enable BSG logging (!96) Needs merged with: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/262 Short story first: Last night I was poking around the code as I always do looking for the cause of an exception and got sick and tired of the generic bad exceptions we always work off of. So I fixed it. This allows us access to BSG's internal logging using Nlog. This is useful for everybody. Not just SPT dev's, but mod dev's alike. It can be enabled from `core.json` with the option to send the output to the server. Here's an example of the improvement, its huge. Bepinex console is the gerneric logging we always use, the editor behind it is the improved logging from Nlog. Its night and day. ![image](/attachments/491dd8b6-e89a-4809-b19e-c5906ab6989e) The levels are based off of Nlog ordinals where low is more logging, high is less. (Stupid I know, but what can you do) Verbosity is as follows: * In all cases, except off, better exceptions will be logged. * to see the logging output in your bepinex logs, make sure you have debug logging enabled in bepinex. * WARNING: trace-info logging will quickly create log files in the megabytes. * 0 - trace * 1 - debug * 2 - info * 3 - warn * 4 - error * 5 - fatal * 6 - off Co-authored-by: Cj <161484149+CJ-SPT@users.noreply.github.com> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Modules/pulls/96 Co-authored-by: Cj Co-committed-by: Cj --- .../Aki.Custom/Models/BsgLoggingResponse.cs | 5 ++ project/Aki.Debugging/Aki.Debugging.csproj | 1 + project/Aki.Debugging/AkiDebuggingPlugin.cs | 11 ++++ .../Aki.Debugging/Patches/LoggerClassPatch.cs | 54 +++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 project/Aki.Custom/Models/BsgLoggingResponse.cs create mode 100644 project/Aki.Debugging/Patches/LoggerClassPatch.cs diff --git a/project/Aki.Custom/Models/BsgLoggingResponse.cs b/project/Aki.Custom/Models/BsgLoggingResponse.cs new file mode 100644 index 0000000..5c3fab9 --- /dev/null +++ b/project/Aki.Custom/Models/BsgLoggingResponse.cs @@ -0,0 +1,5 @@ +public struct LoggingLevelResponse +{ + public int verbosity { get; set; } + public bool sendToServer {get; set; } +} \ No newline at end of file diff --git a/project/Aki.Debugging/Aki.Debugging.csproj b/project/Aki.Debugging/Aki.Debugging.csproj index ae60ee6..e6b446e 100644 --- a/project/Aki.Debugging/Aki.Debugging.csproj +++ b/project/Aki.Debugging/Aki.Debugging.csproj @@ -24,6 +24,7 @@ + diff --git a/project/Aki.Debugging/AkiDebuggingPlugin.cs b/project/Aki.Debugging/AkiDebuggingPlugin.cs index f4c9876..1258d7b 100644 --- a/project/Aki.Debugging/AkiDebuggingPlugin.cs +++ b/project/Aki.Debugging/AkiDebuggingPlugin.cs @@ -1,5 +1,7 @@ using System; using Aki.Common; +using Aki.Common.Http; +using Aki.Common.Utils; using Aki.Debugging.Patches; using BepInEx; @@ -8,6 +10,8 @@ namespace Aki.Debugging [BepInPlugin("com.spt-aki.debugging", "AKI.Debugging", AkiPluginInfo.PLUGIN_VERSION)] public class AkiDebuggingPlugin : BaseUnityPlugin { + public static LoggingLevelResponse logLevel; + public void Awake() { Logger.LogInfo("Loading: Aki.Debugging"); @@ -15,6 +19,7 @@ namespace Aki.Debugging try { new EndRaidDebug().Enable(); + new LoggerClassLogPatch().Enable(); // new CoordinatesPatch().Enable(); // new StaticLootDumper().Enable(); @@ -32,5 +37,11 @@ namespace Aki.Debugging Logger.LogInfo("Completed: Aki.Debugging"); } + + public void Start() + { + var loggingJson = RequestHandler.GetJson("/singleplayer/enableBSGlogging"); + logLevel = Json.Deserialize(loggingJson); + } } } diff --git a/project/Aki.Debugging/Patches/LoggerClassPatch.cs b/project/Aki.Debugging/Patches/LoggerClassPatch.cs new file mode 100644 index 0000000..6ec94c8 --- /dev/null +++ b/project/Aki.Debugging/Patches/LoggerClassPatch.cs @@ -0,0 +1,54 @@ +using System.Reflection; +using System.Text.RegularExpressions; +using Aki.Common.Utils; +using Aki.Reflection.Patching; +using Aki.Reflection.Utils; +using HarmonyLib; +using NLog; + +namespace Aki.Debugging.Patches +{ + public class LoggerClassLogPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.GetDeclaredMethods(typeof(LoggerClass)) + .SingleCustom(m => m.Name == nameof(LoggerClass.Log) && m.GetParameters().Length == 4); + } + + [PatchPostfix] + private static void PatchPostfix(string nlogFormat, string unityFormat, LogLevel logLevel, object[] args) + { + var bsgLevel = LogLevel.FromOrdinal(logLevel.Ordinal); + var sptLevel = LogLevel.FromOrdinal(AkiDebuggingPlugin.logLevel.verbosity); + + // See Nlog docs for information on ordinal levels + // Ordinal works from low to high 0 - trace, 1 - debug, 3 - info ... + if (bsgLevel >= sptLevel) + { + // We want to remove any character thats not a single digit inside of {} + // This prevents string builder exceptions. + nlogFormat = Regex.Replace(nlogFormat, @"\{[^{}]*[^\d{}][^{}]*\}", ""); + nlogFormat = string.Format(nlogFormat, args); + + Logger.LogDebug($"output Nlog: {logLevel} : {nlogFormat}"); + + if (AkiDebuggingPlugin.logLevel.sendToServer) + { + ServerLog.Info("EFT Logging:", $"{logLevel} : {nlogFormat}"); + } + } + + // I've opted to leave this disabled for now, it doesn't add much in + // terms of value, its mostly the same stuff as the nlogFormat + // Deciced to keep it here incase we decide we want it later. + // After a 5 minute factory run at full verbosity, i ended up with a 20K + // line long player.log file. + + //unityFormat = Regex.Replace(unityFormat, @"\{[^{}]*[^\d{}][^{}]*\}", ""); + //unityFormat = string.Format(unityFormat, args); + //Logger.LogDebug($"Verbosity: {logLevel}"); + //Logger.LogDebug($"output unity: {unityFormat}"); + } + } +} \ No newline at end of file