summaryrefslogtreecommitdiffstats
path: root/logging/log_test.go
blob: 93ceaf6c81171f79b088de90f0941d4a8de43c6b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package logging_test

import (
	"errors"
	"log/slog"
	"testing"

	"go.sudomsg.com/kit/logging"
	"go.sudomsg.com/kit/logging/test"
)

func TestWithLogger_And_FromContext(t *testing.T) {
	ctx := t.Context()
	mock := test.NewMockLogHandler(t)
	logger := slog.New(mock)

	ctx = logging.WithLogger(ctx, logger)

	got := logging.FromContext(ctx)
	if got != logger {
		t.Errorf("expected logger from context to match original logger")
	}
}

func TestFromContext_DefaultFallback(t *testing.T) {
	ctx := t.Context()
	got := logging.FromContext(ctx)

	if got != slog.Default() {
		t.Errorf("expected default logger when no logger is in context")
	}
}

func TestRecoverAndLog(t *testing.T) {
	ctx := t.Context()
	mock := test.NewMockLogHandler(t)

	logger := slog.New(mock)
	ctx = logging.WithLogger(ctx, logger)

	err := errors.New("something broke")
	logging.RecoverAndLog(ctx, "panic recovered", err)

	records := mock.Records()
	if len(records) != 1 {
		t.Fatalf("expected 1 log record, got %d", len(records))
	}

	record := records[0]
	if record.Message != "panic recovered" {
		t.Errorf("expected message 'panic recAvered', got %q", record.Message)
	}

	foundStack := false
	record.Attrs(func(a slog.Attr) bool {
		if a.Key == "stack" {
			foundStack = true
		}
		return true
	})

	if !foundStack {
		t.Errorf("expected 'stack' attribute in log")
	}
}

func TestWith(t *testing.T) {
	ctx := t.Context()

	mock := test.NewMockLogHandler(t)

	logger := slog.New(mock)
	ctx = logging.WithLogger(ctx, logger)

	user := "user"
	id := "1234"

	logger2, newCtx := logging.With(ctx, "user", user, "id", id)
	logger2.InfoContext(ctx, "test message")

	records := mock.Records()
	if len(records) != 1 {
		t.Fatalf("expected 1 record, got %d", len(records))
	}

	record := records[0]
	foundUser := false
	foundID := false

	record.Attrs(func(attr slog.Attr) bool {
		switch attr.Key {
		case "user":
			foundUser = attr.Value.String() == user
		case "id":
			foundID = attr.Value.String() == id
		}
		return true
	})

	if !foundUser || !foundID {
		t.Errorf("expected 'user' and 'id' attributes in log record, %v", records)
	}

	// Test context carries logger with same attributes
	logFromCtx := logging.FromContext(newCtx)
	logFromCtx.InfoContext(ctx, "second message")

	if len(mock.Records()) != 2 {
		t.Errorf("expected 2 log records, got %d", len(mock.Records()))
	}
}

func TestWithGroup(t *testing.T) {
	ctx := t.Context()

	mock := test.NewMockLogHandler(t)

	logger := slog.New(mock)
	ctx = logging.WithLogger(ctx, logger)

	logger2, _ := logging.WithGroup(ctx, "foo")
	logger2.InfoContext(ctx, "test message", "key", "value")

	records := mock.Records()
	if len(records) != 1 {
		t.Fatalf("expected 1 record, got %d", len(records))
	}

	record := records[0]
	var foundGroup bool

	record.Attrs(func(attr slog.Attr) bool {
		foundGroup = attr.Value.Kind() == slog.KindGroup

		return false
	})

	if !foundGroup {
		t.Errorf("expected 'user' and 'id' attributes in log record, %v", records)
	}
}