GO:源碼的修改、調試
需求:
1.通過修改GO源碼邏輯,實現想要的自定義功能。
例如:修改GO的net/http等相關包的代碼,內嵌針對HTTP請求/應答的原始消息輸出到日誌,方便定位排查。
2.臨時修改GO源碼邏輯,進行復雜的調試,便於理解GO代碼。
例如:學習GO的net/http包,看着一長串的調用【深度、廣度】,如果能調試輸出,是否更便於理解代碼呢?
實現:
直接修改GO源碼,編譯。
例子:
我的開發環境:
[test1280@localhost ~]$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/test1280/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/test1280/gopath"
GOPROXY="https://goproxy.io"
GORACE=""
GOROOT="/home/test1280/go"
GOTMPDIR=""
GOTOOLDIR="/home/test1280/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build447053725=/tmp/go-build -gno-record-gcc-switches"
我的目錄結構:
[test1280@localhost ~]$ tree -L 1
.
├── go
├── go1.12.5.linux-amd64.tar.gz
├── gopath
└── myproject
3 directories, 1 file
[test1280@localhost ~]$ tree -L 2
.
├── go
│ ├── api
│ ├── AUTHORS
│ ├── bin
│ ├── CONTRIBUTING.md
│ ├── CONTRIBUTORS
│ ├── doc
│ ├── favicon.ico
│ ├── lib
│ ├── LICENSE
│ ├── misc
│ ├── PATENTS
│ ├── pkg
│ ├── README.md
│ ├── robots.txt
│ ├── src
│ ├── test
│ └── VERSION
├── go1.12.5.linux-amd64.tar.gz
├── gopath
└── myproject
├── go.mod
├── main.go
└── myproject
11 directories, 13 files
我的測試代碼:
[test1280@localhost myproject]$ cat go.mod
module myproject
go 1.12
[test1280@localhost myproject]$ cat main.go
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("http://127.0.0.1:8080/")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
正常編譯運行:
[test1280@localhost myproject]$ go build && ./myproject
{
"current": "Sat Aug 17 02:56:09 2019"
}
想要達到的效果:調用http.Get時,記錄一條日誌到標準輸出。
修改GO源碼:
我的GO源碼位置從上面的信息中可知是在“$HOME/go/src”,修改net/http/client.go中的Get函數:
func Get(url string) (resp *Response, err error) {
fmt.Println("test1280: call http.Get()")
return DefaultClient.Get(url)
}
備註:由於client.go中已import “fmt”,因此我添加的fmt.Println【內嵌的自定義邏輯】不需要再額外引入。
重新編譯GO項目:
[test1280@localhost myproject]$ go build && ./myproject
test1280: call http.Get()
{
"current": "Sat Aug 17 03:04:02 2019"
}
- 修改的是$HOME/go/src中的GO源碼;
- 重新編譯的是GO應用(GO工具鏈發現GO源碼有被修改,重新編譯GO源碼以及GO應用);
- 輸出將顯示在stdout、stderr;(默認情況下,例如重定向輸出例外)
如果你想要調試GO源碼,可像我一樣增加fmt.Print輸出信息,這樣你重新編譯GO程序,調試將顯示在終端。
如果你想要改變GO源碼,例如記錄HTTP請求/應答原始的報文,可將其內嵌到net/http等包中,記錄到日誌。