| name | debug-go |
| description | Go debugging best practices, tools, and techniques for effective troubleshooting. |
| version | 1.0.0 |
| author | magic |
| license | MIT |
| metadata | {"hermes":{"tags":["go","debugging","troubleshooting","delve"],"category":"software-development"}} |
Go Debugging Guide
Comprehensive guide to debugging Go applications using various tools and techniques.
When to Use
Load this skill when:
- Debugging Go application crashes or panics
- Investigating performance issues
- Setting up debugging environment
- Troubleshooting concurrency issues (goroutines, channels)
- Profiling memory or CPU usage
- Need to understand Go's debugging tools
Quick Reference
Delve (go-delve)
go install github.com/go-delve/delve/cmd/dlv@latest
dlv debug
dlv test ./...
dlv attach <pid>
dlv exec ./myapp
(dlv) break main.go:42
(dlv) continue
(dlv) next
(dlv) step
(dlv) print variable
(dlv) goroutines
Quick Debugging with fmt
fmt.Printf("DEBUG: value=%v, type=%T\n", value, value)
import "encoding/json"
func prettyPrint(v interface{}) {
b, _ := json.MarshalIndent(v, "", " ")
fmt.Println(string(b))
}
Debugging Tools
Delve (Recommended)
| Feature | Command |
|---|
| Set breakpoint | dlv break <file>:<line> |
| Conditional break | dlv cond <breakpoint> <condition> |
| View variables | dlv print <var> |
| Stack trace | dlv stack |
| Goroutines | dlv goroutines |
| Threads | dlv threads |
pprof (Profiling)
import _ "net/http/pprof"
go run main.go
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Common Debugging Techniques
1. Panic Recovery
func main() {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %v", r)
debug.PrintStack()
}
}()
riskyOperation()
}
2. Race Condition Detection
go run -race main.go
go test -race ./...
var counter int
go func() {
counter++ // Race condition!
}()
3. Deadlock Detection
import "runtime/debug"
func init() {
debug.SetGCPercent(-1)
}
4. HTTP Debugging
import "net/http/httputil"
func debugTransport() http.RoundTripper {
return &dumpTransport{}
}
type dumpTransport struct{}
func (d *dumpTransport) RoundTrip(req *http.Request) (*http.Response, error) {
dump, _ := httputil.DumpRequestOut(req, true)
fmt.Println(string(dump))
return http.DefaultTransport.RoundTrip(req)
}
IDE Integration
VS Code + Go Extension
- Set breakpoints by clicking gutter
- Launch debug: Run → Start Debugging (F5)
- Debug tests: Click "debug" above test function
- Variables pane shows local variables
- Call stack shows goroutine stack
GoLand (JetBrains)
- Full-featured debugger
- Evaluate expressions
- Conditional breakpoints
- Inline variable values
- Goroutine debugging view
Logging Best Practices
Use log/slog (Go 1.21+)
import "log/slog"
slog.Info("User logged in",
"user_id", userID,
"ip", ipAddress,
"duration", time.Since(start))
slog.Debug("Cache miss", "key", cacheKey)
logger := slog.With("request_id", requestID)
logger.Info("Processing request")
Log Levels
slog.SetLogLoggerLevel(slog.LevelDebug)
slog.SetLogLoggerLevel(slog.LevelInfo)
Pitfalls
Forgetting to Close Resources
Problem: File/connection leaks
Solution: Always use defer:
file, err := os.Open("file.txt")
if err != nil {
return err
}
defer file.Close()
Ignoring Errors
Problem: Silent failures
Solution: Always check errors:
doSomething()
if err := doSomething(); err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
Race Conditions
Problem: Concurrent access to shared state
Solution: Use channels or sync primitives:
var mu sync.Mutex
var counter int
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}
Verification
After setting up debugging:
dlv debug starts without errors
- Breakpoints hit correctly
- Variables inspectable with
print
go test -race passes
- pprof profiles accessible at
/debug/pprof/
Tools & References