使用GoLand進(jìn)行調(diào)試1 - 入門

本文由Florin P??an于2019年2月6日發(fā)表

調(diào)試是任何現(xiàn)代應(yīng)用程序生命周期的重要組成部分浪听。它不僅有助于發(fā)現(xiàn)錯(cuò)誤窒所,因?yàn)槌绦騿T經(jīng)常使用調(diào)試器來(lái)查看和理解他們必須使用的新代碼庫(kù)或?qū)W習(xí)新語(yǔ)言時(shí)會(huì)發(fā)生什么。

人們更喜歡兩種調(diào)試方式:

  • print語(yǔ)句:在您的代碼執(zhí)行可能運(yùn)行的各個(gè)步驟時(shí)記錄
  • 直接或通過(guò)IDE 使用Delve之類的調(diào)試器:這可以更好地控制執(zhí)行流程磅轻,更多功能可以查看原始打印語(yǔ)句中可能未包含的代碼珍逸,甚至可以在應(yīng)用程序期間更改值運(yùn)行時(shí)或繼續(xù)執(zhí)行應(yīng)用程序。

在本系列中聋溜,我們將重點(diǎn)介紹第二個(gè)選項(xiàng)谆膳,使用IDE調(diào)試應(yīng)用程序。

正如您從上面的描述中注意到的那樣撮躁,這樣做提供了更多的控制和功能來(lái)查找錯(cuò)誤漱病,因此本文分為幾個(gè)部分:

  • 調(diào)試應(yīng)用程序
  • 調(diào)試測(cè)試
  • 調(diào)試本地計(jì)算機(jī)上正在運(yùn)行的應(yīng)用程序
  • 調(diào)試遠(yuǎn)程計(jì)算機(jī)上正在運(yùn)行的應(yīng)用程序

我們?cè)谙旅娼榻B這些場(chǎng)景,不論從哪里調(diào)試, 都會(huì)會(huì)提供以下功能

  • 調(diào)試的基礎(chǔ)知識(shí)
    1. 控制執(zhí)行流程
    2. 評(píng)估表達(dá)式
    3. 看自定義值
    4. 改變變量值
  • 使用斷點(diǎn)

IDE還支持調(diào)試在Linux上生成的核心轉(zhuǎn)儲(chǔ)以及在Linux上使用Mozilla的rr可逆調(diào)試器杨帽。我們將在即將發(fā)布的單獨(dú)博文中看到這些功能漓穿。

我們將在所有上述應(yīng)用程序中使用簡(jiǎn)單的Web服務(wù)器,但這些應(yīng)用程序可以應(yīng)用于任何類型的應(yīng)用程序注盈,CLI工具晃危,GUI應(yīng)用程序等。

我們將使用Go Modules老客,但使用任何其他依賴管理表單的默認(rèn)GOPATH也可以正常工作僚饭。

使用Go Modules(vgo)類型創(chuàng)建應(yīng)用程序,并確保您使用Go 1.11+或更高版本胧砰。
如果您沒(méi)有Go 1.11或想要使用GOPATH模式鳍鸵,請(qǐng)選擇Go

該應(yīng)用程序可以在下面找到:

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/gorilla/mux"
)

const (
    readTimeout  = 5
    writeTimeout = 10
    idleTimeout  = 120
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    returnStatus := http.StatusOK
    w.WriteHeader(returnStatus)
    message := fmt.Sprintf("Hello %s!", r.UserAgent())
    w.Write([]byte(message))
}

func main() {
    serverAddress := ":8080"
    l := log.New(os.Stdout, "sample-srv ", log.LstdFlags|log.Lshortfile)
    m := mux.NewRouter()

    m.HandleFunc("/", indexHandler)

    srv := &http.Server{
        Addr:         serverAddress,
        ReadTimeout:  readTimeout * time.Second,
        WriteTimeout: writeTimeout * time.Second,
        IdleTimeout:  idleTimeout * time.Second,
        Handler:      m,
    }

    l.Println("server started")
    if err := srv.ListenAndServe(); err != nil {
        panic(err)
    }
}

我們還可以創(chuàng)建一個(gè)這樣的測(cè)試文件:

package main
 
import (
    "net/http"
    "net/http/httptest"
    "testing"
)
 
func TestIndexHandler(t *testing.T) {
    tests := []struct {
        name           string
        r              *http.Request
        w              *httptest.ResponseRecorder
        expectedStatus int
    }{
        {
            name:           "good",
            r:              httptest.NewRequest("GET", "/", nil),
            w:              httptest.NewRecorder(),
            expectedStatus: http.StatusOK,
        },
    }
    for _, test := range tests {
        test := test
        t.Run(test.name, func(t *testing.T) {
            indexHandler(test.w, test.r)
            if test.w.Code != test.expectedStatus {
                t.Errorf("Failed to produce expected status code %d, got %d", test.expectedStatus, test.w.Code)
            }
        })
    }
}

我們應(yīng)該注意的最后一個(gè)信息是調(diào)試體驗(yàn)也受到用于編譯目標(biāo)程序的Go版本的影響朴则。隨著每個(gè)Go版本的發(fā)布权纤,Go團(tuán)隊(duì)致力于添加更多調(diào)試信息并提高現(xiàn)有版本的質(zhì)量,從舊版本(如Go 1.8)切換到Go 1.9或以更戲劇性的方式從轉(zhuǎn)1.8到Go 1.11乌妒。因此汹想,您可以使用的Go版本越新,您的體驗(yàn)就越好撤蚊。

現(xiàn)在我們所有的代碼都已到位古掏,讓我們開始調(diào)試它!

調(diào)試應(yīng)用程序

要調(diào)試應(yīng)用程序侦啸,我們可以單擊綠色三角形槽唾,然后選擇Debug'go build main.go'。
或者光涂,我們可以右鍵單擊文件夾并選擇Debug | go build <項(xiàng)目名稱>庞萍。

使用GoLand進(jìn)行調(diào)試 - 1

調(diào)試測(cè)試

這與調(diào)試應(yīng)用程序類似, Goland識(shí)別這些測(cè)試用例是標(biāo)準(zhǔn)的測(cè)試包, 忘闻,gocheck和測(cè)試框架钝计,所以這些測(cè)試可以從編輯器窗口直接運(yùn)行

至于其它測(cè)試框架,則需要編輯配置文件齐佳,或添加額外的參數(shù)私恬,具體取決于使用非標(biāo)準(zhǔn)包的參數(shù)。

使用GoLand進(jìn)行調(diào)試 - 2

在本地計(jì)算機(jī)上調(diào)試正在運(yùn)行的應(yīng)用程序

在某些情況下炼吴,您可能希望調(diào)試在IDE外部啟動(dòng)的應(yīng)用程序本鸣。

  • 其中一種情況是應(yīng)用程序在本地計(jì)算機(jī)上運(yùn)行。
    要使用調(diào)試器運(yùn)行它硅蹦,請(qǐng)?jiān)贗DE中打開項(xiàng)目荣德,然后選擇Attach to Process ...
    如果這是您第一次使用此功能闷煤,請(qǐng)下載一個(gè)名為gops的小型實(shí)用程序,可從https://github.com/google/gops下載命爬。該程序可幫助IDE找到在您的計(jì)算機(jī)上運(yùn)行的Go進(jìn)程曹傀。然后再次調(diào)用Attach to Process ...功能。
    或者從您計(jì)算上選一個(gè)已經(jīng)存在的項(xiàng)目饲宛,然后就可以開始下一步了。

為了確保調(diào)試能夠成功嗜价, 你必須要做的是編譯是為的程序添加一寫特殊的flag艇抠。goland將會(huì)自動(dòng)添加添加這些flag,因此僅在手動(dòng)編譯時(shí)久锥,才需要你來(lái)配置家淤。

要確保調(diào)試會(huì)話成功并且您可以毫無(wú)問(wèn)題地調(diào)試應(yīng)用程序,您需要做的就是使用特殊標(biāo)志編譯應(yīng)用程序瑟由。IDE將自動(dòng)為其他配置類型添加這些標(biāo)志絮重,因此僅在手動(dòng)編譯應(yīng)用程序時(shí)才需要這些標(biāo)志。

如果您使用Go 1.10或更高版本運(yùn)行歹苦,則需要添加-gcflags="all=-N -l"go build命令中青伤。

  go build -gcflags="all=-N -l"

如果您使用的是Go 1.9或更早版本,則需要添加-gcflags="-N -l"go build命令中殴瘦。

go build -gcflags="-N -l"

重要的提示狠角!有些人也使用-ldflags="all=-w"-ldflags="-w",這取決于使用的Go版本蚪腋。
但這與調(diào)試應(yīng)用程序不兼容丰歌,因?yàn)樗鼊h除了Delve工作所需的必要DWARF信息。因此屉凯,goland無(wú)法調(diào)試應(yīng)用程序立帖。在支持此功能的操作系統(tǒng)和文件系統(tǒng)上使用符號(hào)鏈接或符號(hào)鏈接時(shí),將遇到類似的問(wèn)題悠砚。由于Go工具鏈晓勇,Delve和IDE之間不兼容,使用符號(hào)鏈接目前與調(diào)試應(yīng)用程序不兼容哩簿。

使用GoLand進(jìn)行調(diào)試 - 3

在遠(yuǎn)程計(jì)算機(jī)上調(diào)試正在運(yùn)行的應(yīng)用程序

最后這種情況比較復(fù)雜宵蕉,這類調(diào)試允許goland調(diào)試遠(yuǎn)程主機(jī)上運(yùn)行的程序。通過(guò)遠(yuǎn)程調(diào)試节榜,我們可以在本地或云中考慮在本地計(jì)算機(jī)遠(yuǎn)程目標(biāo)或?qū)嶋H服務(wù)器上運(yùn)行的容器羡玛。
運(yùn)行遠(yuǎn)程調(diào)試,有一下幾點(diǎn)需要注意:

  • 與運(yùn)行本地計(jì)算機(jī)上運(yùn)行的應(yīng)用程序非常相似宗苍,您必須注意用于編譯應(yīng)用程序的編譯器標(biāo)志稼稿。
  • 使用相同的Go版本和主機(jī)/目標(biāo)編譯Delve薄榛,因?yàn)楦鞣N操作系統(tǒng)之間可能存在細(xì)微差別,這可能導(dǎo)致調(diào)試會(huì)話無(wú)法按預(yù)期工作让歼。
  • 如果使用 GOPATH敞恋,確保相同的GOPATH路徑
    例如:如果你的項(xiàng)目在github.com/JetBrains/go-sample可用,那么goland所在機(jī)器和程序運(yùn)行機(jī)器上谋右,應(yīng)用程序都在GOPATH / src / github.com / JetBrains下/ go-sample硬猫,GOPATH可以在這兩臺(tái)機(jī)器之間有所不同,goland可以自動(dòng)映射本地和遠(yuǎn)程計(jì)算機(jī)之間的目錄改执。

下一步啸蜜,在部署應(yīng)用程序時(shí),還要在遠(yuǎn)程服務(wù)器安裝相同的版本Delve辈挂。完成之后衬横,有兩種方法啟動(dòng)調(diào)試

  • 遠(yuǎn)程服務(wù)器上運(yùn)行命令:
    dlv --listen=:2345 --headless=true --api-version=2 exec ./application

  • 或者運(yùn)行命令:
    dlv --listen=:2345 --headless=true --api-version=2 attach <pid>
    其中<PID>是應(yīng)用程序的進(jìn)程ID。

以上兩步請(qǐng)注意防火墻開啟2345端口

完成所有這些操作后终蒂,編輯配置蜂林,監(jiān)聽(tīng)遠(yuǎn)程主機(jī)和端口,即可開始調(diào)試了拇泣。


配置遠(yuǎn)程調(diào)試
使用GoLand進(jìn)行調(diào)試 - 4

您可以使用以下Dockerfile中的容器來(lái)調(diào)試:

FROM golang:1.11.5-alpine3.8 AS build-env

ENV CGO_ENABLED 0

# Allow Go to retreive the dependencies for the build step
RUN apk add --no-cache git

WORKDIR /goland-debugging/
ADD . /goland-debugging/

RUN go build -o /goland-debugging/srv .

# Get Delve from a GOPATH not from a Go Modules project
WORKDIR /go/src/
RUN go get github.com/go-delve/delve/cmd/dlv

# final stage
FROM alpine:3.8

WORKDIR /
COPY --from=build-env /goland-debugging/srv /
COPY --from=build-env /go/bin/dlv /

EXPOSE 8080 40000

CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "exec", "/srv"]

請(qǐng)注意噪叙,在此Dockerfile中,項(xiàng)目名為goland-debugging挫酿,但您應(yīng)更改此文件夾名稱以匹配您創(chuàng)建的項(xiàng)目的名稱构眯。
運(yùn)行Docker容器時(shí),還需要為其指定--security-opt="apparmor=unconfined" --cap-add=SYS_PTRACE參數(shù)早龟。如果從命令行執(zhí)行此操作惫霸,則這些是docker run命令的參數(shù)。如果從IDE執(zhí)行此操作葱弟,則必須將這些選項(xiàng)放在“ 運(yùn)行選項(xiàng)”字段中壹店。

使用GoLand進(jìn)行調(diào)試 - 5

本文章翻譯自https://blog.jetbrains.com/go/2019/02/06/debugging-with-goland-getting-started
,本文譯者酌情量改動(dòng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芝加,隨后出現(xiàn)的幾起案子硅卢,更是在濱河造成了極大的恐慌,老刑警劉巖藏杖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件将塑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蝌麸,警方通過(guò)查閱死者的電腦和手機(jī)点寥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)来吩,“玉大人敢辩,你說(shuō)我怎么就攤上這事蔽莱。” “怎么了戚长?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵盗冷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我同廉,道長(zhǎng)仪糖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任迫肖,我火速辦了婚禮乓诽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咒程。我一直安慰自己,他們只是感情好讼育,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布帐姻。 她就那樣靜靜地躺著,像睡著了一般奶段。 火紅的嫁衣襯著肌膚如雪饥瓷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天痹籍,我揣著相機(jī)與錄音呢铆,去河邊找鬼。 笑死蹲缠,一個(gè)胖子當(dāng)著我的面吹牛棺克,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播线定,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼娜谊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了斤讥?” 一聲冷哼從身側(cè)響起纱皆,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芭商,沒(méi)想到半個(gè)月后派草,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铛楣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年近迁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛉艾。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钳踊,死狀恐怖衷敌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拓瞪,我是刑警寧澤缴罗,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站祭埂,受9級(jí)特大地震影響面氓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛆橡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一舌界、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泰演,春花似錦呻拌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至垃喊,卻和暖如春猾普,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背本谜。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工初家, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乌助。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓溜在,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親眷茁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子炕泳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. 分布式系統(tǒng)核心問(wèn)題 參考書籍:《區(qū)塊鏈原理、設(shè)計(jì)與應(yīng)用》 一致性問(wèn)題例子:兩個(gè)不同的電影院買同一種電影票上祈,如...
    molscar閱讀 905評(píng)論 0 0
  • windows下 golang 安裝與配置請(qǐng)參照:http://www.reibang.com/p/b6f34ae...
    molscar閱讀 2,113評(píng)論 0 7
  • 2018年1月16日 星期二晴天 我在西沽住了幾天培遵,我想妹妹了,是因?yàn)楹脦滋於紱](méi)看見(jiàn)她了登刺,今天我和爺爺奶奶...
    陳泉妡閱讀 1,035評(píng)論 0 1
  • 我們的印象中明星的所有動(dòng)作一定是完美的纸俭,一定比普通人美皇耗,也一定帥過(guò)普通人,所以自然而然大家一定覺(jué)得明星吃東西一定是...
    貍語(yǔ)閱讀 665評(píng)論 0 0
  • 今天臘月二十九揍很,明天就過(guò)年了郎楼,人們常把臘月二十九稱作“小除夕”万伤,這一天,大家往來(lái)拜訪叫做別歲呜袁。 民謠稱“二十九敌买,蒸...
    蘇易子閱讀 232評(píng)論 0 2