2024-01-16 12:28:27 -06:00
|
|
|
package clog
|
2023-12-12 18:27:55 -05:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"reflect"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
testopts = &slog.HandlerOptions{
|
|
|
|
|
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
|
|
|
|
|
// Ignore time to make testing easier.
|
|
|
|
|
if a.Key == "time" {
|
|
|
|
|
return slog.Attr{}
|
|
|
|
|
}
|
|
|
|
|
return a
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestLogger(t *testing.T) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
|
base := slog.New(NewHandler(slog.NewJSONHandler(b, testopts)))
|
|
|
|
|
log := NewLogger(base).With("a", "b")
|
|
|
|
|
log.InfoContext(ctx, "")
|
|
|
|
|
t.Log(b.String())
|
|
|
|
|
|
|
|
|
|
want := map[string]any{
|
|
|
|
|
"level": "INFO",
|
|
|
|
|
"msg": "",
|
|
|
|
|
"a": "b",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLoggerNilBase(t *testing.T) {
|
|
|
|
|
log := NewLogger(nil)
|
|
|
|
|
log.Info("")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLoggerFromContext(t *testing.T) {
|
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
|
base := slog.New(NewHandler(slog.NewJSONHandler(b, testopts)))
|
|
|
|
|
log := NewLogger(base).With("a", "b")
|
|
|
|
|
|
|
|
|
|
ctx := WithLogger(context.Background(), log)
|
|
|
|
|
FromContext(ctx).Info("")
|
|
|
|
|
|
|
|
|
|
want := map[string]any{
|
|
|
|
|
"level": "INFO",
|
|
|
|
|
"msg": "",
|
|
|
|
|
"a": "b",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Run("FromContext.Info", func(t *testing.T) {
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Reset()
|
|
|
|
|
|
2024-01-16 12:28:27 -06:00
|
|
|
t.Run("clog.Info", func(t *testing.T) {
|
2023-12-12 18:27:55 -05:00
|
|
|
InfoContext(ctx, "")
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLoggerPC(t *testing.T) {
|
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
|
log := NewLogger(slog.New(NewHandler(slog.NewJSONHandler(b, &slog.HandlerOptions{
|
|
|
|
|
AddSource: true,
|
|
|
|
|
ReplaceAttr: testopts.ReplaceAttr,
|
|
|
|
|
}))))
|
|
|
|
|
|
|
|
|
|
log.Info("")
|
|
|
|
|
t.Log(b.String())
|
|
|
|
|
|
|
|
|
|
var got struct {
|
|
|
|
|
Source struct {
|
|
|
|
|
File string `json:"file"`
|
|
|
|
|
Function string `json:"function"`
|
|
|
|
|
} `json:"source"`
|
|
|
|
|
}
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
// Knowing that the PC is from this test is good enough.
|
2024-01-16 12:28:27 -06:00
|
|
|
want := fmt.Sprintf("github.com/chainguard-dev/clog.%s", t.Name())
|
2023-12-12 18:27:55 -05:00
|
|
|
if got.Source.Function != want {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-18 17:33:25 -07:00
|
|
|
|
|
|
|
|
func TestWith(t *testing.T) {
|
|
|
|
|
ctx := context.WithValue(context.Background(), "test", "test")
|
|
|
|
|
log := NewLoggerWithContext(ctx, nil)
|
|
|
|
|
withed := log.With("a", "b")
|
|
|
|
|
if want := withed.ctx; want != ctx {
|
|
|
|
|
t.Errorf("want %v, got %v", want, ctx)
|
|
|
|
|
}
|
|
|
|
|
withed = log.WithGroup("a")
|
|
|
|
|
if want := withed.ctx; want != ctx {
|
|
|
|
|
t.Errorf("want %v, got %v", want, ctx)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-24 10:21:37 -05:00
|
|
|
|
|
|
|
|
func TestDefaultHandler(t *testing.T) {
|
|
|
|
|
old := slog.Default()
|
|
|
|
|
defer func() {
|
|
|
|
|
slog.SetDefault(old)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
|
slog.SetDefault(slog.New(slog.NewJSONHandler(b, testopts)))
|
|
|
|
|
|
|
|
|
|
t.Run("Info", func(t *testing.T) {
|
|
|
|
|
FromContext(WithValues(context.Background(), "a", "b")).Info("")
|
|
|
|
|
want := map[string]any{
|
|
|
|
|
"level": "INFO",
|
|
|
|
|
"msg": "",
|
|
|
|
|
"a": "b",
|
|
|
|
|
}
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b.Reset()
|
|
|
|
|
|
|
|
|
|
t.Run("InfoContext", func(t *testing.T) {
|
|
|
|
|
// Set logger with original value
|
|
|
|
|
ctx := WithValues(context.Background(), "a", "b")
|
|
|
|
|
logger := FromContext(ctx)
|
|
|
|
|
|
|
|
|
|
// Override value in request context - we expect this to overwrite the original value set in the logger
|
|
|
|
|
logger.InfoContext(WithValues(ctx, "a", "c"), "")
|
|
|
|
|
|
|
|
|
|
want := map[string]any{
|
|
|
|
|
"level": "INFO",
|
|
|
|
|
"msg": "",
|
|
|
|
|
"a": "c",
|
|
|
|
|
}
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-01-27 16:29:38 -05:00
|
|
|
|
|
|
|
|
b.Reset()
|
|
|
|
|
|
|
|
|
|
t.Run("Debug - no log", func(t *testing.T) {
|
|
|
|
|
logger := FromContext(context.Background())
|
|
|
|
|
logger.Debug("asdf")
|
|
|
|
|
|
|
|
|
|
if b.Len() != 0 {
|
|
|
|
|
t.Errorf("want empty, got %q", b.String())
|
|
|
|
|
}
|
|
|
|
|
})
|
2025-01-24 10:21:37 -05:00
|
|
|
}
|
2025-03-03 18:20:42 -05:00
|
|
|
|
|
|
|
|
func TestContext(t *testing.T) {
|
|
|
|
|
old := slog.Default()
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
slog.SetDefault(old)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
|
slog.SetDefault(slog.New(slog.NewJSONHandler(b, testopts)))
|
|
|
|
|
|
|
|
|
|
msg := "hello world"
|
|
|
|
|
want := map[string]any{
|
|
|
|
|
"level": "INFO",
|
|
|
|
|
"msg": msg,
|
|
|
|
|
"a": "b",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx := WithValues(context.Background(), "a", "b")
|
|
|
|
|
// These should all give the same output and be functionally equivalent.
|
|
|
|
|
for _, tc := range []struct {
|
|
|
|
|
name string
|
|
|
|
|
fn func()
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "clog.InfoContext",
|
|
|
|
|
fn: func() {
|
|
|
|
|
InfoContext(ctx, msg)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "clog.FromContext.Info",
|
|
|
|
|
fn: func() {
|
|
|
|
|
FromContext(ctx).Info(msg)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "clog.FromContext.InfoContext",
|
|
|
|
|
fn: func() {
|
|
|
|
|
FromContext(ctx).InfoContext(ctx, msg)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
} {
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
|
b.Reset()
|
|
|
|
|
tc.fn()
|
|
|
|
|
|
|
|
|
|
var got map[string]any
|
|
|
|
|
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if !reflect.DeepEqual(want, got) {
|
|
|
|
|
t.Errorf("want %v, got %v", want, got)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|