新增实例槽位隔离与结构化日志,多开不再共用日志与账号

This commit is contained in:
yml2213
2026-10-14 21:32:49 +08:00
parent f96fa7d858
commit 8c4b15066f
27 changed files with 2011 additions and 468 deletions
+57 -5
View File
@@ -14,9 +14,20 @@ import (
"time"
"huya-go/internal/huya"
"huya-go/internal/instance"
"huya-go/internal/logger"
"huya-go/internal/sniper"
)
// closeLogger 由 logger.Init 返回;os.Exit 不会执行 defer,退出前必须显式刷盘。
var closeLogger func()
const (
categoryNet = "网络"
categoryMonitor = "监控"
categoryCLI = "CLI"
)
func main() {
var (
cmd = flag.String("cmd", "list", "命令:list/score/records/exchange/monitor")
@@ -47,10 +58,15 @@ func main() {
refreshSuccess = flag.Bool("refresh-after-success", true, "monitor 成功后异步刷新积分和记录")
freqBackoffMS = flag.Int("freq-backoff", 300, "操作频繁后的账号退避毫秒")
errorBackoffMS = flag.Int("error-backoff", 300, "请求异常后的账号退避毫秒")
verbose = flag.Bool("v", false, "输出调试日志")
verbose = flag.Bool("v", false, "输出调试日志(同时打印到 stderr)")
logDir = flag.String("log-dir", "", "日志目录,默认使用应用数据目录下的 logs")
logLevel = flag.String("log-level", "info", "日志最低等级:debug/info/warn/error")
)
flag.Parse()
initLogging(*logDir, *logLevel, *verbose)
defer flushLogs()
if *sid <= 0 {
exitErr(errors.New("必须提供有效 -sid"))
}
@@ -68,11 +84,13 @@ func main() {
accounts = append(accounts, sniper.Account{UID: uid, Cookie: ck})
}
logger := func(string) {}
if *verbose {
logger = func(msg string) { fmt.Fprintln(os.Stderr, msg) }
clientLogger := func(msg string) {
logger.LogEvent(categoryNet, logger.LevelDebug, "%s", msg)
if *verbose {
fmt.Fprintln(os.Stderr, msg)
}
}
client, closeClient, err := huya.NewActivityClient(*transport, *wssHost, time.Duration(*timeoutSec)*time.Second, logger)
client, closeClient, err := huya.NewActivityClient(*transport, *wssHost, time.Duration(*timeoutSec)*time.Second, clientLogger)
if err != nil {
exitErr(err)
}
@@ -138,6 +156,8 @@ func main() {
outMu.Lock()
defer outMu.Unlock()
_ = json.NewEncoder(os.Stdout).Encode(result)
logger.LogAccountEvent(categoryMonitor, sniper.LogLevelForCategory(result.Category), strconv.FormatInt(result.UID, 10),
"loop=%d action=%s category=%s msg=%s error=%s", result.Loop, result.Action, result.Category, result.Message, result.Error)
}
cfg := sniper.Config{
SID: int32(*sid),
@@ -336,8 +356,40 @@ func availableScore(resp *huya.GetUserScoreResp) int64 {
return resp.AvailableScore()
}
// initLogging 初始化 CLI 日志:默认写入应用数据目录下的 logs,和 GUI 一样是
// 结构化日志(带分类与账号标签),便于事后复盘。
func initLogging(dir, level string, verbose bool) {
if strings.TrimSpace(dir) == "" {
dir = instance.DefaultLogDir()
}
logger.SetMinLevel(logger.LevelFromString(chooseLevel(level, verbose)))
store := logger.NewStore(1000)
closeFn, err := logger.Init(store, dir, "CLI", "cli", instance.DefaultDataDir())
closeLogger = closeFn
if err != nil {
fmt.Fprintf(os.Stderr, "日志文件不可用,仅保留在内存: %v\n", err)
}
}
func chooseLevel(level string, verbose bool) string {
if verbose {
return logger.LevelDebug
}
return level
}
// flushLogs 把异步日志队列刷盘;必须在 os.Exit 之前调用。
func flushLogs() {
if closeLogger != nil {
closeLogger()
closeLogger = nil
}
}
func exitErr(err error) {
logger.LogEvent(categoryCLI, logger.LevelError, "%v", err)
fmt.Fprintln(os.Stderr, "错误:", err)
flushLogs()
os.Exit(1)
}