203 lines
7.5 KiB
C#
203 lines
7.5 KiB
C#
//using Meryel.UnityCodeAssist.Serilog;
|
|
//using Meryel.UnityCodeAssist.Serilog.Core;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.Linq;
|
|
|
|
#if ELOGGER
|
|
|
|
#pragma warning disable IDE0005
|
|
using Serilog = Meryel.Serilog;
|
|
#pragma warning restore IDE0005
|
|
|
|
|
|
#nullable enable
|
|
|
|
|
|
namespace Meryel.UnityCodeAssist.Editor.Logger
|
|
{
|
|
|
|
//[InitializeOnLoad]
|
|
public static class ELogger
|
|
{
|
|
public static event System.Action? OnVsInternalLogChanged;
|
|
|
|
|
|
// Change 'new LoggerConfiguration().MinimumLevel.Debug();' if you change these values
|
|
const Serilog.Events.LogEventLevel fileMinLevel = Serilog.Events.LogEventLevel.Debug;
|
|
const Serilog.Events.LogEventLevel outputWindowMinLevel = Serilog.Events.LogEventLevel.Information;
|
|
static LoggingLevelSwitch? fileLevelSwitch, outputWindowLevelSwitch;
|
|
|
|
//static bool IsInitialized { get; set; }
|
|
|
|
static ILogEventSink? _outputWindowSink;
|
|
static ILogEventSink? _memorySink;
|
|
|
|
|
|
public static string GetInternalLogContent() => _memorySink == null ? string.Empty : ((MemorySink)_memorySink).Export();
|
|
public static int GetErrorCountInInternalLog() => _memorySink == null ? 0 : ((MemorySink)_memorySink).ErrorCount;
|
|
public static int GetWarningCountInInternalLog() => _memorySink == null ? 0 : ((MemorySink)_memorySink).WarningCount;
|
|
|
|
public static string? FilePath { get; private set; }
|
|
public static string? VSFilePath { get; private set; }
|
|
|
|
//**-- make it work with multiple clients
|
|
static string? _vsInternalLog;
|
|
public static string? VsInternalLog
|
|
{
|
|
get => _vsInternalLog;
|
|
set
|
|
{
|
|
_vsInternalLog = value;
|
|
OnVsInternalLogChanged?.Invoke();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static ELogger()
|
|
{
|
|
var isFirst = false;
|
|
const string stateName = "isFirst";
|
|
if (!SessionState.GetBool(stateName, false))
|
|
{
|
|
isFirst = true;
|
|
SessionState.SetBool(stateName, true);
|
|
}
|
|
|
|
var projectPath = CommonTools.GetProjectPath();
|
|
var outputWindowSink = new System.Lazy<ILogEventSink>(() => new UnityOutputWindowSink(null));
|
|
|
|
Init(isFirst, projectPath, outputWindowSink);
|
|
|
|
if (isFirst)
|
|
LogHeader(Application.unityVersion, projectPath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Empty method for invoking static class ctor
|
|
/// </summary>
|
|
public static void Bump() { }
|
|
|
|
|
|
static void LogHeader(string unityVersion, string solutionDir)
|
|
{
|
|
var os = System.Runtime.InteropServices.RuntimeInformation.OSDescription;
|
|
var assisterVersion = Assister.Version;
|
|
var syncModel = Synchronizer.Model.Utilities.Version;
|
|
var hash = CommonTools.GetHashForLogFile(solutionDir);
|
|
var port = Synchronizer.Model.Utilities.GetPortForMQTTnet(solutionDir);
|
|
Serilog.Log.Debug(
|
|
"Beginning logging {OS}, Unity {U}, Unity Code Assist {A}, Communication Protocol {SM}, Project: '{Dir}', Project Hash: {Hash}, Port: {Port}",
|
|
os, unityVersion, assisterVersion, syncModel, solutionDir, hash, port);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static string GetFilePath(string solutionDir)
|
|
{
|
|
var solutionHash = CommonTools.GetHashForLogFile(solutionDir);
|
|
var tempDir = System.IO.Path.GetTempPath();
|
|
var fileName = $"UnityCodeAssist_U_Log_{solutionHash}_.TXT"; // hour code will be appended to the end of file, so add a trailing '_'
|
|
var filePath = System.IO.Path.Combine(tempDir, fileName);
|
|
return filePath;
|
|
}
|
|
|
|
static string GetVSFilePath(string solutionDir)
|
|
{
|
|
var solutionHash = CommonTools.GetHashForLogFile(solutionDir);
|
|
var tempDir = System.IO.Path.GetTempPath();
|
|
#if MERYEL_UCA_LITE_VERSION
|
|
var fileName = $"UnityCodeAssistLite_VS_Log_{solutionHash}_.TXT"; // hour code will be appended to the end of file, so add a trailing '_'
|
|
#else
|
|
var fileName = $"UnityCodeAssist_VS_Log_{solutionHash}_.TXT"; // hour code will be appended to the end of file, so add a trailing '_'
|
|
#endif
|
|
var filePath = System.IO.Path.Combine(tempDir, fileName);
|
|
return filePath;
|
|
}
|
|
|
|
|
|
public static void Init(bool isFirst, string solutionDir, System.Lazy<ILogEventSink> outputWindowSink)
|
|
{
|
|
|
|
FilePath = GetFilePath(solutionDir);
|
|
VSFilePath = GetVSFilePath(solutionDir);
|
|
|
|
fileLevelSwitch = new LoggingLevelSwitch(fileMinLevel);
|
|
outputWindowLevelSwitch = new LoggingLevelSwitch(outputWindowMinLevel);
|
|
|
|
var config = new LoggerConfiguration()
|
|
.MinimumLevel.Debug()
|
|
.Enrich.With(new DomainHashEnricher());
|
|
|
|
const string outputTemplate = "{Timestamp:HH:mm:ss.fff} [U] [{Level:u3}] [{DomainHash}] {Message:lj}{NewLine}{Exception}";
|
|
|
|
config = config.WriteTo.PersistentFile(FilePath
|
|
, outputTemplate: outputTemplate
|
|
, shared: true
|
|
, persistentFileRollingInterval: PersistentFileRollingInterval.Day
|
|
, preserveLogFilename: true
|
|
, levelSwitch: fileLevelSwitch
|
|
, rollOnEachProcessRun: isFirst
|
|
);
|
|
|
|
_outputWindowSink ??= outputWindowSink.Value;
|
|
if (_outputWindowSink != null)
|
|
config = config.WriteTo.Sink(_outputWindowSink, outputWindowMinLevel, outputWindowLevelSwitch);
|
|
|
|
_memorySink ??= new MemorySink(outputTemplate);
|
|
config = config.WriteTo.Sink(_memorySink, fileMinLevel, null);
|
|
|
|
config = config.Destructure.With(new MyDestructuringPolicy());
|
|
|
|
Serilog.Log.Logger = config.CreateLogger();
|
|
//switchableLogger.Set(config.CreateLogger(), disposePrev: true);
|
|
|
|
OnOptionsChanged();
|
|
|
|
//IsInitialized = true;
|
|
}
|
|
|
|
public static void OnOptionsChanged()
|
|
{
|
|
// Since we don't use LogEventLevel.Fatal, we can use it for disabling sinks
|
|
|
|
var isLoggingToFile = OptionsIsLoggingToFile;
|
|
var targetFileLevel = isLoggingToFile ? fileMinLevel : Serilog.Events.LogEventLevel.Fatal;
|
|
if (fileLevelSwitch != null)
|
|
fileLevelSwitch.MinimumLevel = targetFileLevel;
|
|
|
|
var isLoggingToOutputWindow = OptionsIsLoggingToOutputWindow;
|
|
var targetOutputWindowLevel = isLoggingToOutputWindow ? outputWindowMinLevel : Serilog.Events.LogEventLevel.Fatal;
|
|
if (outputWindowLevelSwitch != null)
|
|
outputWindowLevelSwitch.MinimumLevel = targetOutputWindowLevel;
|
|
}
|
|
|
|
//**-- UI for these two
|
|
static bool OptionsIsLoggingToFile => true;
|
|
static bool OptionsIsLoggingToOutputWindow => true;
|
|
}
|
|
|
|
public class MyDestructuringPolicy : IDestructuringPolicy
|
|
{
|
|
// serilog cannot destruct StringArrayContainer by default, so do it manually
|
|
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out Serilog.Events.LogEventPropertyValue? result)
|
|
{
|
|
if (value is Synchronizer.Model.StringArrayContainer sac)
|
|
{
|
|
var items = sac.Container.Select(item => propertyValueFactory.CreatePropertyValue(item, true));
|
|
result = new Serilog.Events.SequenceValue(items);
|
|
return true;
|
|
}
|
|
|
|
result = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif |