GFramework/docs/zh-CN/core/logging.md
gewuyou 230cd0e5d1 docs(godot): 归档 Godot logging 主题
- 补充 GodotLogAppender 与 Core appender 组合示例

- 更新 Godot logging 文档中的文件输出接入说明

- 归档 godot-logging-core-sink 恢复材料并清理 boot 索引
2026-05-03 18:54:33 +08:00

4.9 KiB
Raw Blame History

title, description
title description
日志Logging 说明 GFramework.Core.Logging 的日志接口、组合方式与常见使用入口。

日志Logging

GFramework.Core.Logging 是 Core runtime 的默认日志实现。只加载抽象层时,LoggerFactoryResolver 会退回 silent provider加载 GFramework.Core 或在 ArchitectureConfiguration 里显式提供 provider 后,日志才会 真正输出。

最小用法

using GFramework.Core.Abstractions.Logging;

var logger = LoggerFactoryResolver.Provider.CreateLogger("Bootstrap");

logger.Info("Application started");
logger.Warn("Config file missing");

默认 ArchitectureConfiguration 会把 provider 配成 ConsoleLoggerFactoryProvider,最小级别是 Info。如果你 直接走标准 Architecture 启动路径,这条配置会自动生效。

在 Architecture 中调整日志级别

using GFramework.Core.Architectures;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Abstractions.Properties;
using GFramework.Core.Logging;

var configuration = new ArchitectureConfiguration
{
    LoggerProperties = new LoggerProperties
    {
        LoggerFactoryProvider = new ConsoleLoggerFactoryProvider
        {
            MinLevel = LogLevel.Debug
        }
    }
};

如果你只是想减少噪音或临时打开 Debug,通常只调 MinLevel 就够了。

结构化日志与上下文

默认 Core logger 实现支持 IStructuredLoggerLogContext。当你需要把 requestIdsceneName 之类的 上下文随异步流透传时,优先用上下文属性,而不是把所有信息拼进字符串。

using GFramework.Core.Abstractions.Logging;

var logger = LoggerFactoryResolver.Provider.CreateLogger("Matchmaking");

using (LogContext.Push("RequestId", requestId))
{
    if (logger is IStructuredLogger structured)
    {
        structured.Log(
            LogLevel.Info,
            "Player matched",
            ("PlayerId", playerId),
            ("RoomId", roomId));
    }
}

当前仓库内置的常用实现

  • ConsoleLoggerFactoryProvider
  • ConsoleLoggerFactory
  • CompositeLogger
  • LoggingConfigurationLoader

如果你需要文件输出、rolling file、async appender 或 JSON formatter可以先用 LoggingConfigurationLoader 读取 LoggingConfiguration,再把自定义 ILoggerFactoryProvider 挂到 ArchitectureConfiguration.LoggerProperties.LoggerFactoryProviderLoggerFactoryResolver.Provider

宿主包也可以提供自己的 appender。Godot 项目如果需要把 Core 日志管线输出到 Godot 控制台,可以引用 GFramework.Godot.Logging.GodotLogAppender,再用 CompositeLogger 或自定义 factory 把它和文件、JSON、异步输出等 Core 组件组合在同一条调用面下。

组合多个输出目标

需要同时写入宿主控制台和文件时,保留业务侧 ILogger 调用面不变,替换 provider 即可。下面的 provider 会为每个 logger 创建一个 CompositeLogger,并把同步的 Godot 控制台输出和异步文件输出组合在一起:

using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Logging;
using GFramework.Core.Logging.Appenders;
using GFramework.Core.Logging.Formatters;
using GFramework.Godot.Logging;

public sealed class GodotCompositeLoggerFactoryProvider : ILoggerFactoryProvider
{
    private readonly string _filePath;

    public GodotCompositeLoggerFactoryProvider(string filePath)
    {
        _filePath = filePath;
    }

    public LogLevel MinLevel { get; set; } = LogLevel.Info;

    public ILogger CreateLogger(string name)
    {
        return new CompositeLogger(
            name,
            MinLevel,
            new GodotLogAppender(),
            new AsyncLogAppender(new FileAppender(_filePath, new DefaultLogFormatter())));
    }
}

在 Godot 宿主里,文件路径应先解析成普通文件系统路径,再挂到架构配置:

using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Abstractions.Properties;
using GFramework.Core.Architectures;
using Godot;

var logPath = ProjectSettings.GlobalizePath("user://logs/game.log");
var configuration = new ArchitectureConfiguration
{
    LoggerProperties = new LoggerProperties
    {
        LoggerFactoryProvider = new GodotCompositeLoggerFactoryProvider(logPath)
        {
            MinLevel = LogLevel.Debug
        }
    }
};

GodotLogAppender 只负责 Godot 控制台落点文件生命周期、异步缓冲、formatter 与过滤规则仍然来自 Core logging 组件。

什么时候该换 provider

下面这些场景通常不该只靠改 MinLevel

  • 需要文件输出、rolling file 或 async appender
  • 需要按 namespace / level 做过滤
  • 需要 JSON 格式日志
  • 需要组合多个 appender
  • 需要把输出落到 Godot、Unity 或其他宿主控制台

这时更合理的做法是保留 ILogger 调用面不变,只替换 provider / factory / formatter / appender 组合。