---
title: 日志生成器
description: 介绍日志生成器如何为标记类型生成 ILogger 字段并减少日志样板。
---

# 日志生成器

> GFramework.Core.SourceGenerators 自动生成日志代码，减少样板代码

## 概述

日志生成器是一个 Source Generator，它会自动为标记了 `[Log]` 特性的类生成 ILogger 字段。这消除了手动编写日志字段的需要，让开发者专注于业务逻辑。

## 基本用法

### 标记类

```csharp
using GFramework.Core.SourceGenerators.Abstractions.Logging;

[Log]
public partial class MyService
{
    public void DoSomething()
    {
        // 自动生成的 Logger 字段可直接使用
        Logger.Info("执行操作");
    }
}
```

### 生成代码

上面的代码会被编译时转换为：

```csharp
// <auto-generated/>
public partial class MyService
{
    private static readonly ILogger Logger =
        LoggerFactoryResolver.Provider.CreateLogger("YourNamespace.MyService");
}
```

**注意**：生成器只生成 ILogger 字段，不生成日志方法。日志方法（Info、Debug、Error 等）来自 ILogger 接口本身。

## 日志级别

生成的 Logger 字段支持 ILogger 接口的所有方法：

```csharp
[Log]
public partial class MyClass
{
    public void Example()
    {
        // 调试信息
        Logger.Debug($"调试信息: {value}");

        // 普通信息
        Logger.Info("操作成功");

        // 警告
        Logger.Warning($"警告: {message}");

        // 错误
        Logger.Error($"错误: {ex.Message}");

        // 严重错误
        Logger.Critical("系统故障");
    }
}
```

## 自定义日志类别

```csharp
[Log("Gameplay")]
public partial class GameplaySystem
{
    // 日志会标记为 Gameplay 类别
    public void Update()
    {
        Logger.Info("游戏逻辑更新");
    }
}
```

## 配置选项

### 自定义字段名称

```csharp
[Log(FieldName = "_customLogger")]
public partial class MyClass
{
    public void DoSomething()
    {
        // 使用自定义字段名
        _customLogger.Info("使用自定义日志器");
    }
}
```

### 非静态字段

```csharp
[Log(IsStatic = false)]
public partial class InstanceLogger
{
    // 生成实例字段而非静态字段
    public void LogMessage()
    {
        Logger.Info("实例日志");
    }
}
```

### 访问修饰符

```csharp
[Log(AccessModifier = "protected")]
public partial class ProtectedLogger
{
    // 生成 protected 字段
}
```

### 配置选项说明

| 参数             | 类型      | 默认值       | 说明                              |
|----------------|---------|-----------|---------------------------------|
| Name           | string? | null      | 日志分类名称（默认使用类名）                  |
| FieldName      | string  | "Logger"  | 生成的字段名称                         |
| IsStatic       | bool    | true      | 是否生成静态字段                        |
| AccessModifier | string  | "private" | 访问修饰符（private/protected/public） |

## 与其他模块集成

### 与 Godot 集成

```csharp
[Log]
[ContextAware]
public partial class GodotController : Node
{
    public override void _Ready()
    {
        Logger.Info("控制器已准备就绪");
    }
}
```

### 与架构集成

```csharp
[Log]
public partial class MySystem : AbstractSystem
{
    protected override void OnInit()
    {
        Logger.Info("系统初始化");
    }
}
```

## 实际应用示例

### 游戏控制器

```csharp
using GFramework.Core.Abstractions.Controller;
using GFramework.Core.SourceGenerators.Abstractions.Logging;
using GFramework.Core.SourceGenerators.Abstractions.Rule;

[Log]
[ContextAware]
public partial class PlayerController : IController
{
    public void HandleInput(string action)
    {
        Logger.Debug($"处理输入: {action}");

        switch (action)
        {
            case "jump":
                Logger.Info("玩家跳跃");
                Jump();
                break;
            case "attack":
                Logger.Info("玩家攻击");
                Attack();
                break;
            default:
                Logger.Warning($"未知操作: {action}");
                break;
        }
    }

    private void Jump()
    {
        try
        {
            // 跳跃逻辑
            Logger.Debug("跳跃执行成功");
        }
        catch (Exception ex)
        {
            Logger.Error($"跳跃失败: {ex.Message}");
        }
    }
}
```

### 数据处理服务

```csharp
[Log("DataService")]
public partial class DataProcessor
{
    public void ProcessData(string data)
    {
        Logger.Info($"开始处理数据，长度: {data.Length}");

        if (string.IsNullOrEmpty(data))
        {
            Logger.Warning("数据为空，跳过处理");
            return;
        }

        try
        {
            // 处理逻辑
            Logger.Debug("数据处理中...");
            // ...
            Logger.Info("数据处理完成");
        }
        catch (Exception ex)
        {
            Logger.Error($"数据处理失败: {ex.Message}");
            throw;
        }
    }
}
```

## 最佳实践

### 1. 合理使用日志级别

```csharp
[Log]
public partial class BestPracticeExample
{
    public void ProcessRequest()
    {
        // Debug: 详细的调试信息
        Logger.Debug("开始处理请求");

        // Info: 重要的业务流程信息
        Logger.Info("请求处理成功");

        // Warning: 可恢复的异常情况
        Logger.Warning("缓存未命中，使用默认值");

        // Error: 错误但不影响系统运行
        Logger.Error("处理失败，将重试");

        // Critical: 严重错误，可能导致系统崩溃
        Logger.Critical("数据库连接失败");
    }
}
```

### 2. 避免过度日志

```csharp
[Log]
public partial class PerformanceExample
{
    private int _frameCount = 0;

    public void Update()
    {
        // 好的做法：定期记录
        if (_frameCount % 1000 == 0)
        {
            Logger.Debug($"已运行 {_frameCount} 帧");
        }
        _frameCount++;

        // 避免：每帧都记录
        // Logger.Debug($"帧 {_frameCount}"); // ❌ 太频繁
    }
}
```

### 3. 结构化日志信息

```csharp
[Log]
public partial class StructuredLogging
{
    public void ProcessUser(int userId, string action)
    {
        // 好的做法：包含上下文信息
        Logger.Info($"用户操作 [UserId={userId}, Action={action}]");

        // 避免：信息不完整
        // Logger.Info("用户操作"); // ❌ 缺少上下文
    }
}
```

## 常见问题

### Q: 为什么需要 partial 关键字？

**A**: 源代码生成器需要向现有类添加代码，`partial` 关键字允许一个类的定义分散在多个文件中。

### Q: 可以在静态类中使用吗？

**A**: 可以，生成器会自动生成静态字段：

```csharp
[Log]
public static partial class StaticHelper
{
    public static void DoSomething()
    {
        Logger.Info("静态方法日志");
    }
}
```

### Q: 如何自定义日志工厂？

**A**: 通过配置 `LoggerFactoryResolver.Provider` 来自定义日志工厂实现。

---

**相关文档**：

- [Source Generators 概述](./index.md)
- [枚举扩展生成器](./enum-generator.md)
- [ContextAware 生成器](./context-aware-generator.md)
