Go 调用方根据其运行位置打印不同的程序计数器

Go 调用方根据其运行位置打印不同的程序计数器,go,runtime,logrus,Go,Runtime,Logrus,我有下面的代码,它根据运行的位置打印不同的程序计数器值 代码: 当使用go run或编译的二进制文件运行时,它会打印(main.bar) 从Visual Studio代码运行代码时(仅在调试模式下工作正常) 运行时,(foo,bar,两者均缺失) 我正在使用一个框架(logrus),它依赖于PCs命令来执行一些操作(记录文件名)由于PC值根据其运行位置不断变化,因此它在调试模式下工作,但在使用go run或编译的二进制文件运行时失败 你知道是什么原因导致电脑加载方式不同吗?任何正在进行的配置或优

我有下面的代码,它根据运行的位置打印不同的程序计数器值

代码:

  • 当使用
    go run
    或编译的二进制文件运行时,它会打印(
    main.bar
  • 从Visual Studio代码运行代码时(仅在调试模式下工作正常)
  • 运行时,(
    foo
    bar
    ,两者均缺失)
  • 我正在使用一个框架(logrus),它依赖于PCs命令来执行一些操作(记录文件名)
    由于PC值根据其运行位置不断变化,因此它在调试模式下工作,但在使用
    go run
    或编译的二进制文件运行时失败

    你知道是什么原因导致电脑加载方式不同吗?任何正在进行的配置或优化?

    状态文档:

    要将这些PC转换为符号信息,如函数名和行号,请使用CallersFrames。CallersFrames解释内联函数,并将返回程序计数器调整为调用程序计数器。不鼓励直接迭代返回的PC片,因为在任何返回的PC上使用FuncForPC都不能解释内联或返回程序计数器调整

    Doc建议使用从原始计数器获取函数信息,这些计数器了解并说明函数内联,例如:

    pcs := make([]uintptr, 10)
    n := runtime.Callers(0, pcs)
    pcs = pcs[:n]
    
    frames := runtime.CallersFrames(pcs)
    for {
        frame, more := frames.Next()
        if !more {
            break
        }
        fmt.Println("Function:", frame.Function)
    }
    
    无论您如何调用/运行它,都应该输出该命令(请在上尝试):

    各国的文件:

    要将这些PC转换为符号信息,如函数名和行号,请使用CallersFrames。CallersFrames解释内联函数,并将返回程序计数器调整为调用程序计数器。不鼓励直接迭代返回的PC片,因为在任何返回的PC上使用FuncForPC都不能解释内联或返回程序计数器调整

    Doc建议使用从原始计数器获取函数信息,这些计数器了解并说明函数内联,例如:

    pcs := make([]uintptr, 10)
    n := runtime.Callers(0, pcs)
    pcs = pcs[:n]
    
    frames := runtime.CallersFrames(pcs)
    for {
        frame, more := frames.Next()
        if !more {
            break
        }
        fmt.Println("Function:", frame.Function)
    }
    
    无论您如何调用/运行它,都应该输出该命令(请在上尝试):



    这可能是由于函数内联造成的,请参阅以了解其如何影响堆栈跟踪以及如何确认。这是否回答了您的问题@Marc I添加了
    go:noinline
    ,但它仍然没有显示
    bar
    方法。有没有其他配置在这里可能会有所帮助?无意冒犯,但您可能添加了错误的配置,或者没有重新编译二进制文件。你真的不应该这样做只是为了避开日志库中的一个bug。@Marc没有问题,我也怀疑我的实现:)有和没有
    go:noinline
    有区别。唯一的区别是,现在
    goplayer
    和使用
    go run
    中的输出是相同的。但是,
    bar
    不显示的问题仍然存在。奇怪的是,这在几周前就开始起作用了,我们刚刚开始注意到
    文件名
    没有被
    logrus
    记录下来,并深入研究了这个问题,这可能是由于函数内联造成的,请看它如何影响堆栈跟踪以及如何确认。这是否回答了您的问题@Marc I添加了
    go:noinline
    ,但它仍然没有显示
    bar
    方法。有没有其他配置在这里可能会有所帮助?无意冒犯,但您可能添加了错误的配置,或者没有重新编译二进制文件。你真的不应该这样做只是为了避开日志库中的一个bug。@Marc没有问题,我也怀疑我的实现:)有和没有
    go:noinline
    有区别。唯一的区别是,现在
    goplayer
    和使用
    go run
    中的输出是相同的。但是,
    bar
    不显示的问题仍然存在。奇怪的是,这在几周前就起作用了,我们刚刚开始注意到
    logrus
    没有记录
    filename
    并深入研究了这个问题,不幸的是,
    logrus
    框架内部使用
    运行时。调用方
    API来解决这个问题。那么,使用这个API调用有什么解决方法可以让它工作吗?调试模式是如何实现这一点的,可能会跳过一些优化步骤?@Bandikish更有可能在调试模式下运行时,禁用函数内联,以便您可以检查/跟踪每个函数调用。调试模式与性能无关,而是与可跟踪性有关。如果
    logrus
    使用
    runtime.Callers()
    而不使用
    runtime.CallersFrames()
    ,则它严重需要更新。对于常规调用堆栈,它使用
    runtime.CallersFrames()
    ,但在单例初始化期间,它使用此API来计算
    logrus包@BandiKishore是的,您应该在那里创建一个问题。不幸的是,
    logrus
    框架内部使用
    runtime.Callers
    API来解决这个问题。那么,使用这个API调用有什么解决方法可以让它工作吗?调试模式是如何实现这一点的,可能会跳过一些优化步骤?@Bandikish更有可能在调试模式下运行时,禁用函数内联,以便您可以检查/跟踪每个函数调用。调试模式与性能无关,而是与可跟踪性有关。如果
    logrus
    使用
    runtime.Callers()
    而不使用
    runtime.CallersFrames()
    ,则它严重需要更新。对于常规调用堆栈,它使用
    runtime.CallersFrames()
    ,但在单例初始化期间,它使用此API来计算
    logrus包@是的,你应该在那里制造一个问题。
    
    Value of pc runtime.Callers
    Value of pc main.bar
    Value of pc main.foo
    Value of pc main.main
    Value of pc runtime.main
    Value of pc runtime.goexit
    
    Value of pc runtime.Callers
    Value of pc runtime.Callers
    Value of pc main.main
    Value of pc main.main
    Value of pc runtime.main
    Value of pc runtime.goexit
    
    pcs := make([]uintptr, 10)
    n := runtime.Callers(0, pcs)
    pcs = pcs[:n]
    
    frames := runtime.CallersFrames(pcs)
    for {
        frame, more := frames.Next()
        if !more {
            break
        }
        fmt.Println("Function:", frame.Function)
    }
    
    Function: runtime.Callers
    Function: main.bar
    Function: main.foo
    Function: main.main
    Function: runtime.main