implement panic log for gateway and launcher

add file logger to gateway

ref issue: #1734

Signed-off-by: Cytown <cytown@gmail.com>
This commit is contained in:
Cytown
2026-03-23 15:40:17 +08:00
parent cff9065084
commit df17684dd4
10 changed files with 163 additions and 7 deletions
+17 -1
View File
@@ -47,6 +47,10 @@ const (
serviceShutdownTimeout = 30 * time.Second
providerReloadTimeout = 30 * time.Second
gracefulShutdownTimeout = 15 * time.Second
logPath = "logs"
panicFile = "gateway_panic.log"
logFile = "gateway.log"
)
type services struct {
@@ -79,7 +83,19 @@ func (p *startupBlockedProvider) GetDefaultModel() string {
}
// Run starts the gateway runtime using the configuration loaded from configPath.
func Run(debug bool, configPath string, allowEmptyStartup bool) error {
func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) error {
panicPath := filepath.Join(homePath, logPath, panicFile)
panicFunc, err := logger.InitPanic(panicPath)
if err != nil {
return fmt.Errorf("error initializing panic log: %w", err)
}
defer panicFunc()
if err = logger.EnableFileLogging(filepath.Join(homePath, logPath, logFile)); err != nil {
panic(fmt.Sprintf("error enabling file logging: %v", err))
}
defer logger.DisableFileLogging()
cfg, err := config.LoadConfig(configPath)
if err != nil {
return fmt.Errorf("error loading config: %w", err)
+36
View File
@@ -0,0 +1,36 @@
package logger
import (
"fmt"
"os"
"path/filepath"
"runtime/debug"
"time"
)
func InitPanic(filePath string) (func(), error) {
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return nil, fmt.Errorf("failed to create log directory: %w", err)
}
writer := initPanicFile(filePath)
if writer == nil {
return nil, fmt.Errorf("failed to create log file: %s", filePath)
}
return func() {
defer writer.Close()
if err := recover(); err != nil {
now := time.Now().Format("2006-01-02 15:04:05")
stack := debug.Stack()
logMsg := "\n\n====================\n[" + now + "] PANIC OCCURRED: " + fmt.Sprintf(
"%v",
err,
) + "\n" + string(
stack,
)
writer.Write([]byte(logMsg))
os.Exit(1)
}
}, nil
}
+21
View File
@@ -0,0 +1,21 @@
//go:build !windows
// +build !windows
package logger
import (
"fmt"
"io"
"os"
)
func initPanicFile(panicFile string) io.WriteCloser {
file, err := os.OpenFile(panicFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND|os.O_SYNC, 0o600)
if err != nil {
panic(fmt.Sprintf("error in open panic: %v", err))
}
if err = Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
panic(fmt.Sprintf("error in syscall.Dup2: %v", err))
}
return file
}
+25
View File
@@ -0,0 +1,25 @@
//go:build windows
// +build windows
package logger
import (
"fmt"
"io"
"os"
"golang.org/x/sys/windows"
)
func initPanicFile(panicFile string) io.WriteCloser {
file, err := os.OpenFile(panicFile, os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0600)
if err != nil {
panic(fmt.Sprintf("error in open panic: %v", err))
}
err = windows.SetStdHandle(windows.STD_ERROR_HANDLE, windows.Handle(file.Fd()))
if err != nil {
panic(fmt.Sprintf("Failed to redirect stderr to file: %v", err))
}
os.Stderr = file
return file
}
+12
View File
@@ -0,0 +1,12 @@
//go:build linux && amd64
// +build linux,amd64
package logger
import (
"syscall"
)
func Dup2(oldfd int, newfd int) error {
return syscall.Dup2(oldfd, newfd)
}
+12
View File
@@ -0,0 +1,12 @@
//go:build linux && arm64
// +build linux,arm64
package logger
import (
"syscall"
)
func Dup2(oldfd int, newfd int) error {
return syscall.Dup3(oldfd, newfd, 0)
}
+12
View File
@@ -0,0 +1,12 @@
//go:build darwin
// +build darwin
package logger
import (
"syscall"
)
func Dup2(oldfd int, newfd int) error {
return syscall.Dup2(oldfd, newfd)
}
+12
View File
@@ -0,0 +1,12 @@
//go:build linux && loong64
// +build linux,loong64
package logger
import (
"syscall"
)
func Dup2(oldfd int, newfd int) error {
return syscall.Dup3(oldfd, newfd, 0)
}