Skip to content

Commit ab9bf95

Browse files
committed
clean up; don't keep original Fmt, consolidate tests, generate golden files for new test cases
Signed-off-by: Callum Styan <[email protected]>
1 parent bbd432e commit ab9bf95

File tree

13 files changed

+554
-489
lines changed

13 files changed

+554
-489
lines changed

internal/entryhuman/entry.go

Lines changed: 2 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -179,108 +179,7 @@ func writeValueFast(w io.Writer, v interface{}) (bool, error) {
179179
}
180180
}
181181

182-
func Fmt(
183-
buf interface {
184-
io.StringWriter
185-
io.Writer
186-
}, termW io.Writer, ent slog.SinkEntry,
187-
) {
188-
reset(buf, termW)
189-
ts := ent.Time.Format(TimeFormat)
190-
buf.WriteString(render(termW, timeStyle, ts+" "))
191-
192-
level := ent.Level.String()
193-
level = strings.ToLower(level)
194-
if len(level) > 4 {
195-
level = level[:4]
196-
}
197-
level = "[" + level + "]"
198-
buf.WriteString(render(termW, levelStyle(ent.Level), level))
199-
buf.WriteString(" ")
200-
201-
if len(ent.LoggerNames) > 0 {
202-
loggerName := quoteKey(strings.Join(ent.LoggerNames, ".")) + ": "
203-
buf.WriteString(loggerName)
204-
}
205-
206-
var multilineKey string
207-
var multilineVal string
208-
msg := strings.TrimSpace(ent.Message)
209-
if strings.Contains(msg, "\n") {
210-
multilineKey = "msg"
211-
multilineVal = msg
212-
msg = "..."
213-
msg = quote(msg)
214-
}
215-
buf.WriteString(msg)
216-
217-
if ent.SpanContext.IsValid() {
218-
ent.Fields = append(slog.M(
219-
slog.F("trace", ent.SpanContext.TraceID),
220-
slog.F("span", ent.SpanContext.SpanID),
221-
), ent.Fields...)
222-
}
223-
224-
for i, f := range ent.Fields {
225-
if multilineVal != "" {
226-
break
227-
}
228-
229-
var s string
230-
switch v := f.Value.(type) {
231-
case string:
232-
s = v
233-
case error, xerrors.Formatter:
234-
s = fmt.Sprintf("%+v", v)
235-
}
236-
s = strings.TrimSpace(s)
237-
if !strings.Contains(s, "\n") {
238-
continue
239-
}
240-
241-
// Remove this field.
242-
ent.Fields = append(ent.Fields[:i], ent.Fields[i+1:]...)
243-
multilineKey = f.Name
244-
multilineVal = s
245-
}
246-
247-
keyStyle := timeStyle
248-
// Help users distinguish logs by keeping some color in the equal signs.
249-
equalsStyle := timeStyle
250-
251-
for i, f := range ent.Fields {
252-
if i < len(ent.Fields) {
253-
buf.WriteString(tab)
254-
}
255-
buf.WriteString(render(termW, keyStyle, quoteKey(f.Name)))
256-
buf.WriteString(render(termW, equalsStyle, "="))
257-
valueStr := formatValue(f.Value)
258-
buf.WriteString(valueStr)
259-
}
260-
261-
if multilineVal != "" {
262-
if msg != "..." {
263-
buf.WriteString(" ...")
264-
}
265-
266-
// Proper indentation.
267-
lines := strings.Split(multilineVal, "\n")
268-
for i, line := range lines[1:] {
269-
if line != "" {
270-
lines[i+1] = strings.Repeat(" ", len(multilineKey)+2) + line
271-
}
272-
}
273-
multilineVal = strings.Join(lines, "\n")
274-
275-
multilineKey = render(termW, keyStyle, multilineKey)
276-
buf.WriteString("\n")
277-
buf.WriteString(multilineKey)
278-
buf.WriteString("= ")
279-
buf.WriteString(multilineVal)
280-
}
281-
}
282-
283-
// OptimizedFmt returns a human readable format for ent. Assumes we have a bytes.Buffer
182+
// Fmt returns a human readable format for ent. Assumes we have a bytes.Buffer
284183
// which we will more easily be able to assume underlying reallocation of it's size is possible
285184
// if necessary than for an arbitrary io.Writer/io.StringWriter
286185
// Note that while bytes.Buffer can in theory return an error for writes, it only does so if the buffer size will
@@ -292,7 +191,7 @@ func Fmt(
292191
// We also do not indent the fields as go's test does that automatically
293192
// for extra lines in a log so if we did it here, the fields would be indented
294193
// twice in test logs. So the Stderr logger indents all the fields itself.
295-
func OptimizedFmt(buf *bytes.Buffer, termW io.Writer, ent slog.SinkEntry) {
194+
func Fmt(buf *bytes.Buffer, termW io.Writer, ent slog.SinkEntry) {
296195
reset(buf, termW)
297196

298197
// Timestamp + space

internal/entryhuman/entry_test.go

Lines changed: 27 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -142,191 +142,6 @@ func TestEntry(t *testing.T) {
142142
),
143143
},
144144
},
145-
}
146-
if *updateGoldenFiles {
147-
ents, err := os.ReadDir("testdata")
148-
if err != nil {
149-
t.Fatal(err)
150-
}
151-
for _, ent := range ents {
152-
os.Remove("testdata/" + ent.Name())
153-
}
154-
}
155-
156-
for _, tc := range ents {
157-
tc := tc
158-
t.Run(tc.name, func(t *testing.T) {
159-
t.Parallel()
160-
goldenPath := fmt.Sprintf("testdata/%s.golden", tc.name)
161-
162-
var gotBuf bytes.Buffer
163-
entryhuman.Fmt(&gotBuf, io.Discard, tc.ent)
164-
165-
if *updateGoldenFiles {
166-
err := os.WriteFile(goldenPath, gotBuf.Bytes(), 0o644)
167-
if err != nil {
168-
t.Fatal(err)
169-
}
170-
return
171-
}
172-
173-
wantByt, err := os.ReadFile(goldenPath)
174-
if err != nil {
175-
t.Fatal(err)
176-
}
177-
178-
assert.Equal(t, "entry matches", string(wantByt), gotBuf.String())
179-
})
180-
}
181-
182-
t.Run("isTTY during file close", func(t *testing.T) {
183-
t.Parallel()
184-
185-
tmpdir := t.TempDir()
186-
f, err := os.CreateTemp(tmpdir, "slog")
187-
if err != nil {
188-
t.Fatal(err)
189-
}
190-
defer f.Close()
191-
192-
done := make(chan struct{}, 2)
193-
go func() {
194-
entryhuman.Fmt(new(bytes.Buffer), f, slog.SinkEntry{
195-
Level: slog.LevelCritical,
196-
Fields: slog.M(
197-
slog.F("hey", "hi"),
198-
),
199-
})
200-
done <- struct{}{}
201-
}()
202-
go func() {
203-
_ = f.Close()
204-
done <- struct{}{}
205-
}()
206-
<-done
207-
<-done
208-
})
209-
}
210-
211-
// Verifies that OptimizedFmt returtns the same result as Fmt.
212-
// We can remove this if we are okay with removing the existing Fmt function and replacing it with OptimizedFmt (can return an error).
213-
func TestEntry_Optimized(t *testing.T) {
214-
t.Parallel()
215-
216-
type tcase struct {
217-
name string
218-
ent slog.SinkEntry
219-
}
220-
221-
ents := []tcase{
222-
{
223-
"simpleNoFields",
224-
slog.SinkEntry{
225-
Message: "wowowow\tizi",
226-
Time: kt,
227-
Level: slog.LevelDebug,
228-
229-
File: "myfile",
230-
Line: 100,
231-
Func: "mypkg.ignored",
232-
},
233-
},
234-
{
235-
"multilineMessage",
236-
slog.SinkEntry{
237-
Message: "line1\nline2",
238-
Level: slog.LevelInfo,
239-
},
240-
},
241-
{
242-
"multilineField",
243-
slog.SinkEntry{
244-
Message: "msg",
245-
Level: slog.LevelInfo,
246-
Fields: slog.M(slog.F("field", "line1\nline2")),
247-
},
248-
},
249-
{
250-
"named",
251-
slog.SinkEntry{
252-
Level: slog.LevelWarn,
253-
LoggerNames: []string{"some", "cat"},
254-
Message: "meow",
255-
Fields: slog.M(
256-
slog.F("breath", "stinky"),
257-
),
258-
},
259-
},
260-
{
261-
"funky",
262-
slog.SinkEntry{
263-
Level: slog.LevelWarn,
264-
Fields: slog.M(
265-
slog.F("funky^%&^&^key", "value"),
266-
slog.F("funky^%&^&^key2", "@#\t \t \n"),
267-
),
268-
},
269-
},
270-
{
271-
"spacey",
272-
slog.SinkEntry{
273-
Level: slog.LevelWarn,
274-
Fields: slog.M(
275-
slog.F("space in my key", "value in my value"),
276-
),
277-
},
278-
},
279-
{
280-
"nil",
281-
slog.SinkEntry{
282-
Level: slog.LevelWarn,
283-
Fields: slog.M(
284-
slog.F("nan", nil),
285-
),
286-
},
287-
},
288-
{
289-
"bytes",
290-
slog.SinkEntry{
291-
Level: slog.LevelWarn,
292-
Fields: slog.M(
293-
slog.F("somefile", []byte("blah bla\x01h blah")),
294-
),
295-
},
296-
},
297-
{
298-
"driverValue",
299-
slog.SinkEntry{
300-
Level: slog.LevelWarn,
301-
Fields: slog.M(
302-
slog.F("val", sql.NullString{String: "dog", Valid: true}),
303-
slog.F("inval", sql.NullString{String: "cat", Valid: false}),
304-
),
305-
},
306-
},
307-
{
308-
"object",
309-
slog.SinkEntry{
310-
Level: slog.LevelWarn,
311-
Fields: slog.M(
312-
slog.F("obj", slog.M(
313-
slog.F("obj1", testObj{
314-
foo: 1,
315-
bar: 2,
316-
dra: []byte("blah"),
317-
}),
318-
slog.F("obj2", testObj{
319-
foo: 3,
320-
bar: 4,
321-
dra: []byte("blah"),
322-
}),
323-
)),
324-
slog.F("map", map[string]string{
325-
"key1": "value1",
326-
}),
327-
),
328-
},
329-
},
330145
{
331146
"primitiveTypes",
332147
slog.SinkEntry{
@@ -401,19 +216,39 @@ func TestEntry_Optimized(t *testing.T) {
401216
},
402217
},
403218
}
219+
if *updateGoldenFiles {
220+
ents, err := os.ReadDir("testdata")
221+
if err != nil {
222+
t.Fatal(err)
223+
}
224+
for _, ent := range ents {
225+
os.Remove("testdata/" + ent.Name())
226+
}
227+
}
404228

405229
for _, tc := range ents {
406230
tc := tc
407231
t.Run(tc.name, func(t *testing.T) {
408232
t.Parallel()
233+
goldenPath := fmt.Sprintf("testdata/%s.golden", tc.name)
234+
235+
var gotBuf bytes.Buffer
236+
entryhuman.Fmt(&gotBuf, io.Discard, tc.ent)
409237

410-
var fmtBuf bytes.Buffer
411-
var optBuf bytes.Buffer
238+
if *updateGoldenFiles {
239+
err := os.WriteFile(goldenPath, gotBuf.Bytes(), 0o644)
240+
if err != nil {
241+
t.Fatal(err)
242+
}
243+
return
244+
}
412245

413-
entryhuman.Fmt(&fmtBuf, io.Discard, tc.ent)
414-
entryhuman.OptimizedFmt(&optBuf, io.Discard, tc.ent)
246+
wantByt, err := os.ReadFile(goldenPath)
247+
if err != nil {
248+
t.Fatal(err)
249+
}
415250

416-
assert.Equal(t, "outputs match", fmtBuf.String(), optBuf.String())
251+
assert.Equal(t, "entry matches", string(wantByt), gotBuf.String())
417252
})
418253
}
419254

@@ -429,7 +264,7 @@ func TestEntry_Optimized(t *testing.T) {
429264

430265
done := make(chan struct{}, 2)
431266
go func() {
432-
entryhuman.OptimizedFmt(new(bytes.Buffer), f, slog.SinkEntry{
267+
entryhuman.Fmt(new(bytes.Buffer), f, slog.SinkEntry{
433268
Level: slog.LevelCritical,
434269
Fields: slog.M(
435270
slog.F("hey", "hi"),
@@ -472,7 +307,7 @@ func BenchmarkFmt(b *testing.B) {
472307
b.ResetTimer()
473308
b.ReportAllocs()
474309
for i := 0; i < b.N; i++ {
475-
entryhuman.OptimizedFmt(bytes.NewBuffer(nil), w, se)
310+
entryhuman.Fmt(bytes.NewBuffer(nil), w, se)
476311
}
477312
})
478313
}

0 commit comments

Comments
 (0)