一、调试
调试是确定程序为何不像与其那样工作的过程。程序不像预期那样工作的迹象有很多,包括编译错误、运行阶段错误、文件权限问题以及数据不正确等。
1 日志
日志指的是记录程序执行期间发生的情况。无论程序需不需要调试,都会产生日志,这对于理解程序的执行情况很有帮助。很多常见的应用程序都提供了日志功能,这些日志可用来监视应用程序的健康状况、跟踪问题以及发现问题。
日志并非报告Bug而提供的,而是可供在Bug发生时使用的基础措施。诸如Nginx等Web服务器在运行期间将日志写入文件,包括访问日志和错误日志
Go语言提供了log包,让应用程序能够将日志写入终端或文件。
package main
import "log"
func main(){
log.Printf("This is a log message")
}
这个程序将输出一条日志消息到终端,结果如下:
log包还可以用来记录发生的致命错误。如下:
package main
import (
"errors"
"log"
)
func main() {
var errFatal = errors.New("We only just started and we are crashing")
log.Fatal(errFatal)
}
执行结果如下:
查看日志对了解发生的意外事件更有帮助。这意味着需要将日志写入文件,以便日后访问他们,如下:
package main
import (
"log"
"os"
)
func main() {
f, err := os.OpenFile("example03.log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
log.Fatal(err)
}
defer f.Close()
log.SetOutput(f)
for i := 1; i <= 5; i++ {
log.Printf("Log iteration %d", i)
}
}
结果我们得到了一个example03.log的日志文件,如下:
要将日志写入文件,还可以使用操作系统提供的功能将日志输出从终端重定向到文件。这种方法不需要编写任何的Go代码,因为它使用的是操作系统提供的功能。如下面的代码将向终端输出5条消息
package main
import (
"log"
)
func main() {
for i := 1; i <= 5; i++ {
log.Printf("Log iteration %d", i)
}
}
使用重定向功能,可将输出重定向到文件。
go run example04.go > example.log 2>&1
结果如下:
通常情况下,我们使用操作系统将日志重定向到日志文件,而不使用Go代码。因为这种方法更灵活,能够让其他工具在必要时候使用日志
2 打印数据
在很多情况下,Bug嗾使由于数据不符合预期导致的。如下面这个程序。他提示玩家出入,并根据属兔判断玩家能否获得奖励。如果玩家猜对了名字,就能够获得奖励;否则将显示一条消息,指出他没有获奖。
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Guess the name of my pet to win a prize: ")
text, _ := reader.ReadString('\n')
text = strings.Replace(text, "\n", "", -1)
if text == "John" {
fmt.Println("You won! You win chocolate!")
} else {
fmt.Println("You didn't win. Better luck next time")
}
}
我们在检测是否发生bug的时候可以添加一条指令:
fmt.Println("[DEBUG] text is:",text)
3 使用Delve
Go语言没有官方调试器,但很多社区项目都提供了Go语言调试器。Delve就是这样的项目,它为Go项目提供了丰富的调试环境。
安装:go get github.com/go-delve/delve/cmd/dlv
确认安装成功使用dlv --help
命令
相比较于日志和打印代码行,Delve提供的环境要精致得多。虽然使用fmt包进行调试是一种快捷而简单的方法,但Delve提供了更精致的程序调试环境。Delve让开发人员能够与正在执行的程序交互、进入正在运行的进程以及查看核心转储和栈跟踪。使用如下程序演示如何使用Delve
package main
import (
"fmt"
)
func echo(s string) {
fmt.Println(s)
return
}
func main() {
s := "Hello World"
t := "Goodbye Cruel World"
echo(s)
echo(t)
}
调试过程如下:
这里的调试过程和gdb的调试过程几乎一样的,就不过多赘述了
参考书籍
[1]: 【Go语言入门经典】[英] 乔治·奥尔波 著 张海燕 译