diff --git a/.UniLogger/Packages/manifest.json b/.UniLogger/Packages/manifest.json index d41af7f..82a0dd7 100644 --- a/.UniLogger/Packages/manifest.json +++ b/.UniLogger/Packages/manifest.json @@ -5,7 +5,7 @@ "com.boundfoxstudios.fluentassertions": "6.8.0", "com.dbrizov.naughtyattributes": "2.1.4", "com.unity.2d.sprite": "1.0.0", - "com.unity.ide.rider": "3.0.25", + "com.unity.ide.rider": "3.0.26", "com.unity.mobile.android-logcat": "1.3.2", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", diff --git a/.UniLogger/Packages/packages-lock.json b/.UniLogger/Packages/packages-lock.json index 8c422e4..bfe4b96 100644 --- a/.UniLogger/Packages/packages-lock.json +++ b/.UniLogger/Packages/packages-lock.json @@ -34,7 +34,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.25", + "version": "3.0.26", "depth": 0, "source": "registry", "dependencies": { diff --git a/Runtime/Services/Target.cs b/Runtime/Services/Target.cs index 4a6759c..a503cd4 100644 --- a/Runtime/Services/Target.cs +++ b/Runtime/Services/Target.cs @@ -3,25 +3,35 @@ namespace UnityEngine { - public abstract class Target + public abstract class TargetBase { - private readonly bool[] _stackTraceLogType; - [NotNull] public Formatter Formatter { get; } [NotNull] public Filterer Filterer { get; } - protected Target() : this(null, null) + protected TargetBase() : this(null, null) { } - protected Target([CanBeNull] Formatter formatter = null, [CanBeNull] Filterer filterer = null) + protected TargetBase([CanBeNull] Formatter formatter = null, [CanBeNull] Filterer filterer = null) { Formatter = formatter ?? new Formatter(); Filterer = filterer ?? new Filterer(true); + } + } + public abstract class Target : TargetBase + { + private readonly bool[] _stackTraceLogType; + + protected Target() : this(null, null) + { + } + + protected Target([CanBeNull] Formatter formatter = null, [CanBeNull] Filterer filterer = null) : base(formatter, filterer) + { _stackTraceLogType = new bool[LogTypes.Count]; foreach (var logType in LogTypes) { @@ -29,10 +39,9 @@ protected Target([CanBeNull] Formatter formatter = null, [CanBeNull] Filterer fi } } - public Target SetStackTraceEnabled(LogLevel logLevel, bool enabled) + public void SetStackTraceEnabled(LogLevel logLevel, bool enabled) { _stackTraceLogType[(int)logLevel] = enabled; - return this; } public bool GetStackTraceEnabled(LogLevel logLevel) @@ -40,9 +49,9 @@ public bool GetStackTraceEnabled(LogLevel logLevel) return _stackTraceLogType[(int)logLevel]; } - public abstract void Log(string message, [CanBeNull] string stackTrace); + protected internal abstract void Log(string message, [CanBeNull] string stackTrace); - public virtual void Flush() + protected internal virtual void Flush() { } } diff --git a/Runtime/Targets.meta b/Runtime/Targets.meta new file mode 100644 index 0000000..110c053 --- /dev/null +++ b/Runtime/Targets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c784b3496c414364a839ed5ae583244c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Targets/UnityTarget.cs b/Runtime/Targets/UnityTarget.cs new file mode 100644 index 0000000..cc823f4 --- /dev/null +++ b/Runtime/Targets/UnityTarget.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; + +namespace UnityEngine +{ + public class UnityTarget : TargetBase + { + internal UnityTarget([NotNull] Formatter formatter, [NotNull] Filterer filterer) : base(formatter, filterer) + { + } + } +} \ No newline at end of file diff --git a/Runtime/Targets/UnityTarget.cs.meta b/Runtime/Targets/UnityTarget.cs.meta new file mode 100644 index 0000000..95457c4 --- /dev/null +++ b/Runtime/Targets/UnityTarget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 123bd9e1be16d8f4cbbcbd7c6ba7ad34 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ULogger.Static.cs b/Runtime/ULogger.Static.cs index e420cbf..75bee14 100644 --- a/Runtime/ULogger.Static.cs +++ b/Runtime/ULogger.Static.cs @@ -35,17 +35,36 @@ public partial class ULogger [CanBeNull] private static ULoggerData Data { get; set; } - - [CanBeNull] - public static List Targets => Data?.Targets; + + public static IEnumerable GetTargets() + { + if (Data == null) yield break; + yield return Data.UnityTarget; + foreach (var target in Data.Targets) + { + yield return target; + } + } + + public static T GetTarget() where T : TargetBase + { + if (Data == null) return null; + if (Data.UnityTarget is T unityTarget) + { + return unityTarget; + } + return Data.Targets.First(c => c is T) as T; + } public static void Initialize(Formatter unityFormatter = null, Filterer unityFilterer = null) { // prepare default loggers and swap unity logger to custom + unityFormatter ??= new Formatter(); + unityFilterer ??= new Filterer(true); + var unityTarget = new UnityTarget(unityFormatter, unityFilterer); Data = new ULoggerData { - UnityFormatter = unityFormatter ?? new Formatter(), - UnityFilterer = unityFilterer ?? new Filterer(true), + UnityTarget = unityTarget, LogHandler = new UnityLogger(Debug.unityLogger.logHandler), }; Debug.unityLogger.logHandler = Data.LogHandler; diff --git a/Runtime/ULogger.cs b/Runtime/ULogger.cs index a979f14..74a1f2f 100644 --- a/Runtime/ULogger.cs +++ b/Runtime/ULogger.cs @@ -21,14 +21,15 @@ internal void SendLogToUnity(LogLevel logLevel, string message, Color color, Obj } // means it is possible to send log to Unity, catch using Application.logMessageReceivedThreaded and broadcast to other targets - if (WillBeAllowedByFilterer(Data.UnityFilterer, logLevel, _tags)) + if (WillBeAllowedByFilterer(Data.UnityTarget.Filterer, logLevel, _tags)) { - var line = new LogEntry(_tags.Where(c => Data.UnityFilterer.IsAllowed(logLevel, c)), logLevel, message, color, context); - var formattedMessage = Data.UnityFormatter.Format(line); + var line = new LogEntry(_tags.Where(c => Data.UnityTarget.Filterer.IsAllowed(logLevel, c)), logLevel, message, color, context); + var formattedMessage = Data.UnityTarget.Formatter.Format(line); - // manually extract stack trace if stack it disabled by unity but some target needs it + // manually extract stack trace if stack it disabled by unity (or we are in separate thread) but some target needs it var manualStacktrace = string.Empty; - if (Application.GetStackTraceLogType(logLevel.ConvertToLogType()) == StackTraceLogType.None && + if (!ThreadDispatcher.IsMainThread || + Application.GetStackTraceLogType(logLevel.ConvertToLogType()) == StackTraceLogType.None && Data.Targets.Any(c => WillBeAllowedByFilterer(c.Filterer, logLevel, _tags) && c.GetStackTraceEnabled(logLevel))) { manualStacktrace = StackTraceUtility.ExtractStackTrace(); diff --git a/Runtime/ULoggerData.cs b/Runtime/ULoggerData.cs index 3171254..2c30fbb 100644 --- a/Runtime/ULoggerData.cs +++ b/Runtime/ULoggerData.cs @@ -4,9 +4,8 @@ namespace UnityEngine { internal class ULoggerData { - public List Targets { get; } = new List(); - public Formatter UnityFormatter { get; set; } - public Filterer UnityFilterer { get; set; } - public UnityLogger LogHandler { get; set; } + public List Targets { get; } = new(); + public UnityTarget UnityTarget { get; init; } + public UnityLogger LogHandler { get; init; } } } \ No newline at end of file diff --git a/Runtime/Utilities/IsExternalInit.cs b/Runtime/Utilities/IsExternalInit.cs new file mode 100644 index 0000000..c9b67dd --- /dev/null +++ b/Runtime/Utilities/IsExternalInit.cs @@ -0,0 +1,9 @@ +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices +{ + // this is needed to enable the record feature in .NET framework and .NET core <= 3.1 projects + // ReSharper disable once UnusedType.Global + internal static class IsExternalInit + { + } +} \ No newline at end of file diff --git a/Runtime/Utilities/IsExternalInit.cs.meta b/Runtime/Utilities/IsExternalInit.cs.meta new file mode 100644 index 0000000..6e3b2ae --- /dev/null +++ b/Runtime/Utilities/IsExternalInit.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b2800417d54f494d8d73b0e8dea9735c +timeCreated: 1695472656 \ No newline at end of file diff --git a/Runtime/Utilities/ThreadDispatcher.cs b/Runtime/Utilities/ThreadDispatcher.cs new file mode 100644 index 0000000..80bce7f --- /dev/null +++ b/Runtime/Utilities/ThreadDispatcher.cs @@ -0,0 +1,17 @@ +using System.Threading; + +namespace UnityEngine +{ + internal static class ThreadDispatcher + { + public static Thread MainThread { get; private set; } + + public static bool IsMainThread => MainThread != null && MainThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void AutoConfigureLogger() + { + MainThread = Thread.CurrentThread; + } + } +} \ No newline at end of file diff --git a/Runtime/Utilities/ThreadDispatcher.cs.meta b/Runtime/Utilities/ThreadDispatcher.cs.meta new file mode 100644 index 0000000..ad8c770 --- /dev/null +++ b/Runtime/Utilities/ThreadDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1dea6fdfc3db451cabc8a5b54a6b9907 +timeCreated: 1701124788 \ No newline at end of file