Fix crash when being denied to save logs.
This commit is contained in:
@@ -4,10 +4,10 @@
|
|||||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND.
|
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND.
|
||||||
|
|
||||||
// logger 模块:基于 zerolog 的日志初始化,支持控制台输出(可读格式)+ 文件输出(JSON 结构化)。
|
// logger 模块:基于 zerolog 的日志初始化,支持控制台输出(可读格式)+ 文件输出(JSON 结构化)。
|
||||||
|
// 日志目录优先级:exe 同目录 log/ → %APPDATA%/SRemoteConnectClient/log/ → 仅控制台输出。
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -19,42 +19,85 @@ import (
|
|||||||
// log 包级全局日志实例,所有 .go 文件共用。
|
// log 包级全局日志实例,所有 .go 文件共用。
|
||||||
var log zerolog.Logger
|
var log zerolog.Logger
|
||||||
|
|
||||||
// initLogger 初始化全局日志:
|
// initLogger 初始化全局日志。
|
||||||
// - 日志文件存储在 srcc.exe 同目录的 log/ 下,按日期命名
|
// 尝试在 exe 目录下创建 log/,若无写权限(多用户安装场景)则回退到 %APPDATA%。
|
||||||
// - 控制台使用可读的 ConsoleWriter(带颜色)
|
// 日志按日期命名,控制台使用可读格式(带颜色),文件使用 JSON 结构化格式。
|
||||||
// - 同时输出到控制台和文件
|
|
||||||
func initLogger() {
|
func initLogger() {
|
||||||
exePath, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
exePath, _ = os.Getwd()
|
|
||||||
}
|
|
||||||
exeDir := filepath.Dir(exePath)
|
|
||||||
|
|
||||||
logDir := filepath.Join(exeDir, "log")
|
|
||||||
if err := os.MkdirAll(logDir, 0755); err != nil {
|
|
||||||
panic(fmt.Sprintf("无法创建日志目录: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
today := time.Now().Format("2006-01-02")
|
|
||||||
logFile := filepath.Join(logDir, today+".log")
|
|
||||||
|
|
||||||
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("无法打开日志文件: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
consoleWriter := zerolog.ConsoleWriter{
|
consoleWriter := zerolog.ConsoleWriter{
|
||||||
Out: os.Stdout,
|
Out: os.Stdout,
|
||||||
TimeFormat: "2006-01-02 15:04:05",
|
TimeFormat: "2006-01-02 15:04:05",
|
||||||
NoColor: false,
|
NoColor: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
multi := io.MultiWriter(consoleWriter, file)
|
logFile := openLogFile()
|
||||||
|
if logFile == nil {
|
||||||
|
// 连 %APPDATA% 都写不了,仅控制台输出
|
||||||
|
log = zerolog.New(consoleWriter).
|
||||||
|
With().Timestamp().Caller().Logger().
|
||||||
|
Level(zerolog.DebugLevel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
multi := io.MultiWriter(consoleWriter, logFile)
|
||||||
log = zerolog.New(multi).
|
log = zerolog.New(multi).
|
||||||
With().
|
With().Timestamp().Caller().Logger().
|
||||||
Timestamp().
|
|
||||||
Caller().
|
|
||||||
Logger().
|
|
||||||
Level(zerolog.DebugLevel)
|
Level(zerolog.DebugLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// openLogFile 按优先级尝试打开日志文件。
|
||||||
|
// 返回 nil 表示无法创建日志文件,此时程序仅输出到控制台。
|
||||||
|
func openLogFile() *os.File {
|
||||||
|
logDir, err := resolveLogDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
today := time.Now().Format("2006-01-02")
|
||||||
|
logPath := filepath.Join(logDir, today+".log")
|
||||||
|
|
||||||
|
f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveLogDir 解析日志目录。
|
||||||
|
// 优先使用 exe 同目录下的 log/;若不可写则使用 %APPDATA%/SRemoteConnectClient/log/。
|
||||||
|
func resolveLogDir() (string, error) {
|
||||||
|
// 1. 尝试 exe 同目录
|
||||||
|
exePath, _ := os.Executable()
|
||||||
|
if exePath != "" {
|
||||||
|
dir := filepath.Join(filepath.Dir(exePath), "log")
|
||||||
|
if err := os.MkdirAll(dir, 0755); err == nil {
|
||||||
|
// 验证确实可写
|
||||||
|
testFile := filepath.Join(dir, ".write_test")
|
||||||
|
if f, err := os.Create(testFile); err == nil {
|
||||||
|
f.Close()
|
||||||
|
os.Remove(testFile)
|
||||||
|
return dir, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 回退到 %APPDATA%/SRemoteConnectClient/log
|
||||||
|
appData := os.Getenv("APPDATA")
|
||||||
|
if appData == "" {
|
||||||
|
appData = os.Getenv("LOCALAPPDATA")
|
||||||
|
}
|
||||||
|
if appData != "" {
|
||||||
|
dir := filepath.Join(appData, "SRemoteConnectClient", "log")
|
||||||
|
if err := os.MkdirAll(dir, 0755); err == nil {
|
||||||
|
return dir, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 最后尝试当前工作目录
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
dir := filepath.Join(cwd, "log")
|
||||||
|
if err := os.MkdirAll(dir, 0755); err == nil {
|
||||||
|
return dir, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", os.ErrPermission
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user