调试 Go 程序

发布于 2020-06-06 13:58:12

打印输出、日志输出

利用 fmtlog 在程序里输出相关信息是比较传统的调试手不详述了。

唯一要提的是如何把结构体连带字段名一起输出出来,否则看起来还是比较难受。这个可以通过fmt 的内置的 %#v 格式来输出完整字段:

type S struct {
	A int
	B int
}

func main() {
	a := S{3, 4}
	fmt.Printf("%v, %#v", a, a)
}
$ go run main.go
{3 4}, main.S{A:3, B:4}

另外还有一些第三方的封装:

GDB

  1. 安装 gdb: brew install gdb
  2. macOS 上需要关闭 DWARF debug 信息的压缩:export GOFLAGS="-ldflags=-compressdwarf=false"
  3. macOS 上以普通用户运行 gdb <executable-binary> 后在内部调用 run 之后报错 Unable to find Mach task port for process-id 42061: (os/kern) failure (0x5). (please check gdb is codesigned - see taskgated(8)),在依照这个回答 执行后依然没有解决
  4. 倒是通过sudo以管理员权限运行可以解决这个报错,然后通过 run 命令运行程序,但。。然后就卡住没有新的提示符输出了???

最后通过 –entitlements gdb.xml 参数可以解决这个问题,并且不需要通过sudo运行!

gdb.xml 内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.debugger</key>
    <true/>
    <key>com.apple.security.get-task-allow</key>
    <true/>
</dict>
</plist>

具体使用可参考视频 使用GDB调试Go程序 - YouTube 和查看 Go使用gdb调试

常见命令:

  • list。列出代码,输入第一次后如果输入回车,那么就会重复以上命令
  • break。加断点,一般是list之后,break 行号来加断点
  • bt。打印调用链
  • info files。打印调试文件信息
  • run。运行所要调试的代码
  • up 和 down。在frame里跳来跳去
  • info args 和 info locals 打印参数和本地变量
  • whatis 和 p。打印变量和想要看的值,例如数组啊,函数啊,都可以
  • info goroutines。查看所有的goroutine及其ID
  • goroutine 命令。对对应的goroutine执行命令。
  • q。退出
  • help。打印帮助文档

CGDB

CGDB: Curses-based interface to the GNU Debugger.

可以参考这个视频 Easier Go debugging on the command line with CGDB

  • esc: goto source code separate window
  • i: insert, goto the console window
  • c: continue
  • r: run
  • s: step into function
  • n: next
  • print: print variables

Delve 调试

安装:

# 确保编译工具链
xcode-select --install
# 安装 dlv
go get github.com/go-delve/delve/cmd/dlv
# 开启开发者模式
sudo /usr/sbin/DevToolsSecurity -enable

通过dlv debug *.go启动,进入一个交互界面,在这个界面里我们就可以进行调试操作了。

可观看短视频 Debugging Go applications with Delve,以及 delve 开发者的演讲 Advanced Go debugging with Delve所有演讲

(dlv) help
The following commands are available:

Running the program:
    call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
    continue (alias: c) --------- Run until breakpoint or program termination.
    next (alias: n) ------------- Step over to next source line.
    restart (alias: r) ---------- Restart process.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    stepout (alias: so) --------- Step out of the current function.

Manipulating breakpoints:
    break (alias: b) ------- Sets a breakpoint.
    breakpoints (alias: bp)  Print out info for active breakpoints.
    clear ------------------ Deletes breakpoint.
    clearall --------------- Deletes multiple breakpoints.
    condition (alias: cond)  Set breakpoint condition.
    on --------------------- Executes a command when a breakpoint is hit.
    trace (alias: t) ------- Set tracepoint.

Viewing program variables and memory:
    args ----------------- Print function arguments.
    display -------------- Print value of an expression every time the program stops.
    examinemem (alias: x)  Examine memory:
    locals --------------- Print local variables.
    print (alias: p) ----- Evaluate an expression.
    regs ----------------- Print contents of CPU registers.
    set ------------------ Changes the value of a variable.
    vars ----------------- Print package variables.
    whatis --------------- Prints type of an expression.

Listing and switching between threads and goroutines:
    goroutine (alias: gr) -- Shows or changes current goroutine
    goroutines (alias: grs)  List program goroutines.
    thread (alias: tr) ----- Switch to the specified thread.
    threads ---------------- Print out info for every traced thread.

Viewing the call stack and selecting frames:
    deferred --------- Executes command in the context of a deferred call.
    down ------------- Move the current frame down.
    frame ------------ Set the current frame, or execute command on a different frame.
    stack (alias: bt)  Print stack trace.
    up --------------- Move the current frame up.

Other commands:
    config --------------------- Changes configuration parameters.
    disassemble (alias: disass)  Disassembler.
    edit (alias: ed) ----------- Open where you are in $DELVE_EDITOR or $EDITOR
    exit (alias: quit | q) ----- Exit the debugger.
    funcs ---------------------- Print list of functions.
    help (alias: h) ------------ Prints the help message.
    libraries ------------------ List loaded dynamic libraries
    list (alias: ls | l) ------- Show source code.
    source --------------------- Executes a file containing a list of delve commands
    sources -------------------- Print list of source files.
    types ---------------------- Print list of types

Type help followed by a command for full documentation.

IDE 调试

Goland

参见 Debugging - Help | GoLand。它的优点是可以动态加载代码更新。

几个概念分别是 breakpoints,debug mode,debug configurations

VSCode

单元测试

  • go 的单元测试文件必须是 xxx_test.go 格式,而且函数名必须是 TestXXX(t *testing.T) 格式
  • testing
    • 使用内置 testing 库,并通过调用 *testing.T.Error() 触发测试失败
    • 另外可通过 *testing.T.Log()*tesing.T.Logf() 输更多信息
  • go test 运行测试
    • -v 输出详细信息,包含 Log 输出的信息
    • -cover 参数可以输出覆盖率信息
    • -json 参数可以输出 JSON 格式,用于程序自动化处理
    • go test ./... 分别运行每个包里的测试
    • -c 单独的测试可执行文件
  • 第三方库

另外,测试里还有Mock, Stub, Spy的概念。

Benchmarks

  • test#Benchmarks
    • 函数名必须是 BenchmarkXXX(b *testing.B) 格式
    • go test -bench=. -v 运行性能测试

参考