Files
chess_game/Scripts/Logger.cs

176 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Godot;
using System;
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// 仿照 Python logging 的 日志系统
/// </summary>
public static class Logging {
// ========== 日志级别 ==========
public enum Level {
NOSET = 0,
DEBUG = 10,
INFO = 20,
WARNING = 30,
ERROR = 40,
CRITICAL = 50
}
/// <summary>
/// 日志记录器
/// </summary>
public class Logger(string name) {
public string Name { get; } = name;
public Level LogLevel { get; set; } = Level.INFO;
private readonly List<Action<Level, string, string, string>> _handlers = [];
public void AddHandler(Action<Level, string, string, string> handler) =>
_handlers.Add(handler);
// ===== 日志方法 =====
public void Debug(string fmt, params object[] args) =>
Log(Level.DEBUG, fmt, false, args);
public void Info(string fmt, params object[] args) =>
Log(Level.INFO, fmt, false, args);
public void Warning(string fmt, params object[] args) =>
Log(Level.WARNING, fmt, false, args);
public void Error(string fmt, params object[] args) =>
Log(Level.ERROR, fmt, false, args);
public void Critical(string fmt, params object[] args) =>
Log(Level.CRITICAL, fmt, true, args);
public void Exception(string fmt, Exception e, params object[] args) {
// TODO for godot not support /r/n yet
string stackTrace = e.StackTrace?.Replace("\r\n", "\n") ?? "";
string exceptionMessage = $"{fmt}\n{e.Message}\n{stackTrace}";
Log(Level.ERROR, exceptionMessage, false, args);
}
// ===== 核心Log方法 =====
private void Log(Level level, string fmt, bool isExec = false, params object[] args) {
if (level < LogLevel) return;
// 格式化消息
string message = args.Length > 0 ?
string.Format(fmt, args) : fmt;
// 添加执行堆栈信息
string stackInfo = isExec ?
$"\nExecution Stack:\n{System.Environment.StackTrace}" : "";
// 构建前缀
string prefix = $"[{DateTime.Now:HH:mm:ss}] [{level}] [{Name}]";
// 调用所有处理器
foreach (var handler in _handlers) {
handler(level, prefix, message, stackInfo);
}
}
[Conditional("DEBUG")]
public void Assert(bool condition, string fmt, params object[] args) {
if (condition) return;
string message = args.Length > 0 ?
string.Format(fmt, args) : fmt;
Error("Assertion Failed: " + message, true);
if (Debugger.IsAttached)
Debugger.Break();
System.Diagnostics.Debug.Assert(condition, message);
}
}
// ========== 全局管理器 ==========
private static readonly Dictionary<string, Logger> _loggers = [];
private static readonly Logger _root = GetLogger("root");
/// <summary>
/// 获取或创建日志记录器
/// </summary>
public static Logger GetLogger(string name = "root") {
if (!_loggers.TryGetValue(name, out var logger)) {
logger = new Logger(name);
logger.AddHandler(DefaultHandler);
_loggers[name] = logger;
}
return logger;
}
// ========== 优化的默认处理器 ==========
private static void DefaultHandler(Level level, string prefix, string message, string stackInfo) {
// 构建完整日志消息
string fullMessage = $"{prefix} {message}{stackInfo}";
switch (level) {
case Level.DEBUG:
// DEBUG级别使用GD.Print + OS条件
if (OS.IsStdOutVerbose())
GD.Print(fullMessage);
break;
case Level.INFO:
// INFO级别使用GD.Print
GD.Print(fullMessage);
break;
case Level.WARNING:
// WARNING级别使用PrintRich + 黄色
GD.PrintRich($"[color=yellow]{fullMessage}[/color]");
break;
case Level.ERROR:
// ERROR级别使用GD.PrintErr
GD.PrintRich($"[color=red][b]{fullMessage}[/b][/color]");
// GD.PrintErr(fullMessage);
break;
case Level.CRITICAL:
// CRITICAL级别使用GD.PushError
GD.PushError(fullMessage);
break;
}
}
// ========== 快捷操作方式 ==========
public static void Debug(string fmt, params object[] args) =>
_root.Debug(fmt, args);
public static void Info(string fmt, params object[] args) =>
_root.Info(fmt, args);
public static void Warning(string fmt, params object[] args) =>
_root.Warning(fmt, args);
public static void Error(string fmt, params object[] args) =>
_root.Error(fmt, args);
public static void Critical(string fmt, params object[] args) =>
_root.Critical(fmt, args);
// ===== C语言风格的宏断言快捷方式 =====
[Conditional("DEBUG")]
public static void Assert(bool condition, string fmt, params object[] args) =>
_root.Assert(condition, fmt, args);
[Conditional("DEBUG")]
public static void TestPrint() {
GD.Print("GameSystem Singleton Initialized");
GD.PrintErr("This is a print error");
GD.PushWarning("This is a warning");
GD.PushError("This is a error");
Debug("This is a debug");
Info("This is a info");
Warning("This is a warn");
Error("This is a error");
Critical("This is a critical");
Assert(true, "This is a assert");
}
}