@@ -20,7 +20,13 @@ import (
20
20
"golang.org/x/exp/slices"
21
21
)
22
22
23
- const timeRE = `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|[+-]\d{2}:\d{2})`
23
+ // textTimeRE is a regexp to match log timestamps for Text handler.
24
+ // This is RFC3339Nano with the fixed 3 digit sub-second precision.
25
+ const textTimeRE = `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|[+-]\d{2}:\d{2})`
26
+
27
+ // jsonTimeRE is a regexp to match log timestamps for Text handler.
28
+ // This is RFC3339Nano with an arbitrary sub-second precision.
29
+ const jsonTimeRE = `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})`
24
30
25
31
func TestLogTextHandler (t * testing.T ) {
26
32
var buf bytes.Buffer
@@ -30,7 +36,7 @@ func TestLogTextHandler(t *testing.T) {
30
36
check := func (want string ) {
31
37
t .Helper ()
32
38
if want != "" {
33
- want = "time=" + timeRE + " " + want
39
+ want = "time=" + textTimeRE + " " + want
34
40
}
35
41
checkLogOutput (t , buf .String (), want )
36
42
buf .Reset ()
@@ -112,7 +118,7 @@ func TestConnections(t *testing.T) {
112
118
// log.Logger's output goes through the handler.
113
119
SetDefault (New (NewTextHandler (& slogbuf , & HandlerOptions {AddSource : true })))
114
120
log .Print ("msg2" )
115
- checkLogOutput (t , slogbuf .String (), "time=" + timeRE + ` level=INFO source=.*logger_test.go:\d{3} msg=msg2` )
121
+ checkLogOutput (t , slogbuf .String (), "time=" + textTimeRE + ` level=INFO source=.*logger_test.go:\d{3} msg=msg2` )
116
122
117
123
// The default log.Logger always outputs at Info level.
118
124
slogbuf .Reset ()
@@ -371,7 +377,7 @@ func TestNewLogLogger(t *testing.T) {
371
377
h := NewTextHandler (& buf , nil )
372
378
ll := NewLogLogger (h , LevelWarn )
373
379
ll .Print ("hello" )
374
- checkLogOutput (t , buf .String (), "time=" + timeRE + ` level=WARN msg=hello` )
380
+ checkLogOutput (t , buf .String (), "time=" + textTimeRE + ` level=WARN msg=hello` )
375
381
}
376
382
377
383
func checkLogOutput (t * testing.T , got , wantRegexp string ) {
@@ -507,3 +513,64 @@ func callerPC(depth int) uintptr {
507
513
runtime .Callers (depth , pcs [:])
508
514
return pcs [0 ]
509
515
}
516
+
517
+ // panicTextAndJsonMarshaler is a type that panics in MarshalText and MarshalJSON.
518
+ type panicTextAndJsonMarshaler struct {
519
+ msg any
520
+ }
521
+
522
+ func (p panicTextAndJsonMarshaler ) MarshalText () ([]byte , error ) {
523
+ panic (p .msg )
524
+ }
525
+
526
+ func (p panicTextAndJsonMarshaler ) MarshalJSON () ([]byte , error ) {
527
+ panic (p .msg )
528
+ }
529
+
530
+ func TestPanics (t * testing.T ) {
531
+ // Revert any changes to the default logger. This is important because other
532
+ // tests might change the default logger using SetDefault. Also ensure we
533
+ // restore the default logger at the end of the test.
534
+ currentLogger := Default ()
535
+ currentLogWriter := log .Writer ()
536
+ currentLogFlags := log .Flags ()
537
+ t .Cleanup (func () {
538
+ SetDefault (currentLogger )
539
+ log .SetOutput (currentLogWriter )
540
+ log .SetFlags (currentLogFlags )
541
+ })
542
+
543
+ var logBuf bytes.Buffer
544
+ log .SetOutput (& logBuf )
545
+ log .SetFlags (log .Lshortfile &^ log .LstdFlags )
546
+
547
+ SetDefault (New (newDefaultHandler (log .Output )))
548
+ for _ , pt := range []struct {
549
+ in any
550
+ out string
551
+ }{
552
+ {(* panicTextAndJsonMarshaler )(nil ), `logger_test.go:\d+: INFO msg p=<nil>` },
553
+ {panicTextAndJsonMarshaler {io .ErrUnexpectedEOF }, `logger_test.go:\d+: INFO msg p="!PANIC: unexpected EOF"` },
554
+ {panicTextAndJsonMarshaler {"panicking" }, `logger_test.go:\d+: INFO msg p="!PANIC: panicking"` },
555
+ {panicTextAndJsonMarshaler {42 }, `logger_test.go:\d+: INFO msg p="!PANIC: 42"` },
556
+ } {
557
+ Info ("msg" , "p" , pt .in )
558
+ checkLogOutput (t , logBuf .String (), pt .out )
559
+ logBuf .Reset ()
560
+ }
561
+
562
+ SetDefault (New (NewJSONHandler (& logBuf , nil )))
563
+ for _ , pt := range []struct {
564
+ in any
565
+ out string
566
+ }{
567
+ {(* panicTextAndJsonMarshaler )(nil ), `{"time":"` + jsonTimeRE + `","level":"INFO","msg":"msg","p":null}` },
568
+ {panicTextAndJsonMarshaler {io .ErrUnexpectedEOF }, `{"time":"` + jsonTimeRE + `","level":"INFO","msg":"msg","p":"!PANIC: unexpected EOF"}` },
569
+ {panicTextAndJsonMarshaler {"panicking" }, `{"time":"` + jsonTimeRE + `","level":"INFO","msg":"msg","p":"!PANIC: panicking"}` },
570
+ {panicTextAndJsonMarshaler {42 }, `{"time":"` + jsonTimeRE + `","level":"INFO","msg":"msg","p":"!PANIC: 42"}` },
571
+ } {
572
+ Info ("msg" , "p" , pt .in )
573
+ checkLogOutput (t , logBuf .String (), pt .out )
574
+ logBuf .Reset ()
575
+ }
576
+ }
0 commit comments