| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package main
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
- )
- // logger.go —— 简单文件日志(windowsgui 子系统无控制台,统一落盘)。
- // 特性:按天轮转(跨天自动切换文件);所有写出内容经 Redact 脱敏,token 不明文落盘。
- type Logger struct {
- mu sync.Mutex
- file *os.File
- path string
- day string
- }
- func NewLogger() *Logger {
- l := &Logger{}
- l.rotate(time.Now().Format("20060102"))
- return l
- }
- // rotate 切换到指定日期的日志文件(关闭旧句柄)。
- func (l *Logger) rotate(day string) {
- if l.file != nil {
- _ = l.file.Close()
- l.file = nil
- }
- dir := logDir()
- _ = os.MkdirAll(dir, 0o755)
- p := filepath.Join(dir, "tray-"+day+".log")
- f, err := os.OpenFile(p, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o600)
- if err != nil {
- f = nil
- }
- l.file = f
- l.path = p
- l.day = day
- }
- func (l *Logger) Printf(format string, args ...any) {
- l.mu.Lock()
- defer l.mu.Unlock()
- if day := time.Now().Format("20060102"); day != l.day {
- l.rotate(day) // 跨天轮转
- }
- body := Redact(fmt.Sprintf(format, args...))
- line := fmt.Sprintf("[%s] %s\n", time.Now().Format("2006-01-02 15:04:05"), body)
- if l.file != nil {
- _, _ = l.file.WriteString(line)
- }
- }
- func (l *Logger) Path() string {
- l.mu.Lock()
- defer l.mu.Unlock()
- return l.path
- }
- func (l *Logger) Close() {
- l.mu.Lock()
- defer l.mu.Unlock()
- if l.file != nil {
- _ = l.file.Close()
- l.file = nil
- }
- }
- // Redact 脱敏访问 token(token=xxxx -> token=***),避免凭据明文落盘。
- func Redact(s string) string {
- const marker = "token="
- var b strings.Builder
- for {
- i := strings.Index(s, marker)
- if i < 0 {
- b.WriteString(s)
- return b.String()
- }
- end := i + len(marker)
- b.WriteString(s[:end])
- b.WriteString("***")
- j := end
- for j < len(s) && !isTokenTerminator(s[j]) {
- j++
- }
- s = s[j:]
- }
- }
- func isTokenTerminator(c byte) bool {
- switch c {
- case ' ', '\t', '\r', '\n', '"', '\'', '&', '<', '>', '#', '?':
- return true
- }
- return false
- }
|