Emacs에서 Golang 디버깅 마스터하기
소개
저는 Golang으로 개발을 시작한 이후로 디버거를 실제로 사용하지 않았습니다. 대신 나는 내 코드를 검증하기 위해 순진하게 fmt.Print 문을 모든 곳에 추가했습니다. 인쇄 문과 로그는 첫 번째 디버깅 본능일 수도 있지만 정교한 런타임 동작과 (물론!) 재현이 불가능해 보이는 복잡한 동시성 문제로 인해 크고 복잡한 코드 기반을 처리할 때 종종 부족합니다.
보다 복잡한 프로젝트 작업을 시작한 후(예: https://github.com/cloudoperators/heureka) delve(Golang 디버거)에 대해 더 자세히 살펴보고 Emacs가 무엇을 제공하는지 확인해야 했습니다. 그것과 상호 작용합니다. Go 생태계는 뛰어난 디버깅 도구를 제공하지만 이를 편안한 개발 워크플로에 통합하는 것은 어려울 수 있습니다.
이번 게시물에서는 Emacs, Delve 및 dape의 강력한 조합에 대해 자세히 설명하겠습니다. 이러한 도구를 함께 사용하면 Emacs의 유명한 유연성과 확장성을 유지하면서 기존 IDE를 모방하는(종종 능가하는) 디버깅 환경을 만들 수 있습니다.
다음과 같은 결과를 기대할 수 있습니다.
- dape를 사용하여 Delve 설정 및 구성
- 표준 애플리케이션과 Ginkgo 테스트를 모두 디버그합니다(현재 제가 사용하고 있는 것이 이것이죠?)
- Emacs 전용 사용자 정의로 디버깅 작업 흐름을 최적화하세요
개발 환경 설정
이 게시물에서는 여러분이 이미 Emacs 경험을 갖고 있으며 이제 패키지를 구성하고 작은 Elisp 스니펫을 작성하는 방법을 알고 있다고 가정합니다. 저는 개인적으로 Straight.el을 패키지 관리자로 사용하고,minimal-emacs.d를 최소 바닐라 Emacs 구성으로 사용하고(나만의 사용자 정의와 함께), dape를 디버그 어댑터 클라이언트로, eglot을 LSP 클라이언트로 사용합니다.
필수 Emacs 패키지
Emacs 29 사용자의 경우 eglot이 내장되어 있습니다. Gopls에 대한 eglot 구성 및 일부 고급 Gopls 설정을 확인하세요. 먼저 dape를 추가하겠습니다.
(use-package dape :straight t :config ;; Pulse source line (performance hit) (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line) ;; To not display info and/or buffers on startup ;; (remove-hook 'dape-start-hook 'dape-info) (remove-hook 'dape-start-hook 'dape-repl))
고 모드:
(use-package go-mode :straight t :mode "\.go\'" :hook ((before-save . gofmt-before-save)) :bind (:map go-mode-map ("M-?" . godoc-at-point) ("M-." . xref-find-definitions) ("M-_" . xref-find-references) ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump ("C-c m r" . go-run)) :custom (gofmt-command "goimports"))
필수 Go 도구 설치
LSP 서버인 Delve와 gopls를 설치하세요.
# Install Delve go install github.com/go-delve/delve/cmd/dlv@latest # Install gopls go install golang.org/x/tools/gopls@latest
또한 제가 가끔 사용하는 다른 도구도 많이 있습니다.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/onsi/ginkgo/v2/ginkgo@latest go install -v golang.org/x/tools/cmd/godoc@latest go install -v golang.org/x/tools/cmd/goimports@latest go install -v github.com/stamblerre/gocode@latest go install -v golang.org/x/tools/cmd/gorename@latest go install -v golang.org/x/tools/cmd/guru@latest go install -v github.com/cweill/gotests/...@latest go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest go install -v github.com/fatih/gomodifytags@latest go install -v github.com/godoctor/godoctor@latest go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest go install -v github.com/josharian/impl@latest go install -v github.com/rogpeppe/godef@latest
그런 다음 해당 Emacs 패키지를 구성해야 합니다.
(use-package ginkgo :straight (:type git :host github :repo "garslo/ginkgo-mode") :init (setq ginkgo-use-pwd-as-test-dir t ginkgo-use-default-keys t)) (use-package gotest :straight t :after go-mode :bind (:map go-mode-map ("C-c t f" . go-test-current-file) ("C-c t t" . go-test-current-test) ("C-c t j" . go-test-current-project) ("C-c t b" . go-test-current-benchmark) ("C-c t c" . go-test-current-coverage) ("C-c t x" . go-run))) (use-package go-guru :straight t :hook (go-mode . go-guru-hl-identifier-mode)) (use-package go-projectile :straight t :after (projectile go-mode)) (use-package flycheck-golangci-lint :straight t :hook (go-mode . flycheck-golangci-lint-setup)) (use-package go-eldoc :straight t :hook (go-mode . go-eldoc-setup)) (use-package go-tag :straight t :bind (:map go-mode-map ("C-c t a" . go-tag-add) ("C-c t r" . go-tag-remove)) :init (setq go-tag-args (list "-transform" "camelcase"))) (use-package go-fill-struct :straight t) (use-package go-impl :straight t) (use-package go-playground :straight t)
데이프 구성
dap 대신 dape를 사용하는 특별한 이유는 없습니다. 내가 여전히 MinEmacs를 사용하고 있을 때 그것은 그것의 일부였고 나는 그것에 익숙해졌습니다. 문서에 따르면:
- Dape는 launch.json 파일을 지원하지 않습니다. 프로젝트별 구성이 필요한 경우 dir-locals 및 dape-command를 사용하세요.
- Dape는 사용자가 옵션을 사용하여 기존 구성에 PLIST 항목을 수정하거나 추가할 수 있도록 하여 미니버퍼 내의 인체공학성을 향상시킵니다.
- 마법도 없고 ${workspaceFolder}와 같은 특수 변수도 없습니다. 대신 새 세션을 시작하기 전에 함수와 변수가 해결됩니다.
- vscode가 존재하지 않는 경우 Emacs에서 디버그 어댑터 구성이 어떻게 구현될지 상상해 봅니다.
VSCode를 사용해 본 적이 있다면 이 VSCode가 다양한 디버깅 프로필을 저장하기 위해 launch.json을 사용한다는 사실을 이미 알고 계실 것입니다.
(use-package dape :straight t :config ;; Pulse source line (performance hit) (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line) ;; To not display info and/or buffers on startup ;; (remove-hook 'dape-start-hook 'dape-info) (remove-hook 'dape-start-hook 'dape-repl))
이 페이지에 따라 디버깅 구성에서 조정할 수 있는 다양한 필드/속성이 있습니다.
Property | Description |
---|---|
name | Name for your configuration that appears in the drop down in the Debug viewlet |
type | Always set to "go". This is used by VS Code to figure out which extension should be used for debugging your code |
request | Either of launch or attach. Use attach when you want to attach to an already running process |
mode | For launch requests, either of auto, debug, remote, test, exec. For attach requests, use either local or remote |
program | Absolute path to the package or file to debug when in debug & test mode, or to the pre-built binary file to debug in exec mode |
env | Environment variables to use when debugging. Example: { "ENVNAME": "ENVVALUE" } |
envFile | Absolute path to a file containing environment variable definitions |
args | Array of command line arguments that will be passed to the program being debugged |
showLog | Boolean indicating if logs from delve should be printed in the debug console |
logOutput | Comma separated list of delve components for debug output |
buildFlags | Build flags to be passed to the Go compiler |
remotePath | Absolute path to the file being debugged on the remote machine |
processId | ID of the process that needs debugging (for attach request with local mode) |
샘플 애플리케이션
이제 REST API를 구현한 실제 애플리케이션을 디버깅하여 우리가 배운 내용을 실제로 적용해 보겠습니다.
프로젝트 구조
우리의 예는 다음 구조를 가진 작업 관리용 REST API입니다.
(use-package dape :straight t :config ;; Pulse source line (performance hit) (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line) ;; To not display info and/or buffers on startup ;; (remove-hook 'dape-start-hook 'dape-info) (remove-hook 'dape-start-hook 'dape-repl))
핵심 구성요소
핵심 구성요소를 살펴보겠습니다.
작업은 핵심 도메인 모델을 나타냅니다.
(use-package go-mode :straight t :mode "\.go\'" :hook ((before-save . gofmt-before-save)) :bind (:map go-mode-map ("M-?" . godoc-at-point) ("M-." . xref-find-definitions) ("M-_" . xref-find-references) ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump ("C-c m r" . go-run)) :custom (gofmt-command "goimports"))
TaskStore는 메모리 내 데이터 작업을 처리합니다.
# Install Delve go install github.com/go-delve/delve/cmd/dlv@latest # Install gopls go install golang.org/x/tools/gopls@latest
REST API
API는 다음 엔드포인트를 노출합니다.
- POST /task/create - 새 작업을 생성합니다
-
GET /task/get?id=
- ID로 작업을 검색합니다.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/onsi/ginkgo/v2/ginkgo@latest go install -v golang.org/x/tools/cmd/godoc@latest go install -v golang.org/x/tools/cmd/goimports@latest go install -v github.com/stamblerre/gocode@latest go install -v golang.org/x/tools/cmd/gorename@latest go install -v golang.org/x/tools/cmd/guru@latest go install -v github.com/cweill/gotests/...@latest go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest go install -v github.com/fatih/gomodifytags@latest go install -v github.com/godoctor/godoctor@latest go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest go install -v github.com/josharian/impl@latest go install -v github.com/rogpeppe/godef@latest
섬기는 사람
서버 구현은 다음과 같습니다.
(use-package ginkgo :straight (:type git :host github :repo "garslo/ginkgo-mode") :init (setq ginkgo-use-pwd-as-test-dir t ginkgo-use-default-keys t)) (use-package gotest :straight t :after go-mode :bind (:map go-mode-map ("C-c t f" . go-test-current-file) ("C-c t t" . go-test-current-test) ("C-c t j" . go-test-current-project) ("C-c t b" . go-test-current-benchmark) ("C-c t c" . go-test-current-coverage) ("C-c t x" . go-run))) (use-package go-guru :straight t :hook (go-mode . go-guru-hl-identifier-mode)) (use-package go-projectile :straight t :after (projectile go-mode)) (use-package flycheck-golangci-lint :straight t :hook (go-mode . flycheck-golangci-lint-setup)) (use-package go-eldoc :straight t :hook (go-mode . go-eldoc-setup)) (use-package go-tag :straight t :bind (:map go-mode-map ("C-c t a" . go-tag-add) ("C-c t r" . go-tag-remove)) :init (setq go-tag-args (list "-transform" "camelcase"))) (use-package go-fill-struct :straight t) (use-package go-impl :straight t) (use-package go-playground :straight t)
주요 기능을 살펴보겠습니다.
{ "name": "Launch file", "type": "go", "request": "launch", "mode": "auto", "program": "${file}" }
애플리케이션 구축
서버를 시작해 보겠습니다.
taskapi/ ├── go.mod ├── go.sum ├── main.go ├── task_store.go └── task_test.go
이제 다른 터미널에서 새 작업을 생성하세요:
import ( "fmt" ) type Task struct { ID int `json:"id"` Title string `json:"title"` Description string `json:"description"` Done bool `json:"done"` }
응답:
type TaskStore struct { tasks map[int]Task nextID int } func NewTaskStore() *TaskStore { return &TaskStore{ tasks: make(map[int]Task), nextID: 1, } }
가져올 수 있는지 살펴보겠습니다.
// CreateTask stores a given Task internally func (ts *TaskStore) CreateTask(task Task) Task { task.ID = ts.nextID ts.tasks[task.ID] = task ts.nextID++ return task } // GetTask retrieves a Task by ID func (ts *TaskStore) GetTask(id int) (Task, error) { task, exists := ts.tasks[id] if !exists { return Task{}, fmt.Errorf("task with id %d not found", id) } return task, nil } // UpdateTask updates task ID with a new Task object func (ts *TaskStore) UpdateTask(id int, task Task) error { if _, exists := ts.tasks[id]; !exists { return fmt.Errorf("task with id %d not found", id) } task.ID = id ts.tasks[id] = task return nil }
응답:
package main import ( "encoding/json" "fmt" "net/http" ) // Server implements a web application for managing tasks type Server struct { store *TaskStore } func (s *Server) handleCreateTask(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var task Task if err := json.NewDecoder(r.Body).Decode(&task); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } createdTask := s.store.CreateTask(task) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(createdTask) } func (s *Server) handleGetTask(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } id := 0 fmt.Sscanf(r.URL.Query().Get("id"), "%d", &id) task, err := s.store.GetTask(id) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(task) }
단위 테스트
다음은 TaskStore에 대한 몇 가지 단위 테스트(Ginkgo로 작성)입니다.
package main import ( "log" "net/http" ) func main() { store := NewTaskStore() server := &Server{store: store} http.HandleFunc("/task/create", server.handleCreateTask) http.HandleFunc("/task/get", server.handleGetTask) log.Printf("Starting server on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
go build -o taskapi *.go ./taskapi 2024/11/14 07:03:48 Starting server on :8080
Emacs에서는 다음 스크린샷과 같이 ginkgo-run-this-container를 호출합니다.
Delve 및 Dape를 사용한 기본 디버깅
Task API를 디버깅하기 위해 다음과 같은 접근 방식이 있습니다.
- 애플리케이션을 직접 실행하고 디버그할 수 있습니다
- 실행 중인 프로세스에 연결할 수 있습니다
- 실행 중인 디버깅 세션에 연결할 수 있습니다
다양한 요청 유형에 대한 옵션은 다음과 같습니다.
request | mode | required | optional |
---|---|---|---|
launch | debug | program | dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug |
test | program | dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug | |
exec | program | dlvCwd, env, backend, args, cwd, noDebug | |
core | program, corefilePath | dlvCwd, env | |
replay | traceDirPath | dlvCwd, env | |
attach | local | processId | backend |
remote |
프로필 1: 애플리케이션 실행
다음은 .dir-locals.el에 대한 첫 번째 디버깅 프로필입니다.
(use-package dape :straight t :config ;; Pulse source line (performance hit) (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line) ;; To not display info and/or buffers on startup ;; (remove-hook 'dape-start-hook 'dape-info) (remove-hook 'dape-start-hook 'dape-repl))
? command-cwd에 다른 값을 사용할 수도 있습니다. 내 경우에는 현재 프로젝트가 아닌 디렉터리에서 디버거를 시작하고 싶었습니다. default-directory는 현재 있는 현재 버퍼의 작업 디렉토리를 보유하는 변수입니다.
디버깅 시작:
- dape-info를 실행하여 디버깅 정보 표시
- dape-breakpoint-toggle을 사용하여 중단점 만들기:
이 프로필로 디버거를 시작한 후 dape-repl 버퍼에 다음이 표시되어야 합니다.
(use-package go-mode :straight t :mode "\.go\'" :hook ((before-save . gofmt-before-save)) :bind (:map go-mode-map ("M-?" . godoc-at-point) ("M-." . xref-find-definitions) ("M-_" . xref-find-references) ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump ("C-c m r" . go-run)) :custom (gofmt-command "goimports"))
디버깅할 바이너리/파일을 지정하지 않았습니다(.dir-locals.el에 :program "."가 있음). delve는 애플리케이션을 시작하기 전에 바이너리를 자동으로 빌드합니다.
# Install Delve go install github.com/go-delve/delve/cmd/dlv@latest # Install gopls go install golang.org/x/tools/gopls@latest
프로필 2: 외부 디버거에 연결
기존 디버깅 세션에 연결하기 위한 프로필을 추가해 보겠습니다.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/onsi/ginkgo/v2/ginkgo@latest go install -v golang.org/x/tools/cmd/godoc@latest go install -v golang.org/x/tools/cmd/goimports@latest go install -v github.com/stamblerre/gocode@latest go install -v golang.org/x/tools/cmd/gorename@latest go install -v golang.org/x/tools/cmd/guru@latest go install -v github.com/cweill/gotests/...@latest go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest go install -v github.com/fatih/gomodifytags@latest go install -v github.com/godoctor/godoctor@latest go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest go install -v github.com/josharian/impl@latest go install -v github.com/rogpeppe/godef@latest
이제 CLI에서 디버거를 시작해 보겠습니다.
(use-package ginkgo :straight (:type git :host github :repo "garslo/ginkgo-mode") :init (setq ginkgo-use-pwd-as-test-dir t ginkgo-use-default-keys t)) (use-package gotest :straight t :after go-mode :bind (:map go-mode-map ("C-c t f" . go-test-current-file) ("C-c t t" . go-test-current-test) ("C-c t j" . go-test-current-project) ("C-c t b" . go-test-current-benchmark) ("C-c t c" . go-test-current-coverage) ("C-c t x" . go-run))) (use-package go-guru :straight t :hook (go-mode . go-guru-hl-identifier-mode)) (use-package go-projectile :straight t :after (projectile go-mode)) (use-package flycheck-golangci-lint :straight t :hook (go-mode . flycheck-golangci-lint-setup)) (use-package go-eldoc :straight t :hook (go-mode . go-eldoc-setup)) (use-package go-tag :straight t :bind (:map go-mode-map ("C-c t a" . go-tag-add) ("C-c t r" . go-tag-remove)) :init (setq go-tag-args (list "-transform" "camelcase"))) (use-package go-fill-struct :straight t) (use-package go-impl :straight t) (use-package go-playground :straight t)
이제 Emacs 내에서 dape를 실행하고 go-attach-taskapi 프로필을 선택할 수 있습니다.
프로필 3: 실행 중인 프로세스에 연결
이 시나리오에서는 애플리케이션이 이미 실행 중이지만 여기에 디버거를 연결하려고 합니다. 먼저 애플리케이션을 실행하세요:
{ "name": "Launch file", "type": "go", "request": "launch", "mode": "auto", "program": "${file}" }
프로세스 ID(PID) 확인:
taskapi/ ├── go.mod ├── go.sum ├── main.go ├── task_store.go └── task_test.go
다른 디버그 프로필을 추가해 보겠습니다.
import ( "fmt" ) type Task struct { ID int `json:"id"` Title string `json:"title"` Description string `json:"description"` Done bool `json:"done"` }
도우미 기능이 필요합니다:
type TaskStore struct { tasks map[int]Task nextID int } func NewTaskStore() *TaskStore { return &TaskStore{ tasks: make(map[int]Task), nextID: 1, } }
이제 디버거를 시작합니다.
이제 다음과 같은 POST 요청을 보내는 경우:
// CreateTask stores a given Task internally func (ts *TaskStore) CreateTask(task Task) Task { task.ID = ts.nextID ts.tasks[task.ID] = task ts.nextID++ return task } // GetTask retrieves a Task by ID func (ts *TaskStore) GetTask(id int) (Task, error) { task, exists := ts.tasks[id] if !exists { return Task{}, fmt.Errorf("task with id %d not found", id) } return task, nil } // UpdateTask updates task ID with a new Task object func (ts *TaskStore) UpdateTask(id int, task Task) error { if _, exists := ts.tasks[id]; !exists { return fmt.Errorf("task with id %d not found", id) } task.ID = id ts.tasks[id] = task return nil }
디버거는 설정된 중단점에서 자동으로 중지되어야 합니다.
Ginkgo 테스트 디버깅
Golang에서 테스트를 디버그할 수 있는 능력은 매우 중요합니다. 은행나무 테스트를 실행하기 위해 다음과 같은 여러 기능이 있는 은행나무 모드를 사용합니다.
그리고 결과는 다음과 같습니다.
(use-package dape :straight t :config ;; Pulse source line (performance hit) (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line) ;; To not display info and/or buffers on startup ;; (remove-hook 'dape-start-hook 'dape-info) (remove-hook 'dape-start-hook 'dape-repl))
Ginkgo용 Dape 구성
Ginkgo 테스트 디버깅을 위한 기본 구성은 다음과 같습니다.
(use-package go-mode :straight t :mode "\.go\'" :hook ((before-save . gofmt-before-save)) :bind (:map go-mode-map ("M-?" . godoc-at-point) ("M-." . xref-find-definitions) ("M-_" . xref-find-references) ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump ("C-c m r" . go-run)) :custom (gofmt-command "goimports"))
go-test-ginkgo 디버그 프로필을 선택하면 테스트를 디버그할 수 있습니다.
이제 구성은 매우 정적이므로 단위 테스트/컨테이너를 미리 선택할 수 없습니다. 어떻게든 -ginkgo.focus 매개변수를 동적으로 만들어야 합니다.
# Install Delve go install github.com/go-delve/delve/cmd/dlv@latest # Install gopls go install golang.org/x/tools/gopls@latest
나중에 dape-configs 변수를 살펴보면 다음 값이 표시됩니다.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install github.com/onsi/ginkgo/v2/ginkgo@latest go install -v golang.org/x/tools/cmd/godoc@latest go install -v golang.org/x/tools/cmd/goimports@latest go install -v github.com/stamblerre/gocode@latest go install -v golang.org/x/tools/cmd/gorename@latest go install -v golang.org/x/tools/cmd/guru@latest go install -v github.com/cweill/gotests/...@latest go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest go install -v github.com/fatih/gomodifytags@latest go install -v github.com/godoctor/godoctor@latest go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest go install -v github.com/josharian/impl@latest go install -v github.com/rogpeppe/godef@latest
dape-repl 버퍼에서 디버거(디버그 중심 테스트 프로필 사용)를 시작한 후 다음을 얻습니다.
(use-package ginkgo :straight (:type git :host github :repo "garslo/ginkgo-mode") :init (setq ginkgo-use-pwd-as-test-dir t ginkgo-use-default-keys t)) (use-package gotest :straight t :after go-mode :bind (:map go-mode-map ("C-c t f" . go-test-current-file) ("C-c t t" . go-test-current-test) ("C-c t j" . go-test-current-project) ("C-c t b" . go-test-current-benchmark) ("C-c t c" . go-test-current-coverage) ("C-c t x" . go-run))) (use-package go-guru :straight t :hook (go-mode . go-guru-hl-identifier-mode)) (use-package go-projectile :straight t :after (projectile go-mode)) (use-package flycheck-golangci-lint :straight t :hook (go-mode . flycheck-golangci-lint-setup)) (use-package go-eldoc :straight t :hook (go-mode . go-eldoc-setup)) (use-package go-tag :straight t :bind (:map go-mode-map ("C-c t a" . go-tag-add) ("C-c t r" . go-tag-remove)) :init (setq go-tag-args (list "-transform" "camelcase"))) (use-package go-fill-struct :straight t) (use-package go-impl :straight t) (use-package go-playground :straight t)
?"5개 사양 중 1개"(❶)만 실행되었다는 점에 주목하세요. 이는 ginkgo가 우리가 지정한 컨테이너(❷)에만 집중했다는 의미입니다.
모범 사례 및 팁
디버깅 경험을 통해 다음과 같은 몇 가지 모범 사례를 알게 되었습니다.
- 디버깅 구성에 버전 제어 사용
- .dir-locals.el에서 디버그 구성을 유지합니다.
- 구성에 의미 있는 이름을 사용하세요
- 프로젝트별 디버깅 도우미 기능 생성
- 로컬에서 사용자 정의(버퍼별)
리소스 및 참고 자료
- 마스터의 vscode-go/docs/debugging.md · golang/vscode-go
- delve/dlv dap-mode 직접 지원 · Issue #318 · emacs-lsp/dap-mode
- Dape GitHub 저장소
- Delve 디버거
- Eglot 문서
- 은행나무 테스트 프레임워크
위 내용은 Emacs에서 Golang 디버깅 마스터하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











보안 통신에 널리 사용되는 오픈 소스 라이브러리로서 OpenSSL은 암호화 알고리즘, 키 및 인증서 관리 기능을 제공합니다. 그러나 역사적 버전에는 알려진 보안 취약점이 있으며 그 중 일부는 매우 유해합니다. 이 기사는 데비안 시스템의 OpenSSL에 대한 일반적인 취약점 및 응답 측정에 중점을 둘 것입니다. DebianopensSL 알려진 취약점 : OpenSSL은 다음과 같은 몇 가지 심각한 취약점을 경험했습니다. 심장 출혈 취약성 (CVE-2014-0160) :이 취약점은 OpenSSL 1.0.1 ~ 1.0.1F 및 1.0.2 ~ 1.0.2 베타 버전에 영향을 미칩니다. 공격자는이 취약점을 사용하여 암호화 키 등을 포함하여 서버에서 무단 읽기 민감한 정보를 사용할 수 있습니다.

백엔드 학습 경로 : 프론트 엔드에서 백엔드 초보자로서 프론트 엔드에서 백엔드까지의 탐사 여행은 프론트 엔드 개발에서 변화하는 백엔드 초보자로서 이미 Nodejs의 기초를 가지고 있습니다.

Beegoorm 프레임 워크에서 모델과 관련된 데이터베이스를 지정하는 방법은 무엇입니까? 많은 Beego 프로젝트에서는 여러 데이터베이스를 동시에 작동해야합니다. Beego를 사용할 때 ...

Go Crawler Colly의 대기열 스레딩 문제는 Colly Crawler 라이브러리를 GO 언어로 사용하는 문제를 탐구합니다. � ...

Go Language의 부동 소수점 번호 작동에 사용되는 라이브러리는 정확도를 보장하는 방법을 소개합니다.

Go Language에서 메시지 대기열을 구현하기 위해 Redisstream을 사용하는 문제는 Go Language와 Redis를 사용하는 것입니다 ...

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Go Language 개발을 위해 Goland를 사용할 때 많은 개발자가 사용자 정의 구조 태그를 만날 것입니다 ...

Go Language의 문자열 인쇄의 차이 : println 및 String () 함수 사용 효과의 차이가 진행 중입니다 ...
