golang-processがクラッシュした後にエラーログを出力する方法は?
バックグラウンド
——————————————————————————————
2020年4月22日に更新され、コアダンプサンプルコードを有効にするためにdamonプロセスを追加します
———— ———————————————————————————
前回の記事:https://blog.csdn.net/xmcy001122/article/details/103743249はgolangを使用してエレガントな終了機能を実現しています。
最近、オンラインプログラムでプロセスがクラッシュしたため、Du Niangはエラースタックを出力するための延期コードを追加しました。半日実行した後、プロセスが終了したことがわかりましたが、ログにエラーはありませんでした。そのため、テストを繰り返し、最終的に問題を発見しました。
問題のあるコード:
func main(){
// ... 业务逻辑
// 崩溃的时候,这段代码没有执行
defer func() {
// 如果是崩溃导致的信号,打印错误
err := recover()
if err != nil {
logger.Sugar.Error(err)
}
}()
// 优雅退出
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
waitExit(c)
}
func waitExit(c chan os.Signal) {
for i := range c {
switch i {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
_ = logger.Sugar.Sync()
logger.Sugar.Info("exit...")
os.Exit(1)
}
}
}
実行中、シミュレーションがクラッシュし、エラーがgoland IDEに出力されますが、ログにはエラー出力がありません。
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x13a79af]
goroutine 36 [running]:
robot_server/internal.(*RouteServerConn).onHandleMsgJoinNotify(0xc0001640d0, 0xc00000e700, 0xc0001a6010, 0xc, 0x27f0)
/Users/xuyc/repo/zhaogang.com/go/src/robot_server/internal/route_server_conn.go:92 +0x15f
robot_server/internal.(*RouteServerConn).onHandleData(0xc0001640d0, 0xc00000e700, 0xc0001a6010, 0xc, 0x27f0)
/Users/xuyc/repo/zhaogang.com/go/src/robot_server/internal/route_server_conn.go:65 +0x148
robot_server/base.(*ImClient).NetLoop(0xc0000b4180, 0xc0001ea000, 0x149ab3b)
/Users/xuyc/repo/zhaogang.com/go/src/robot_server/base/im_client.go:168 +0x1f6
robot_server/internal.read(0xc0001640d0, 0xc00016c0f0, 0xb, 0xc0001a200a)
/Users/xuyc/repo/zhaogang.com/go/src/robot_server/internal/route_server_conn.go:41 +0x3f1
created by robot_server/internal.(*RouteServerConn).Start
/Users/xuyc/repo/zhaogang.com/go/src/robot_server/internal/route_server_conn.go:26 +0x5d
Process finished with exit code 2
解決
さまざまな方法を試し、最終的にシステムを使用してコアダンプファイルを生成しました。
コアダンプを有効にする
1. coredump.shを作成し、次のように記述します。
#!/bin/bash
# Filename: coredumpshell.sh
# Description: enable coredump and format the name of core file on centos system
# enable coredump whith unlimited file-size for all users
echo -e "\n# enable coredump whith unlimited file-size for all users\n* soft core unlimited" >> /etc/security/limits.conf
# set the path of core file with permission 777
cd /data && mkdir imcorefile && chmod 777 imcorefile
# format the name of core file.
# %% – 符号%
# %p – 进程号
# %u – 进程用户id
# %g – 进程用户组id
# %s – 生成core文件时收到的信号
# %t – 生成core文件的时间戳(seconds since 0:00h, 1 Jan 1970)
# %h – 主机名
# %e – 程序文件名
# for centos7 system(update 2017.4.2 21:44)
echo -e "\nkernel.core_pattern=/data/imcorefile/core-%e-%s-%u-%g-%p-%t" >> /etc/sysctl.conf
echo -e "\nkernel.core_uses_pid = 1" >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
2.コアダンプ機能を永続的に有効にします
chmod 777 coredump.sh
./coredump.sh
# 重新打开终端
ulimit -a
次の出力は成功を表してい
ます。3。検証(省略することはお勧めしません)
vim test.c
次のように入力します:
#include <stdio.h>
int main( int argc, char * argv[] ) { char a[1]; scanf( "%s", a ); return 0; }
gcc test.c -o test # 编译
./test # 执行test,然后任意输入一串字符后按回车,如zhaogang.com
ls /data/corefile # 在此目录下如果生成了相应的core文件core-test-*,代表成功
実行
上記の設定に従った後、プロセスの前にenv GOTRACEBACK = crashを追加します。
env GOTRACEBACK=crash ./robot_server
プロセスがクラッシュした場合、コアファイルは/ data / imcorefileに生成されます。次に例を示します。
[root@10-0-59-229 imcorefile]# ls
core-robot_server-6-0-0-25365-1587471512
PS:GOTRACEBACKについては、Goを参照してください-GOTRACEBACK(gcore gdb)を介してプログラムがクラッシュした後にコアファイルを生成する方法
デバッグ
gdb
gdb robot_server ../imcorefile/core-robot_server-6-0-0-25365-1587471512
出力:
(gdb) bt # bt查看错误堆栈
#0 runtime.raise () at /usr/local/go/src/runtime/sys_linux_amd64.s:150
#1 0x00000000004405bb in runtime.dieFromSignal (sig=6) at /usr/local/go/src/runtime/signal_unix.go:424
#2 0x0000000000440b3d in runtime.sigfwdgo (sig=6, info=0xc00015fd70, ctx=0xc00015fc40, ~r3=<optimized out>)
at /usr/local/go/src/runtime/signal_unix.go:629
#3 0x000000000043fc60 in runtime.sigtrampgo (sig=<optimized out>, info=0xc00015fd70, ctx=0xc00015fc40)
at /usr/local/go/src/runtime/signal_unix.go:289
#4 0x0000000000459d43 in runtime.sigtramp () at /usr/local/go/src/runtime/sys_linux_amd64.s:357
#5 0x0000000000459e30 in ?? () at /usr/local/go/src/runtime/sys_linux_amd64.s:441
#6 0x0000000000000000 in ?? ()
(gdb) eixt
Undefined command: "eixt". Try "help".
(gdb)
Undefined command: "eixt". Try "help".
(gdb) quit # 退出
結論:コアファイルは生成されますが、特定のエラーは見られないため、掘り下げツールを使用する必要があります。
掘り下げる
1.インストール
go get -u github.com/derekparker/delve/cmd/dlv
go env # 查看 GOPATH="/home/go"
[root@10-0-59-229 robot-server.2020-04-14]# cd /home/go/
[root@10-0-59-229 go]# ls
bin src
[root@10-0-59-229 go]# cd bin
[root@10-0-59-229 bin]# ls
dlv
[root@10-0-59-229 bin]# cp dlv /usr/bin/ # 这样就可以直接使用dlv命令了
cp:是否覆盖"/usr/bin/dlv"? y
[root@10-0-59-229 bin]# dlv # 使用dlv命令
2.デバッグ
形式:dlv core <executable> <core> [flags]
[root@10-0-59-231 robot-server.2020-04-22]# dlv core robot_server /data/imcorefile/core-robot_server-6-0-0-32402-1587555657
Type 'help' for list of commands.
(dlv)
(dlv)
(dlv) bt # 先使用bt显示错误堆栈
0 0x0000000000459be1 in runtime.raise
at /usr/local/go/src/runtime/sys_linux_amd64.s:150
1 0x000000000044074b in runtime.dieFromSignal
at /usr/local/go/src/runtime/signal_unix.go:424
2 0x0000000000440ccd in runtime.sigfwdgo
at /usr/local/go/src/runtime/signal_unix.go:629
3 0x000000000043fdf0 in runtime.sigtrampgo
at /usr/local/go/src/runtime/signal_unix.go:289
4 0x0000000000459ed3 in runtime.sigtramp
at /usr/local/go/src/runtime/sys_linux_amd64.s:357
5 0x0000000000459fc0 in runtime.sigreturn
at /usr/local/go/src/runtime/sys_linux_amd64.s:449
6 0x00000000004408ea in runtime.crash
at /usr/local/go/src/runtime/signal_unix.go:518
7 0x000000000042c1a4 in runtime.fatalpanic
at /usr/local/go/src/runtime/panic.go:717
8 0x000000000042bb55 in runtime.gopanic
at /usr/local/go/src/runtime/panic.go:565
9 0x0000000000440661 in runtime.panicmem
at /usr/local/go/src/runtime/panic.go:82
10 0x0000000000440661 in runtime.sigpanic
at /usr/local/go/src/runtime/signal_unix.go:390
11 0x00000000007aba4f in robot_server/internal.(*RouteServerConn).onHandleMsgJoinNotify
at /home/go/src/robot_server/internal/route_server_conn.go:97
12 0x00000000007ab598 in robot_server/internal.(*RouteServerConn).onHandleData
at /home/go/src/robot_server/internal/route_server_conn.go:65
13 0x00000000007aebd2 in robot_server/internal.(*RouteServerConn).onHandleData-fm
at /home/go/src/robot_server/internal/route_server_conn.go:60
14 0x000000000079bff6 in robot_server/base.(*ImClient).NetLoop
at /home/go/src/robot_server/base/im_client.go:168
15 0x00000000007ab3e1 in robot_server/internal.read
at /home/go/src/robot_server/internal/route_server_conn.go:41
16 0x00000000004582d1 in runtime.goexit
at /usr/local/go/src/runtime/asm_amd64.s:1337
上の図に示すように、エラーの場所は11行目にあります。
11 0x00000000007aba4f in robot_server/internal.(*RouteServerConn).onHandleMsgJoinNotify
at /home/go/src/robot_server/internal/route_server_conn.go:97
実行中のマシンにコードがある場合(プロセスファイルとコアファイルをコンパイルマシンにテストして表示することもできます)、特定のエラー行を表示できます。
[root@10-0-59-231 robot-server.2020-04-22]# dlv core robot_server /data/imcorefile/core-robot_server-6-0-0-32402-1587555657
Type 'help' for list of commands.
(dlv)
(dlv)
(dlv) bt # 先使用bt显示错误堆栈
0 0x0000000000459be1 in runtime.raise
at /usr/local/go/src/runtime/sys_linux_amd64.s:150
1 0x000000000044074b in runtime.dieFromSignal
at /usr/local/go/src/runtime/signal_unix.go:424
2 0x0000000000440ccd in runtime.sigfwdgo
at /usr/local/go/src/runtime/signal_unix.go:629
3 0x000000000043fdf0 in runtime.sigtrampgo
at /usr/local/go/src/runtime/signal_unix.go:289
4 0x0000000000459ed3 in runtime.sigtramp
at /usr/local/go/src/runtime/sys_linux_amd64.s:357
5 0x0000000000459fc0 in runtime.sigreturn
at /usr/local/go/src/runtime/sys_linux_amd64.s:449
6 0x00000000004408ea in runtime.crash
at /usr/local/go/src/runtime/signal_unix.go:518
7 0x000000000042c1a4 in runtime.fatalpanic
at /usr/local/go/src/runtime/panic.go:717
8 0x000000000042bb55 in runtime.gopanic
at /usr/local/go/src/runtime/panic.go:565
9 0x0000000000440661 in runtime.panicmem
at /usr/local/go/src/runtime/panic.go:82
10 0x0000000000440661 in runtime.sigpanic
at /usr/local/go/src/runtime/signal_unix.go:390
11 0x00000000007aba4f in robot_server/internal.(*RouteServerConn).onHandleMsgJoinNotify
at /home/go/src/robot_server/internal/route_server_conn.go:97
12 0x00000000007ab598 in robot_server/internal.(*RouteServerConn).onHandleData
at /home/go/src/robot_server/internal/route_server_conn.go:65
13 0x00000000007aebd2 in robot_server/internal.(*RouteServerConn).onHandleData-fm
at /home/go/src/robot_server/internal/route_server_conn.go:60
14 0x000000000079bff6 in robot_server/base.(*ImClient).NetLoop
at /home/go/src/robot_server/base/im_client.go:168
15 0x00000000007ab3e1 in robot_server/internal.read
at /home/go/src/robot_server/internal/route_server_conn.go:41
16 0x00000000004582d1 in runtime.goexit
at /usr/local/go/src/runtime/asm_amd64.s:1337
(dlv) frame 11 # frame+行号,显示错误的错误信息
> runtime.raise() /usr/local/go/src/runtime/sys_linux_amd64.s:150 (PC: 0x459be1)
Warning: debugging optimized function
Frame 11: /home/go/src/robot_server/internal/route_server_conn.go:97 (PC: 7aba4f)
92: sessionId := *msg.SessionId
93: //if msg.SessionId != nil {
94: // sessionId = *msg.SessionId
95: //}
96:
=> 97: logger.Sugar.Infof("onHandleWelcomeMsgList from_id:%d,to_id:%d,session_type:%d,app_id:%d", *msg.UserId,
98: sessionId, *msg.SessionType, *msg.AppId)
99: DefaultFaqHttpQueryPool.PushGetWelcomeReq(header, msg, false)
100: }
したがって、上記からわかるように、これはmsg.SessionIdのnullポインターによって引き起こされたクラッシュであるはずです。
デーモンの下で設定する方法
通常、サービスは、restart.shおよびその他の再起動スクリプトを使用してバックグラウンド(デーモン)で実行する必要があります。では、スクリプトでenv GOTRACEBACK = crashを設定する方法は?
作者はそれをシェルスクリプトに直接追加しようとしましたが、役に立たないようでした。
function start() {
# 没用
./daemon env GOTRACEBACK=crash ./robot_server --log_dir=${log_dir} --conf=robotserver.conf &
sleep 2
ps -ef | grep robot_server
}
正しいアプローチは、env環境変数を設定した後にexec.Commandを使用するデーモンプロセスです。
cmd := exec.Command(fullPath, args...)
// 在Start()之前设置,启用go core dump 功能
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
err := cmd.Start()
以下の完全なコードを参照してください。
demo.go
package main
import (
"flag"
"fmt"
"os/exec"
"path/filepath"
"time"
)
var (
appPath string
)
func main() {
flag.Parse()
args := make([]string, 0)
for i := range flag.Args() {
if i == 0 {
appPath = flag.Arg(i)
} else {
args = append(args, flag.Arg(i))
}
}
//fmt.Println(flag.Args())
if appPath == "" {
fmt.Println("Usage:./daemon [appPath] [args]")
return
}
fullPath, _ := filepath.Abs(appPath)
cmd := exec.Command(fullPath, args...)
// 启用go core dump 功能
cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
err := cmd.Start()
time.Sleep(time.Second)
if err != nil {
fmt.Printf("daemon error:%s \n", err.Error())
} else {
fmt.Println("daemon success")
}
}
付録
restart.shスクリプト
#!/bin/sh
#nohup ./robot_server -log_dir=log -alsologtostderr=true &
log_dir=./log
function create_log_dir() {
if [[ ! -d "${log_dir}" ]];then
mkdir -p ${log_dir}
fi
}
function start() {
./daemon ./robot_server --log_dir=${log_dir} --conf=robotserver.conf &
sleep 2
ps -ef | grep robot_server
}
function stop() {
if [[ -e server.pid ]]; then
pid=`cat server.pid`
echo "kill pid=$pid"
kill ${pid}
fi
}
stop
create_log_dir
start
コアダンプを閉じる
ulimit -c # 查看core dump状态,0代表关闭,unlimited代表打开
vim /etc/profile
次の文を追加します。
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
有効かどうかを確認します。
# 重新打开终端 如果要启用,把上面那句话注释重新打开终端即可
ulimit -c 如果输出0,代表关闭成功
リダイレクトスキーム
weixin_34167043を参照してください、私はこれを試していません:
logFile, err := os.OpenFile("./log/fatal.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0660)
if err != nil {
log.Println("服务启动出错", "打开异常日志文件失败" , err)
return
}
// 将进程标准出错重定向至文件,进程崩溃时运行时将向该文件记录协程调用栈信息
syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
参照
Golangデバッグツール掘り下げ
https://www.cnblogs.com/li-peng/p/8522592.html
不明なエラーが原因でgolangプログラムがクラッシュしたときに例外をログに記録する方法https://blog.csdn.net/weixin_34167043/article/details/94651600?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3&utm_source =distribute.pc_relevant。none-task-blog-BlogCommendFromBaidu-3
golangランタイム
https://golang.org/src/runtime/crash_unix_test.go?m=text
オン
純粋なGolangで書かれた独自のオープンソースIMをお勧めします。
CoffeeChat:
https://github.com/xmcy0011/CoffeeChat
オープンソースim with server(go)and client(flutter + swift)
サーバー(go)とクライアント(flutter)、シングルチャットとロボット(Xiaowei、Turing、Sizhi)のチャット機能を含む、TeamTalkやGuazi IMなどの有名なプロジェクトを参照してください。現在、グループチャット機能が開発されています。ゴランとフラッターテクノロジーのクロスプラットフォーム開発に興味を持っているウェルカムスターは、もっと注目しています。
————————————————
著作権表示:この記事はCSDNブロガー「XuFei」の元の記事であり、CC 4.0BY-SA著作権契約に準拠しています。元のソースを添付してくださいリンクと転載用のコピー。ステートメント。
元のリンク:https://blog.csdn.net/xmcy001122/article/details/103921991