首次推送
build / build-and-test (push) Failing after 1m24s

This commit is contained in:
2026-10-18 19:44:38 +08:00
commit f047662129
64 changed files with 10454 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
// Package logx 提供「控制台 + 按天切分文件」的运行日志。
package logx
import (
"io"
"log"
"os"
"path/filepath"
"sync"
"time"
)
type dailyWriter struct {
dir string
mu sync.Mutex
f *os.File
day string
}
func (w *dailyWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
day := time.Now().Format("2006-01-02")
if w.f == nil || w.day != day {
if w.f != nil {
_ = w.f.Close()
w.f = nil
}
if err := os.MkdirAll(w.dir, 0o755); err != nil {
return 0, err
}
f, err := os.OpenFile(filepath.Join(w.dir, "daili-"+day+".log"),
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return 0, err
}
w.f = f
w.day = day
}
// 写文件失败不能影响控制台输出
n, err := w.f.Write(p)
return n, err
}
func (w *dailyWriter) Close() error {
w.mu.Lock()
defer w.mu.Unlock()
if w.f == nil {
return nil
}
err := w.f.Close()
w.f = nil
return err
}
// Setup 把标准日志同时写到控制台与 dir 下按天切分的文件。
// 返回的 Closer 在进程退出前关闭即可。
func Setup(dir string) (io.Closer, error) {
if err := os.MkdirAll(dir, 0o755); err != nil {
return nil, err
}
w := &dailyWriter{dir: dir}
// 预热:启动即创建当天文件,避免“刚启动就崩、日志却没落盘”
if _, err := w.Write(nil); err != nil {
return nil, err
}
log.SetOutput(io.MultiWriter(os.Stderr, w))
return w, nil
}
+48
View File
@@ -0,0 +1,48 @@
package logx
import (
"log"
"os"
"path/filepath"
"strings"
"testing"
)
func TestSetupWritesFile(t *testing.T) {
dir := t.TempDir()
logDir := filepath.Join(dir, "logs")
closer, err := Setup(logDir)
if err != nil {
t.Fatalf("Setup 失败: %v", err)
}
log.Printf("hello-logx-%d", 42)
if err := closer.Close(); err != nil {
t.Fatalf("关闭失败: %v", err)
}
entries, err := os.ReadDir(logDir)
if err != nil || len(entries) != 1 {
t.Fatalf("日志目录应有 1 个文件, 实际 %d: %v", len(entries), err)
}
data, err := os.ReadFile(filepath.Join(logDir, entries[0].Name()))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(data), "hello-logx-42") {
t.Fatalf("日志未落盘,文件内容: %q", string(data))
}
}
func TestSetupCreatesFileImmediately(t *testing.T) {
dir := t.TempDir()
closer, err := Setup(dir)
if err != nil {
t.Fatal(err)
}
defer closer.Close()
entries, err := os.ReadDir(dir)
if err != nil || len(entries) != 1 {
t.Fatalf("Setup 后应立刻存在当天日志文件: %v %d", err, len(entries))
}
}