golang获取执行函数名,执行文件名与所在行数

使用Delve进行Golang代码的调试 dlvgit 仓库:https://github.com/go-delve/delve/tree/master/Documentation/installation Delve目的就是为了解决开发者在使用 GDB 调试中遇到的各种各样的问题。我们开始详细的介绍一些使用Delve 调试代码的例子。 安装 首先默认你已经安装了 Go 环境,安装命令很简单,一句话。 go get github.com/derekparker/delve/cmd/dlv 注意:如果你使用Go1.5,你必须在运行这个. 阅读详情

本文首发于我的个人博客

这篇文章介绍了作者在参与一个golang日志系统的开发的时候,解决需要打印出执行日志打印操作时的业务函数名,业务文件名与所在行数的需求过程中,遇到的问题和解决方案

需求场景

在平日里使用日志的时候,一个好的日志系统,往往会打印出类似如下的信息

<log_level>:<log_message>:<package_path>/<filename>:<line_no>:<function_name>
比如
INFO:connect to sql:/users/admin/home/go/src/io/rivers/demoProject/main.go:45:io.rivers.demoProject.testFunction

这样子在打印出日志等级,日志消息的同时,输出业务逻辑所在的文件,行数,函数,对后期的bug排查,性能分析都有很大的帮助

那么,如何在golang中实现这一功能呢?

实现方式

golang的runtime包提供了与之相应的函数接口,主要是runtime.Caller和runtime.FuncForPC

先看一下二者的函数签名

func Caller(skip int) (pc uintptr, file string, line int, ok bool)

func FuncForPC(pc uintptr) *Func

单看函数签名就比较容易了解到:

  • runtime.Caller能够返回在函数栈中的PC(指令寄存器,可以认为存储了当前执行到了哪里),所在的文件,所在文件的具体哪一行
  • runtime.FuncForPC能够根据给定的指令寄存器给出其所在的行数

其中runtime.FuncForPC的参数比较容易理解,就是指指令寄存器,但是runtime.Caller的参数需要解释一下

这里的skip指的是跳过多少个函数栈:

  • skip == 0,不跳过函数栈,返回当前函数PC,文件名,所在行
  • skip == 1,跳过当前函数栈,返回上层调用者调用当前函数时的PC,文件名,所在行
  • skip == 2,以此类推

一般情况下这两个函数都是连在一起使用,如

// 获取上层调用者PC,文件名,所在行
pc, codePath, codeLine, ok := runtime.Caller(1)
if !ok{
    // 不ok,函数栈用尽了
    code = "-"
    func = "-"
} else {
    // 拼接文件名与所在行
    code = fmt.Sprintf("%s:%d", codePath, codeLine)
    // 根据PC获取函数名
    func = runtime.FuncForPC(pc).Name()
}

实现重点与自动获取的优化

可以看到,在我们使用runtime.Caller和runtime.FuncForPC这一组合击的时候,实际上的输入参数只有一个,那就是runtime.Caller的skip。

如何确定skip呢?在实践中,我一般使用两种方式:

  1. 写死
  2. 尝试自动获取

听起来第二种方法要比第一种方法好,但是事实上并不是这样的,在看完实现之后,大家就会明白了

将skip写死

这种方式是比较常见的,通常适用于设计时确定了调用层数的情况,以日志系统为例,我们现在要提供一个接口log,那么我知道外界肯定是要直接调用log的,我最终要打印的就是调用log的函数的文件名,所在行,函数名

那么如果我是在log里使用runtime.Caller,那么我的skip就应该是1

func log(logLevel int, logMessage string) {
    //....
    pc, file, line, ok := runtime.Caller(1)
    //....
}

如果我还做了封装,那么就要根据编写代码时的封装层数调整skip,比如

func log(logLevel int, logMessage string) {
    //....
    logHelper(logLevel, logMessage)
    //....
}

func logHelper(logLevel int, logMessage string) {
    //....
    logReal(logLevel, logMessage)
    //....
}

func logReal(logLevel int, logMessage string) {
    //...
    pc, file, line, ok := runtime.Caller(3)
    //...
}

上述示例中,由于多了两层封装,所以要把skip更改为3

尝试自动获取

这次的尝试自动获取是我在编写日志系统时遇到的一个比较特殊的情况

在上面说的#将skip写死中,其实我们有一个重要的前提,那就是

业务函数全部直接调用日志接口log

但是这次在开发日志系统时,遇到了这样的场景:

日志拥有接口log1和log2,log2调用log1,业务代码既可能调用log2,也可能直接调用log1
log1下层调用runtime.Caller和runtime.FuncForPC组合

这种情况下,skip是不可能写死在源代码里的,于是采取的解决方案如下

由于日志系统在一个独立的包里,所以在FuncForPC将函数名取出来以后,判断是否是日志包中的函数,如果是,就增加skip的值

实现:

for skip := 1; true; skip++ {
    pc, codePath, codeLine, ok := runtime.Caller(skip)
    if !ok{
        // 不ok,函数栈用尽了
        auto.Code = prevCode
        auto.Func = prevFunc
        return auto
    } else{
        prevCode = fmt.Sprintf("%s:%d", codePath, codeLine)
        prevFunc = runtime.FuncForPC(pc).Name()
        auto.Code = prevCode
        auto.Func = prevFunc
        if !strings.Contains(prevFunc, "<package_name>") {
            // 找到包外的函数了
            return auto
        }
    }
}

这样就算是一个能够解决问题的方案了

5分钟搞懂语义通信:如何用深度学习让AI理解你的真实意图? 本文深入解析了语义通信如何利用深度学习技术,实现从传统‘比特保真’到‘语义保真’的范式转移。通过介绍基于神经网络的端到端系统架构、编解码技术及实战案例,阐明AI如何理解并高效传递信息核心意图,为6G时代的人机交互奠定基础。 阅读详情

相关推荐

从ISCXTor2016到CICIDS2017:手把手教你下载和使用UNB的网络安全数据集

本文详细介绍了UNB大学发布的ISCXTor2016和CICIDS2017等网络安全数据集的下载与使用方法,特别适合加密流量识别和网络行为分析研究。文章提供了多种高效获取路径、文件结构解析及实战分析示例,帮助研究者快速上手这些真实场景捕获的精细标注数据集。

weixin_42524945的博客 630

golang按层级获取函数名

/参数 layer 函数所在的层数。// GetFuncName 获取函数名。

420

【科研导航】【计算机视觉与图像处理】从顶刊到潜力股:跨学科(电子/电气/信息)SCI期刊投稿全景图

本文全面解析了计算机视觉与图像处理领域的SCI期刊投稿策略,涵盖从顶刊到潜力股的各类期刊特点。重点介绍了IEEE Transactions系列、Elsevier旗舰期刊以及二区优质期刊的审稿偏好和投稿技巧,特别适合电子/电气/信息交叉学科的研究者。文章还提供了三区、四区期刊的实用投稿建议,帮助科研新手快速找到适合的发表平台。

weixin_30897233的博客 81

如何在Go的函数中得到调用者函数名(caller)

在go语言中,可以通过runtimepackage中 Caller函数获取调用者信息Caller举个例子outputskip 0, caller就是test1skip 1, caller就是test2skip 1, 一个新goroutine执行 test1,caller就是。

翔云 1114

DNN加速器脉动阵列轻量级瞬时故障检测

本文系统综述了面向深度神经网络(DNN)脉动阵列加速器的轻量级瞬时故障检测技术。通过分析比较算法级校验(ABFT)、数值异常监测(剪裁、中值滤波等)、硬件编码检错(AN码、剩余码)以及选择性冗余等方案,指出这些方法能以5%-10%的开销实现对权重和激活比特翻转的高效检测,远低于传统ECC/冗余计算的成本。研究显示,结合多种轻量技术可构建多层防护体系,在保障推理可靠性的同时保持加速器的高性能特性。该成果为安全关键领域的DNN加速器设计提供了重要参考。

欢迎交流! 1073

人工势场法三大致命缺陷?我用ROS+Gazebo做了组对比实验

本文通过ROS与Gazebo仿真实验,深入剖析了人工势场法(APF)在机器人路径规划中的三大经典问题:局部最小值、目标不可达和路径震荡。文章不仅复现了这些缺陷,还对比测试了虚拟目标点法、改进斥力场及运动平滑等主流改进方案,为工程选型提供了基于数据的实用建议。

dapp9builder的博客 216

golang 获取当前文件名和行号的方法

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34051201的博客 3004

Matlab结果性能评价---rms函数(计算矩阵、数组和向量元素均方根)

实例1:创建一个向量(正弦波)并计算其均方根值 实例2:创建一个二维矩阵并计算其均方根值 实例3:计算二维矩阵沿指定维度的均方根值 本例程配套完整源码下载 均方根(Root-Mean-Square Level): 向量x的均方根值为沿着指定的维度执行求和: 语法描述: y = rms(x)返回输入x的均方根值。如果x是行或列向量,y是实数值标量。对于大小尺寸大于1矩阵x,y包含沿x的第一个数组维度计算的均方根值。例如,如果x是N > 1的N*M矩阵,那么y是1*M行向量,对应x矩..

qq_32809093的博客 3万+

go语言日志实现详解(打印日志、日志写入文件和日志切割)

log包定义了Logger类型,该类型提供了一些格式化输出的方法。本包也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Panic系列(Panic|Panicf|Panicln)来使用,比自行创建一个logger对象更容易使用。 package main import ( "log" ) func main() {

不定时分享最优质的网络技术与教程,满满的干货。 5161

Quuppa 如何引领蓝牙 ® 定位服务的全新发展方向

我们最优质的客户,是那些对其他实时定位系统(RTLS)的承诺感到失望、转而寻求 “能覆盖全业务场景的更广泛赋能技术” 的客户 —— 前文提到的消防车制造商就是典型案例:他们尝试并通过 Quuppa 的蓝牙方案取得了成功。我们希望业务合作伙伴(如系统集成商、解决方案提供商)能充分利用 Quuppa 智能定位系统的功能,为客户提供专属解决方案:无论是追踪微型标签、实现未来移动设备的 AoD 功能,还是基于 RSSI 的简单信标(信标作为物联网网关),这些功能都能让同一套 Quuppa 系统支持广泛的用例。

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 831

【报错】ImportError: libpython3.10.so.1.0: cannot open shared object file: No such file or directory

ImportError: libpython3.10.so.1.0: cannot open shared object file: No such file or directory

静谧、淡雅 859

golang 打印函数名/文件名/行号 Callers

golang 的runtime库,提供Caller函数,可以返回运行时正在执行的文件名和行号: 函数定义: func Caller(skip int) (pc uintptr, file string, line int, ok bool) {} 函数用法: _, file, line, ok := runtime.Caller(0) package main import ("fmt";"...

whatday的专栏 1万+

(十二)深入理解蓝牙BLE之“移植Bluez 5.18源码到嵌入式平台”

在某嵌入式平台进行蓝牙开发,发现上面居然没有btmon,hciattach,hcitool等蓝牙调试工具,无奈之下,只好移植bluez协议栈到目标嵌入式平台,建议移植5.18版本(最新的5.54版本居然hcitool等工具不是默认编译的,需要修改Makefile才可以)。 看到很多讲解移植过程的文章都是需要积分的,觉得写一篇免积分的文章还是有些意义的,欢迎同行来交流。 移植环境:Linux ubuntu 目标平台:sigmastar 星宸科技 配置交叉编译工具链:export PATH=$PATH:

2964

2022-03-07 golang获取文件名、函数名、行数

golang获取文件名、函数名、行数

oceanstudy123的博客 1444

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

go 定位函数操作位置(文件名、函数名、所在行)

runtime.Caller()返回函数执行程序计数pc、执行的文件名和所在行数 runtime.FuncForPC()传入pc,得到运行的函数指针 文件结构 - runtime - -file1.go - -file2.go - -main.go main.go文件 package main import ( "fmt" "path" "runtime" ) func main(){ name, funcName, line := f2(0) fmt.Printf("file:%v;fun

wzbwzt的博客 1193

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

如何在 Go 函数中获取调用者的函数名、文件名、行号...

背景我们在应用程序的代码中添加业务日志的时候,不论是什么级别的日志,除了我们主动传给 Logger 让它记录的信息外,这行日志是由哪个函数打印的、所在的位置也是非常重要的信息,不然排查问题的时候很有可能就犹如大海捞针。对于在记录日志时记录调用 Logger 方法的调用者的函数名、行号这些信息。有的日志库支持,比如 Zapfuncmain(){ logger,_:=zap.NewPro...

Seekload 1132

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Go调试器Delve

Delve是Go官方推荐的调试器,我们熟知的Goland、LiteIDE都集成了Delve,同时各大通用IDE如VSCode、Atom、Sublime等的Go插件也都集成了Delve调试Go代码。 除了IDE以外,还有一个使用Delve的GUI调试器——Gdlv。除了提供图形界面外,Gdlv也可以执行Delve命令。 开始 第一步需要安装Delve。 Go1.16及以上版本: $ go install github.com/go-delve/delve/cmd/dlv@latest $ go install

陈戏猿 2326

consul golang使用_以Linux系统为目标:分析新型Golang语言勒索软件

0x00 概述在过去的两个月中,我一直在研究使用Golang编写的逆向软件,并对其进行逆向工程。Go语言,也成为Golang,是Google设计的一种静态类型的、已编译的编程语言,目前在恶意软件开发社区中正在变得越来越流行。在本文中,我将分析一个新发现的Golang勒索软件,该软件主要针对Linux系统发动攻击。 0x01 Go二进制样本分析我们所分析的样本是已经stripped的EL...

weixin_39617702的博客 161

go的delve工具调试

https://yq.aliyun.com/articles/57578 https://www.cnblogs.com/li-peng/p/8522592.html ================================================================================= 追踪代码中的错误可能是一件非常头疼的事情。这在高度依赖goro...

小豆角的博客 962

Go:Go语言的语法规范和开发常见错误

本文介绍了Go语言开发中常见的错误原因和语法规范,以及Go中常用的换行符

Liu_y_xin的博客 634

Go 语言编程 — 使用 delve 进行 DEBUG 调试

目录 文章目录目录delve delve Golang 支持使用 GDB 来进行调试,这与 C 语言几乎是一致的。但 GDB 是一个通用性调试工具,不非常能直接地反映出 Golang 的特点,例如:goroutine 语句的调试。 所以,推荐使用 delve(https://github.com/go-delve/delve),可以理解为是 Golang 版本的 GDB,使用方式大致与 GBD 一致。 安装: go get -u github.com/derekparker/delve/cmd/dlv 测

烟云的计算 4201

golang 生成测试覆盖率_有赞iOS精准测试实践

点击关注“有赞coder”获取更多技术干货哦~作者:周夏赛团队:有赞零售一、背景近几年有赞零售业务快速发展,为了满足日益增多的业务需求,2019年起零售客户端发版改成了每周一次,在质量保障方面,技术团队要面对更大的挑战。故此我们团队做了很多研究,希望通过技术工具来提升移动端测试的质量和效率,这是我们研发移动端精准测试平台的初衷。目前业内移动端的测试手段主要有两种,一种是手工测试,手工测试...

weixin_35531726的博客 846

Go语言-测试与性能分析

Go语言之测试与性能分析 ​ 在接触的几门计算机编程语言中,都会有与之对应的单元测试与性能分析方法或者工具。Go语言当然也不例外,本文将记录Go语言中测试与性能分析的内容,其目的是为了掌握Go语言中测试和性能分析和提出一些容易出现的问题。 目录Go语言之测试与性能分析1. 测试1.1 单元测试1.1.1 第一个单元测试1.2 表组测试1.3 覆盖测试小结2. 基准测试 1. 测试 Go语言里有几种方法可用于单元测试: 基础测试 - 一组参数和结果测试代码 表组测试 - 多组参数和结果测试代码 1

hoyiuga的博客 1921

Go -- log日志库

一、标准库log介绍1、使用Logger2、配置logger2.1、标准logger的配置二、自定义日志库1、需要满足的需求2、了解下runtime包 一、标准库log介绍 Go语言内置的log包实现了简单的日志服务。 1、使用Logger log包定义了Logger类型,该类型提供了一些格式化输出的方法。 log包也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Pan.

CN_LiTianpeng的博客 1254

Go代码调试工具 - delve

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33817333的博客 761

使用Delve调试Golang 代码

追踪代码中的错误可能是一件非常头疼的事情。这在高度依赖goroutine的Golang代码调试中更加的突出。有一个趁手的 debug 工具就显得非常的重要。我们先来看看 Go 官方的debug tool文档写的啥。 GDB does not understand Go programs well. The stack management, threa...

weixin_34372728的博客 213
上一篇: Vue+Axios自动更新
下一篇: Vue中为对象添加字段
FitzLeopard
博客等级 码龄9年 6粉丝 44原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值