You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

log4net自定义ILog中间类日志行号显示为0问题求助

解决自定义LoggerManager日志行号显示为0的问题

问题根源

日志框架默认会抓取直接调用日志方法的代码位置,也就是你的LoggerManager.Print方法所在行,但你需要的是上层UsingClass.Print的调用行号。虽然堆栈追踪里能看到正确行号,但框架没自动定位到那一层,所以显示0。

解决方案

方案1:手动遍历堆栈帧获取调用方信息

在LoggerManager的Print方法里,通过StackTrace跳过当前类的方法,找到第一个外部调用的堆栈帧,提取行号后传入日志方法:

using System.Diagnostics;

public class LoggerManager : ILog
{
    public void Print(object message)
    {
        var stackTrace = new StackTrace(true); // true表示捕获文件名和行号
        StackFrame callerFrame = null;

        // 遍历堆栈帧,跳过LoggerManager自身的方法
        foreach (StackFrame frame in stackTrace.GetFrames())
        {
            var declaringType = frame.GetMethod()?.DeclaringType;
            if (declaringType != null && declaringType != typeof(LoggerManager))
            {
                callerFrame = frame;
                break;
            }
        }

        int lineNumber = callerFrame?.GetFileLineNumber() ?? 0;
        Type callerType = callerFrame?.GetMethod()?.DeclaringType ?? typeof(UsingClass);

        // 将调用方类型和行号传入日志方法
        Log.Debug($"[{callerType.Name}] {message}:{lineNumber}");
    }
}

方案2:利用编译器特性自动注入调用方信息

使用.NET的CallerLineNumber、CallerFilePath等特性,让编译器自动把调用方的行号、文件名等信息注入到方法参数中,无需手动遍历堆栈:

using System.Runtime.CompilerServices;

public class LoggerManager : ILog
{
    // 添加Caller相关特性,编译器会自动填充参数值
    public void Print(object message,
                      [CallerLineNumber] int lineNumber = 0,
                      [CallerMemberName] string callerMethod = "",
                      [CallerFilePath] string callerFile = "")
    {
        // 获取调用方类型
        var callerType = new StackTrace().GetFrame(1).GetMethod().DeclaringType;
        // 输出日志时带上行号
        Log.Debug($"[{callerType.Name}] {message}:{lineNumber}");
    }
}

调用时无需额外传参,编译器会自动处理:

// UsingClass中的调用,直接传消息即可
loggerManager.Print("Hello");

关键注意事项

  • 确保项目编译时启用调试符号生成(生成PDB文件):在项目属性的“生成”选项卡中,勾选“调试信息”为“完整”或“pdb-only”,否则无法获取行号信息。
  • 如果使用第三方日志框架(如NLog、Log4net),部分框架支持配置忽略中间类,让框架自动跳过LoggerManager直接获取调用方信息。比如NLog可以在配置中添加skipFrames="1"来跳过当前方法层。

内容的提问来源于stack exchange,提问作者Omer Somekh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:57:35