GwWuYou 74df4a5ca3 docs(generator): 添加日志代码生成器使用文档
- 创建 GFramework 日志代码生成器完整使用指南
- 包含快速开始示例和基本使用方法说明
- 添加特性参数说明和高级配置示例
- 提供在系统、模型、工具类等不同场景的使用示例
- 整理最佳实践和注意事项部分
- 说明性能考虑和与现有日志系统的兼容性
2025-12-23 21:36:54 +08:00

10 KiB

GFramework 日志代码生成器 (LogAttribute)

概述

GFramework 提供了一个强大的日志代码生成器,类似于 Java 的 @Slf4j 注解。通过在类上使用 [Log] 特性,编译器会自动为该类生成一个日志记录器字段,让您在类的任何地方都能方便地使用日志记录功能。

快速开始

1. 基本使用

在类上添加 [Log] 特性:

using GFramework.Generator.Attributes.generator.logging;

[Log]
public partial class MyService
{
    public void DoSomething()
    {
        // 自动生成的 Log 字段可以直接使用
        Log.Info("开始执行操作");
        
        try
        {
            // 业务逻辑
            Log.Debug("执行业务逻辑", new { Operation = "DoSomething" });
            Log.Info("操作执行成功");
        }
        catch (Exception ex)
        {
            Log.Error("操作执行失败", ex);
        }
    }
}

编译后,生成器会自动为该类添加:

public partial class MyService
{
    private static ILog Log = Log.CreateLogger("MyService");
}

2. 自定义类别名称

[Log("CustomService")]
public partial class MyService
{
    // 生成的 logger 类别为 "CustomService" 而不是 "MyService"
}

3. 自定义字段配置

[Log(FieldName = "Logger", AccessModifier = "protected", IsStatic = false)]
public partial class MyService
{
    // 生成: protected ILog Logger = Log.CreateLogger("MyService");
}

特性参数说明

LogAttribute 构造函数参数

  • category (string, 可选): 指定日志类别,默认为类名

命名参数

  • FieldName (string, 默认 "Log"): 指定生成的字段名称
  • AccessModifier (string, 默认 "private"): 指定字段的访问修饰符
  • IsStatic (bool, 默认 true): 指定字段是否为静态的

使用示例

在系统中的使用

[Log("System")]
public partial class GameSystem : AbstractSystem
{
    protected override void OnInit()
    {
        Log.Info("GameSystem 初始化开始");
        
        // 初始化逻辑
        Log.Debug("正在加载游戏数据...");
        Log.Info("GameSystem 初始化完成");
    }
    
    protected override void OnUpdate(float deltaTime)
    {
        Log.Trace("系统更新", new { DeltaTime = deltaTime });
    }
    
    protected override void OnDestroy()
    {
        Log.Info("GameSystem 销毁");
    }
}

在模型中的使用

[Log("Model")]
public partial class UserModel : AbstractModel
{
    public string UserName { get; set; }
    
    public void SetUserName(string userName)
    {
        Log.Debug("设置用户名", new { OldValue = UserName, NewValue = userName });
        UserName = userName;
        Log.Info("用户名设置完成", new { UserName = userName });
    }
}

在工具类中的使用

[Log("Utility")]
public partial class FileUtility
{
    public void SaveFile(string filePath, string content)
    {
        Log.Debug("开始保存文件", new { FilePath = filePath });
        
        try
        {
            // 文件保存逻辑
            Log.Info("文件保存成功", new { FilePath = filePath });
        }
        catch (Exception ex)
        {
            Log.Error("文件保存失败", ex, new { FilePath = filePath });
        }
    }
}

网络服务中的使用

[Log("Network")]
public partial class NetworkService
{
    public async Task<string> GetDataAsync(string url)
    {
        Log.Debug("发起网络请求", new { Url = url, Method = "GET" });
        
        try
        {
            var response = await httpClient.GetStringAsync(url);
            Log.Info("网络请求成功", new { Url = url, ResponseLength = response.Length });
            return response;
        }
        catch (Exception ex)
        {
            Log.Error("网络请求失败", ex, new { Url = url });
            throw;
        }
    }
}

数据库服务中的使用

[Log("Database")]
public partial class DatabaseService
{
    public async Task<User> GetUserAsync(int userId)
    {
        Log.Debug("查询用户信息", new { UserId = userId });
        
        try
        {
            var user = await _dbContext.Users.FindAsync(userId);
            if (user != null)
            {
                Log.Info("用户查询成功", new { UserId = userId, UserName = user.Name });
            }
            else
            {
                Log.Warn("用户不存在", new { UserId = userId });
            }
            return user;
        }
        catch (Exception ex)
        {
            Log.Error("用户查询失败", ex, new { UserId = userId });
            throw;
        }
    }
}

高级配置示例

使用静态字段

[Log(IsStatic = true)] // 默认配置
public partial class StaticService
{
    public static void StaticMethod()
    {
        Log.Info("静态方法调用");
    }
}

使用实例字段

[Log(IsStatic = false)]
public partial class InstanceService
{
    private readonly string _instanceId;
    
    public InstanceService(string instanceId)
    {
        _instanceId = instanceId;
    }
    
    public void InstanceMethod()
    {
        Log.Info("实例方法调用", new { InstanceId = _instanceId });
    }
}

使用受保护的字段

[Log(AccessModifier = "protected")]
public partial class BaseService
{
    // 子类可以访问 protected 字段
}

[Log] // 派生类也可以有自己的日志记录器
public partial class DerivedService : BaseService
{
    public void DerivedMethod()
    {
        Log.Info("派生类方法");
        // 也可以访问基类的 protected Log 字段
    }
}

最佳实践

1. 使用合适的日志类别名称

// 好的做法:使用有意义的类别名称
[Log("UserService")]
public partial class UserService { }

// 避免:使用过于通用的类别名称
[Log("Service")]
public partial class UserService { }

2. 合理设置日志级别

[Log("BusinessLogic")]
public partial class BusinessService
{
    public void ProcessOrder(Order order)
    {
        // 使用 Info 记录重要的业务流程
        Log.Info("开始处理订单", new { OrderId = order.Id });
        
        // 使用 Debug 记录调试信息
        Log.Debug("订单验证通过", new { OrderId = order.Id });
        
        // 使用 Warning 记录异常情况
        if (order.Amount > 10000)
        {
            Log.Warn("大额订单", new { OrderId = order.Id, Amount = order.Amount });
        }
        
        // 使用 Error 记录错误
        try
        {
            // 业务逻辑
        }
        catch (Exception ex)
        {
            Log.Error("订单处理失败", ex, new { OrderId = order.Id });
        }
    }
}

3. 记录上下文信息

[Log("UserManagement")]
public partial class UserManager
{
    public void UpdateUserProfile(int userId, UserProfile profile)
    {
        Log.Info("更新用户资料", new 
        { 
            UserId = userId, 
            Changes = profile.GetChanges(),
            Timestamp = DateTime.Now
        });
    }
}

4. 在异常处理中使用日志

[Log("DataAccess")]
public partial class UserRepository
{
    public async Task<User> GetUserAsync(int userId)
    {
        try
        {
            return await _context.Users.FirstOrDefaultAsync(u => u.Id == userId);
        }
        catch (DbException ex)
        {
            Log.Error("数据库查询失败", ex, new { UserId = userId });
            throw new DataAccessException("无法获取用户信息", ex);
        }
    }
}

框架组件集成

在 GFramework 架构中使用

[Log("Architecture")]
public partial class ExampleArchitecture : AbstractArchitecture
{
    protected override void Init()
    {
        Log.Info("ExampleArchitecture 初始化开始");
        
        // 注册系统
        RegisterSystem(new GameSystem());
        RegisterSystem(new UISystem());
        
        // 注册模型
        RegisterModel(new UserModel());
        RegisterModel(new GameModel());
        
        // 注册工具
        RegisterUtility(new FileUtility());
        
        Log.Info("ExampleArchitecture 初始化完成");
    }
}

在事件处理中使用

[Log("Event")]
public partial class UserEventHandler
{
    [Log("EventHandler")]
    public void OnUserLoginEvent(UserLoginEvent evt)
    {
        Log.Info("用户登录事件", new 
        { 
            UserId = evt.UserId, 
            LoginTime = evt.LoginTime,
            IpAddress = evt.IpAddress
        });
    }
    
    [Log("EventHandler")]
    public void OnUserLogoutEvent(UserLogoutEvent evt)
    {
        Log.Info("用户登出事件", new 
        { 
            UserId = evt.UserId, 
            LogoutTime = evt.LogoutTime,
            SessionDuration = evt.SessionDuration
        });
    }
}

注意事项

  1. 部分类: 使用 [Log] 特性的类必须是 partial 类,因为生成器会添加字段到同一个类中。

  2. 命名空间引用: 确保项目中引用了 GFramework.Generator.Attributes 包。

  3. 编译时生成: 日志字段是在编译时生成的,不会影响运行时性能。

  4. 多线程安全: 生成的 ILog 实例是线程安全的,可以在多线程环境中使用。

  5. 继承: 派生类可以有自己的 [Log] 特性,也可以访问基类的受保护日志字段。

性能考虑

  • 编译时生成: 字段在编译时生成,没有运行时开销
  • 延迟初始化: 日志记录器按需创建,避免不必要的对象创建
  • 级别检查: 生成的代码包含级别检查,性能与手动创建的日志记录器相同

与现有日志系统的兼容性

生成的代码完全兼容现有的 GFramework.Core.logging 系统:

// 现有的方式仍然可以使用
var manualLogger = Log.CreateLogger("Manual");

// 新生成的字段也可以正常使用
[Log]
public partial class MyService
{
    public void Method()
    {
        // 两种方式都可以使用
        manualLogger.Info("手动创建的日志");
        Log.Info("自动生成的日志");
    }
}

通过使用 [Log] 特性,您可以显著减少样板代码,提高开发效率,同时保持日志记录的一致性和灵活性。