Skip to content

Commit

Permalink
feat: adding log handler that adds label and color to messages
Browse files Browse the repository at this point in the history
only set via code so far, will add gui to log settings to automatically add later
  • Loading branch information
James-Frowen committed May 24, 2023
1 parent e73c9d5 commit bb26471
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 9 deletions.
32 changes: 24 additions & 8 deletions Assets/Mirage/Runtime/Logging/LogFactory.cs
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
Expand All @@ -13,7 +14,7 @@ public static class LogFactory
/// <summary>
/// logHandler used for new loggers
/// </summary>
private static ILogHandler defaultLogHandler = Debug.unityLogger;
private static Func<string, ILogHandler> createLoggerForType = _ => Debug.unityLogger;

public static ILogger GetLogger<T>(LogType defaultLogLevel = LogType.Warning)
{
Expand All @@ -37,7 +38,7 @@ public static ILogger GetLogger(string loggerName, LogType defaultLogLevel = Log

private static ILogger CreateNewLogger(string loggerName, LogType defaultLogLevel)
{
var logger = new Logger(defaultLogHandler)
var logger = new Logger(createLoggerForType.Invoke(loggerName))
{
// by default, log warnings and up
filterLogType = defaultLogLevel
Expand All @@ -48,21 +49,36 @@ private static ILogger CreateNewLogger(string loggerName, LogType defaultLogLeve
}

/// <summary>
/// Replacing log handler for all existing loggers and sets defaultLogHandler for new loggers
/// Replacing log handlers for loggers, with the option to replace for exisitng or just new loggers
/// </summary>
/// <param name="logHandler"></param>
public static void ReplaceLogHandler(ILogHandler logHandler)
public static void ReplaceLogHandler(ILogHandler logHandler, bool replaceExisting = true)
{
defaultLogHandler = logHandler;
ReplaceLogHandler(_ => logHandler, replaceExisting);
}

/// <summary>
/// Replaceing log handlers for loggers, allows for unique log handlers for each type
/// <para>this can be used to add labels or other processing before logging the result</para>
/// </summary>
/// <param name="createHandler"></param>
/// <param name="replaceExisting"></param>
public static void ReplaceLogHandler(Func<string, ILogHandler> createHandler, bool replaceExisting = true)
{
createLoggerForType = createHandler;

foreach (var logger in _loggers.Values)
if (replaceExisting)
{
logger.logHandler = logHandler;
foreach (var kvp in _loggers)
{
var logger = kvp.Value;
var key = kvp.Key;
logger.logHandler = createLoggerForType.Invoke(key);
}
}
}
}


public static class ILoggerExtensions
{
public static void LogError(this ILogger logger, object message)
Expand Down
2 changes: 1 addition & 1 deletion Assets/Mirage/Runtime/Logging/LogSettingsSO.cs
Expand Up @@ -55,7 +55,7 @@ public LoggerSettings(string fullname, LogType level)
_fullNameCache = CreateFullName(Name, Namespace);
}

private static (string name, string @namespace) GetNameAndNameSpaceFromFullname(string fullname)
public static (string name, string @namespace) GetNameAndNameSpaceFromFullname(string fullname)
{
// NOTE we need to be able to recreate fullname from name/namespace
// so we cant always just use empty string for no namespace
Expand Down
133 changes: 133 additions & 0 deletions Assets/Mirage/Runtime/Logging/MirageLogHandler.cs
@@ -0,0 +1,133 @@
using System;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace Mirage.Logging
{
/// <summary>
/// Log handler that adds prefixes to logging
/// </summary>
public class MirageLogHandler : ILogHandler
{
private readonly Settings _settings;
private readonly ILogHandler _inner;
private readonly string _label;

public MirageLogHandler(Settings settings, string fullTypeName = null, ILogHandler inner = null)
{
_inner = inner ?? Debug.unityLogger;
_settings = settings;

if (_settings.Label && !string.IsNullOrEmpty(fullTypeName))
{
var (name, _) = LogSettingsSO.LoggerSettings.GetNameAndNameSpaceFromFullname(fullTypeName);
_label = $"[{name}]";

if (_settings.ColoredLabel)
{
_label = _settings.AllowColorToLabel(fullTypeName, _label);
}
}
else
{
_label = null;
}
}

public void LogException(Exception exception, UnityEngine.Object context)
{
_inner.LogException(exception, context);
}

public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
{
// add label before frame nummber
if (!string.IsNullOrEmpty(_label))
{
format = $"{_label} {format}";
}

format = AddTimePrefix(format);

_inner.LogFormat(logType, context, format, args);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private string AddTimePrefix(string format)
{
string timePrefix;
switch (_settings.TimePrefix)
{
default:
return format;
case TimePrefix.FrameCount:
try
{
// need try/catch for unity function because unity can throw if called from side thread
timePrefix = Time.frameCount.ToString();
}
catch
{
timePrefix = "0";
}
break;
case TimePrefix.DateTimeMilliSeconds:
timePrefix = DateTime.Now.ToString("HH:mm:ss.fff");
break;
case TimePrefix.DateTimeSeconds:
timePrefix = DateTime.Now.ToString("HH:mm:ss");
break;
}

return $"{timePrefix}: {format}";
}

public enum TimePrefix
{
None,
FrameCount,
DateTimeMilliSeconds,
DateTimeSeconds,
}
[Serializable]
public class Settings
{
public TimePrefix TimePrefix;
public readonly bool ColoredLabel;
public readonly bool Label;

/// <summary>
/// Used to change the colors of names
/// <para>number is multiple by hash unchecked, so small changes to seed will cause large changes in result</para>
/// <para>403 seems like a good starting seed, common class like NetworkServer and NetworkClient have different colors</para>
/// </summary>
public int ColorSeed = 403;
public float ColorSaturation = 0.6f;
public float ColorValue = 0.8f;

public Settings(TimePrefix timePrefix, bool coloredLabel, bool label)
{
TimePrefix = timePrefix;
ColoredLabel = coloredLabel;
Label = label;
}

public string AllowColorToLabel(string fullname, string label)
{
var color = ColorFromName(fullname);
var colorHex = ColorUtility.ToHtmlStringRGB(color);
return $"<color=#{colorHex}>{label}</color>";
}

public Color ColorFromName(string fullName)
{
var hash = fullName.GetStableHashCode();
if (ColorSeed != 0)
hash = unchecked(ColorSeed * hash);

var hue = Mathf.Abs((float)hash / (float)int.MaxValue);
return Color.HSVToRGB(hue, ColorSaturation, ColorValue);
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/Mirage/Runtime/Logging/MirageLogHandler.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bb26471

Please sign in to comment.