188 lines
5.3 KiB
Go
188 lines
5.3 KiB
Go
package loggerx_test
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/json"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/yuninks/loggerx"
|
||
|
|
)
|
||
|
|
|
||
|
|
func readOne(t *testing.T, dir, file string) string {
|
||
|
|
t.Helper()
|
||
|
|
files, _ := filepath.Glob(filepath.Join(dir, "*_"+file))
|
||
|
|
if len(files) == 0 {
|
||
|
|
files, _ = filepath.Glob(filepath.Join(dir, file))
|
||
|
|
}
|
||
|
|
if len(files) == 0 {
|
||
|
|
t.Fatalf("没找到 %s", file)
|
||
|
|
}
|
||
|
|
b, err := os.ReadFile(files[0])
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
return string(b)
|
||
|
|
}
|
||
|
|
|
||
|
|
// 默认(不调用 SetFormat)必须是合法 JSON —— 与 readme 的承诺一致
|
||
|
|
func TestDefaultFormatIsJSON(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(), loggerx.SetDir(dir))
|
||
|
|
l.Info(context.Background(), "hello")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
line := strings.TrimSpace(readOne(t, dir, "info.log"))
|
||
|
|
var v map[string]any
|
||
|
|
if err := json.Unmarshal([]byte(line), &v); err != nil {
|
||
|
|
t.Fatalf("默认格式不是合法 JSON: %v\n%s", err, line)
|
||
|
|
}
|
||
|
|
if v["level"] != "info" {
|
||
|
|
t.Errorf("level=%v", v["level"])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetFormat(FormatText) 之后输出单行文本,且仍是一行一条
|
||
|
|
func TestTextFormat(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetFormat(loggerx.FormatText),
|
||
|
|
)
|
||
|
|
ctx := context.Background()
|
||
|
|
l.Info(ctx, "hello text")
|
||
|
|
l.Errorf(ctx, "boom %d", 42)
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
info := strings.TrimSpace(readOne(t, dir, "info.log"))
|
||
|
|
if info == "" {
|
||
|
|
t.Fatal("text 格式没有输出")
|
||
|
|
}
|
||
|
|
for _, want := range []string{"level=info", "time=", "file=", "content="} {
|
||
|
|
if !strings.Contains(info, want) {
|
||
|
|
t.Errorf("text 输出缺少 %q: %s", want, info)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if strings.HasPrefix(info, "{") {
|
||
|
|
t.Errorf("SetFormat(text) 之后不应还是 JSON: %s", info)
|
||
|
|
}
|
||
|
|
if strings.Count(info, "\n") != 0 {
|
||
|
|
t.Errorf("一条日志必须占一行: %q", info)
|
||
|
|
}
|
||
|
|
|
||
|
|
errLine := strings.TrimSpace(readOne(t, dir, "error.log"))
|
||
|
|
if !strings.Contains(errLine, "level=error") || !strings.Contains(errLine, "42") {
|
||
|
|
t.Errorf("error 的 text 输出不正确: %s", errLine)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 内容里有空格/引号时,text 格式用引号包起来,避免歧义
|
||
|
|
func TestTextFormatQuotesAmbiguousValues(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetFormat(loggerx.FormatText),
|
||
|
|
)
|
||
|
|
l.Info(context.Background(), "has space and \"quote\"")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
line := strings.TrimSpace(readOne(t, dir, "info.log"))
|
||
|
|
if !strings.Contains(line, `content="`) {
|
||
|
|
t.Errorf("含空格/引号的值应当被引号包裹: %s", line)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetFormat 传非法值时应保持默认,而不是切到一个没实现的格式
|
||
|
|
func TestInvalidFormatKeepsDefault(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetFormat(loggerx.Format("yaml")),
|
||
|
|
)
|
||
|
|
l.Info(context.Background(), "still-json")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
line := strings.TrimSpace(readOne(t, dir, "info.log"))
|
||
|
|
var v map[string]any
|
||
|
|
if err := json.Unmarshal([]byte(line), &v); err != nil {
|
||
|
|
t.Errorf("非法格式值不该改变默认行为: %v\n%s", err, line)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SetPrefix 必须真的加上前缀(两种格式都生效)
|
||
|
|
func TestPrefixApplied(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetPrefix("[order-svc] "),
|
||
|
|
)
|
||
|
|
l.Info(context.Background(), "with-prefix")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
line := readOne(t, dir, "info.log")
|
||
|
|
if !strings.HasPrefix(line, "[order-svc] ") {
|
||
|
|
t.Errorf("前缀未生效: %q", line)
|
||
|
|
}
|
||
|
|
// 前缀之后仍然要是合法 JSON
|
||
|
|
body := strings.TrimSpace(strings.TrimPrefix(line, "[order-svc] "))
|
||
|
|
var v map[string]any
|
||
|
|
if err := json.Unmarshal([]byte(body), &v); err != nil {
|
||
|
|
t.Errorf("前缀后的内容不是合法 JSON: %v\n%s", err, body)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// text 格式 + 前缀 + expandData 组合
|
||
|
|
func TestTextFormatWithPrefixAndExpand(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetFormat(loggerx.FormatText),
|
||
|
|
loggerx.SetPrefix("P|"),
|
||
|
|
loggerx.SetExpandData("app", "order"),
|
||
|
|
)
|
||
|
|
l.Info(context.Background(), "combo")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
line := strings.TrimSpace(readOne(t, dir, "info.log"))
|
||
|
|
if !strings.HasPrefix(line, "P|level=info") {
|
||
|
|
t.Errorf("前缀/格式组合输出不正确: %s", line)
|
||
|
|
}
|
||
|
|
if !strings.Contains(line, "app=order") {
|
||
|
|
t.Errorf("expandData 未出现在 text 输出里: %s", line)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// text 格式下不可序列化的内容也不能丢
|
||
|
|
func TestTextFormatUnmarshalableContent(t *testing.T) {
|
||
|
|
dir := t.TempDir()
|
||
|
|
l := loggerx.NewLogger(context.Background(),
|
||
|
|
loggerx.SetDir(dir),
|
||
|
|
loggerx.SetFormat(loggerx.FormatText),
|
||
|
|
)
|
||
|
|
l.Info(context.Background(), make(chan int), func() {})
|
||
|
|
l.Info(context.Background(), "after")
|
||
|
|
if err := l.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
content := readOne(t, dir, "info.log")
|
||
|
|
lines := strings.Split(strings.TrimSpace(content), "\n")
|
||
|
|
if len(lines) != 2 {
|
||
|
|
t.Fatalf("期望 2 行,实际 %d: %q", len(lines), content)
|
||
|
|
}
|
||
|
|
for i, line := range lines {
|
||
|
|
if !strings.Contains(line, "content=") {
|
||
|
|
t.Errorf("第 %d 行缺少 content: %s", i+1, line)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|