Skip to content

Instantly share code, notes, and snippets.

@Ddemon26
Created September 26, 2024 07:23
Show Gist options
  • Save Ddemon26/d0ffaf758d3b06e197b4596a51fb5c98 to your computer and use it in GitHub Desktop.
Save Ddemon26/d0ffaf758d3b06e197b4596a51fb5c98 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
namespace TCS.TestSystems.Logging {
public static class GameLogger {
// Dictionary to hold Logger instances for each system, identified by Type
static readonly Dictionary<Type, Logger> Loggers = new();
// Central log storage
static readonly List<LogEntry> LogEntries = new();
// Maximum number of logs to store to prevent memory issues
const int MAX_LOG_ENTRIES = 100;
// Global flag to enable or disable all logging
static bool s_globalLoggingEnabled = true;
// Flag to allow runtime toggling of logs in development and runtime builds
static bool s_allowRuntimeToggling =
#if UNITY_EDITOR || DEVELOPMENT_BUILD
true;
#else
true; // Set to true if you want to allow runtime toggling in runtime builds
#endif
// Lock object for thread safety
static readonly object LockObj = new();
public static void Log(string message, Object context = null) {
var callerType = GetCallerType();
if (callerType == null) {
Debug.Log($"[Unknown] {message}", context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Log,
SystemName = "Unknown",
Message = message
});
return;
}
var logger = GetLogger(callerType);
logger.LogMessage(message, context);
}
public static void LogWarning(string message, Object context = null) {
var callerType = GetCallerType();
if (callerType == null) {
Debug.LogWarning($"[Unknown] {message}", context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Warning,
SystemName = "Unknown",
Message = message
});
return;
}
var logger = GetLogger(callerType);
logger.LogWarningMessage(message, context);
}
public static void LogError(string message, Object context = null) {
var callerType = GetCallerType();
if (callerType == null) {
Debug.LogError($"[Unknown] {message}", context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Error,
SystemName = "Unknown",
Message = message
});
return;
}
var logger = GetLogger(callerType);
logger.LogErrorMessage(message, context);
}
public static void SetGlobalLogging(bool enabled) {
lock (LockObj) {
s_globalLoggingEnabled = enabled;
}
}
public static void SetLoggingEnabled<T>(bool enabled) {
var systemType = typeof(T);
lock (LockObj) {
if (Loggers.TryGetValue(systemType, out var logger)) {
logger.IsEnabled = enabled;
}
else {
Loggers.Add(systemType, new Logger(systemType, enabled));
}
}
}
public static void SetColor<T>(Color color) {
var systemType = typeof(T);
lock (LockObj) {
if (Loggers.TryGetValue(systemType, out var logger)) {
logger.SetLogColor(color);
}
else {
Loggers.Add(systemType, new Logger(systemType, true, color));
}
}
}
public static void SetRuntimeToggling(bool allow) {
lock (LockObj) {
if (s_allowRuntimeToggling) {
s_allowRuntimeToggling = allow;
}
else {
Debug.LogWarning("Runtime toggling is disabled in this build.");
}
}
}
public static List<LogEntry> GetAllLogs() {
lock (LockObj) {
return new List<LogEntry>(LogEntries);
}
}
public static List<LogEntry> GetLogsByType(LogType type) {
lock (LockObj) {
return LogEntries.FindAll(entry => entry.Type == type);
}
}
public static void ClearLogs() {
lock (LockObj) {
LogEntries.Clear();
}
}
internal static void AddLogEntry(LogEntry entry) {
lock (LockObj) {
if (LogEntries.Count >= MAX_LOG_ENTRIES) {
LogEntries.RemoveAt(0); // Remove the oldest log to maintain the max size
}
LogEntries.Add(entry);
}
}
static Logger GetLogger(Type systemType) {
lock (LockObj) {
if (!Loggers.ContainsKey(systemType)) {
Loggers.Add(systemType, new Logger(systemType, true));
}
return Loggers[systemType];
}
}
static Type GetCallerType() {
try {
var stackTrace = new StackTrace();
// The frame at index 0 is this method, index 1 is the Log method, index 2 is the caller
if (stackTrace.FrameCount >= 3) {
var method = stackTrace.GetFrame(2).GetMethod();
return method.DeclaringType;
}
}
catch (Exception ex) {
Debug.LogError($"GameLogger: Failed to get caller type. Exception: {ex.Message}");
}
return null;
}
class Logger {
public Type SystemType { get; }
public bool IsEnabled { get; set; }
Color LogColor { get; set; }
internal Logger(Type systemType, bool isEnabled, Color? logColor = null) {
SystemType = systemType;
IsEnabled = isEnabled;
LogColor = logColor ?? Color.white; // Default to white if no color is provided
}
public void SetLogColor(Color color) {
LogColor = color;
}
public void LogMessage(string message, Object context = null) {
if (ShouldLog()) {
string coloredName = $"[{SystemType.Name}]".RichColor(LogColor);
var formattedMessage = $"{coloredName} {message}";
Debug.Log(formattedMessage, context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Log,
SystemName = SystemType.Name,
Message = message
});
}
}
public void LogWarningMessage(string message, Object context = null) {
if (ShouldLog()) {
string coloredName = $"[{SystemType.Name}]".RichColor(LogColor);
var formattedMessage = $"{coloredName} {message}";
Debug.LogWarning(formattedMessage, context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Warning,
SystemName = SystemType.Name,
Message = message
});
}
}
public void LogErrorMessage(string message, Object context = null) {
if (ShouldLog()) {
string coloredName = $"[{SystemType.Name}]".RichColor(LogColor);
var formattedMessage = $"{coloredName} {message}";
Debug.LogError(formattedMessage, context);
AddLogEntry(new LogEntry {
Timestamp = DateTime.Now,
Type = LogType.Error,
SystemName = SystemType.Name,
Message = message
});
}
}
bool ShouldLog() {
return s_globalLoggingEnabled && IsEnabled;
}
}
public class LogEntry {
public DateTime Timestamp { get; set; }
public LogType Type { get; set; }
public string SystemName { get; set; }
public string Message { get; set; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment