在C#中,执行程序可以使用以下命令检测它是否在调试器中运行:
System.Diagnostics.Debugger.IsAttached
Go中是否有同等效力?我有一些超时,我想在我踩过代码时被禁用。谢谢!
我正在使用GoLand调试器。
答案 0 :(得分:3)
据我所知,没有内置的方式以您描述的方式执行此操作。但是您可以使用构建标记来执行或多或少相同的操作,以指示delve调试器正在运行。您可以使用dlv
参数将构建标记传递给--build-flags
。这与我在How can I check if the race detector is enabled at runtime?
isdelve/delve.go
// +build delve
package isdelve
const Enabled = true
isdelve/nodelve.go
:
// +build !delve
package isdelve
const Enabled = false
a.go
:
package main
import (
"isdelve"
"fmt"
)
func main() {
fmt.Println("delve", isdelve.Enabled)
}
正在运行go run a.go
将报告delve false
并运行
dlv debug --build-flags='-tags=delve' a.go
会报告delve true
。
您必须在GoLand用户界面的某处传递该标志。我对GoLand并不熟悉,所以我无法专门帮助你解决这个问题。
或者,您可以使用delve的set
命令在启动调试器后手动设置变量。
答案 1 :(得分:1)
如果您假定使用的调试器是Delve,则可以检查Delve进程。至少要考虑两种情况(可能更多)。
os.Getppid()
来获取父进程的pid时,该进程将是Delve。os.Getpid()
的结果。这是基于以下假设:您没有找到运行与您的PID相匹配的旧PID的旧Delve。 (我忘记了操作系统重用PID的规则)。 请注意,1和2使用的os函数不同。一个获取父PID,另一个获取您的PID。
一些非常基本的代码要做1看起来像这样:
func isLaunchedByDebugger() bool {
// gops executable must be in the path. See https://github.com/google/gops
gopsOut, err := exec.Command("gops", strconv.Itoa(os.Getppid())).Output()
if err == nil && strings.Contains(string(gopsOut), "\\dlv.exe") {
// our parent process is (probably) the Delve debugger
return true
}
return false
}
答案 2 :(得分:0)
对于情况2,我们可以将程序设置为等待某些信号(SIGUSR1),并在此等待期间连接调试器。
main.go的代码可以像这样:
package main
import (
"os"
"os/signal"
"syscall"
"fmt"
"github.com/my/repo/cmd"
)
const (
waitForSignalEnv = "WAIT_FOR_DEBUGGER"
debuggerPort = "4321"
)
func main() {
// Waiting for debugger attach in case if waitForSignalEnv!=""
if os.Getenv(waitForSignalEnv) != "" {
sigs := make(chan os.Signal, 1)
goOn := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)
go func() {
sig := <-sigs
if sig == syscall.SIGUSR1 {
goOn <- true
} else if (sig == syscall.SIGTERM || sig == syscall.SIGINT ){
fmt.Printf("Exiting ...")
os.Exit(0)
}
}()
fmt.Printf("%s env is set, waiting SIGUSR1.\nYou can run remote debug in vscode and attach dlv debugger:\n\n", waitForSignalEnv)
pid := os.Getpid()
fmt.Printf("dlv attach --continue --accept-multiclient --headless --listen=:%s %d\n", debuggerPort, pid)
fmt.Printf("\nLaunch remote debugger in vscode to port %d and then give SIGUSR1 to the process\n", debuggerPort)
fmt.Printf("kill -SIGUSR1 %d\n", pid)
<-goOn
fmt.Printf("Continue ...")
}
cmd.Execute()
}
vscode的launch.json:
{
"name": "myprog-remote-debug",
"type": "go",
"request": "launch",
"remotePath": "${env:GOPATH}/src/github.com/my/repo",
"mode": "remote",
"port": 4321,
"host": "127.0.0.1",
"program": "${env:GOPATH}/src/github.com/my/repo",
"showLog": true,
"trace": "verbose"
}
说明: 例如,我们以env WAIT_FOR_DEBUGGER = true启动程序
export WAIT_FOR_DEBUGGER=true
./myprog -f values.yaml
它将输出dlv attach ...
命令和kill -SIGUSR <pid>
:
WAIT_FOR_DEBUGGER env is set, waiting SIGUSR1.
You can run remote debug in vscode and attach dlv debugger:
dlv attach --continue --accept-multiclient --headless --listen=:4321 556127
Launch remote debugger in vscode to port 4321 and then give SIGUSR1 to the process
kill -SIGUSR1 556127
运行上面的dlv attach ...
然后转到VS Code并运行myprog-remote-debug。在之前设置断点
然后给他kill -SIGUSR1 556127
断点将起作用
答案 3 :(得分:0)
在 Linux 上,您可以读取 /proc/self/status
文件以检索 TracerPid 字段,即调试器的 PID(如果有)。
func GetTracerPid() (int, error) {
file, err := os.Open("/proc/self/status")
if err != nil {
return -1, fmt.Errorf("can't open process status file: %w", err)
}
defer file.Close()
for {
var tpid int
num, err := fmt.Fscanf(file, "TracerPid: %d\n", &tpid)
if err == io.EOF {
break
}
if num != 0 {
return tpid, nil
}
}
return -1, errors.New("unknown format of process status file")
}
使用方法:
tpid, err := GetTracerPid()
if err != nil {
log.Println("something went wrong", err)
} else if tpid != 0 {
fmt.Println("we're under debugging: tracer_pid", tpid)
} else {
fmt.Println("we're free of tracing")
}