-
Notifications
You must be signed in to change notification settings - Fork 0
/
frog.go
136 lines (118 loc) · 3.59 KB
/
frog.go
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
package frog
import (
"io"
"os"
"github.com/mattn/go-isatty"
)
type NewLogger byte
const (
Auto NewLogger = iota
Basic
JSON
)
// HasTerminal returns true if the passed writer is connected to a terminal.
func HasTerminal(w io.Writer) bool {
f, ok := w.(*os.File)
if !ok {
return false
}
fd := f.Fd()
return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd)
}
// New creates a Logger that writes to os.Stdout, depending on the NewLogger type passed to it:
// - Auto - if terminal detected on stdout, then colors and anchored lines are supported (else, uses Basic)
// - Basic - no colors or anchored lines, no buffering
// - JSON - no colors or anchored lines, no buffering, and each line is a valid JSON object
// Resulting Logger can be modified by including 1 or more NewOpts after the NewLogger type.
// The caller is responsible for calling Close() when done with the returned Logger.
func New(t NewLogger, opts ...PrinterOption) RootLogger {
hasTerminal := false
if t == Auto {
hasTerminal = HasTerminal(os.Stdout)
if !hasTerminal {
t = Basic
}
}
switch t {
case Auto:
prn := TextPrinter{palette: DefaultPalette.toANSI(), printTime: true, printLevel: true, fieldIndent: 20}
return NewBuffered(os.Stdout, hasTerminal, prn.SetOptions(opts...))
case Basic:
prn := TextPrinter{printTime: true, printLevel: true, fieldIndent: 20}
return NewUnbuffered(os.Stdout, prn.SetOptions(opts...))
case JSON:
return NewUnbuffered(os.Stdout, &JSONPrinter{})
}
return nil
}
// AddAnchor adds a new logger on an anchored line (if supported).
// Else, returns passed in Logger.
func AddAnchor(log Logger) Logger {
var aa AnchorAdder
var ok bool
// search up the chain of parents for something that supports adding anchors
tmp := log
for {
if tmp == nil {
break
}
aa, ok = tmp.(AnchorAdder)
if ok {
break
}
tmp = Parent(tmp)
}
// If there's no AnchorAdder available, then just wrap the given Logger in a NoAnchorLogger.
// Note that we can't just return the original Logger here, as the caller is expecting an extra
// level of indirection.
if aa == nil {
return newNoAnchor(log)
}
alog := aa.AddAnchor(log)
if alog == nil {
return log
}
return alog
}
// RemoveAnchor needs to be passed the logger that was returned by AddAnchor.
// It can also work by being passed a child of that Logger.
func RemoveAnchor(log Logger) {
var ar AnchorRemover
var ok bool
// search up the chain of parents for something that supports removing anchors
tmp := log
for {
if tmp == nil {
break
}
ar, ok = tmp.(AnchorRemover)
if ok {
ar.RemoveAnchor()
break
}
tmp = Parent(tmp)
}
}
func Parent(log Logger) Logger {
child, ok := log.(ChildLogger)
if !ok {
return nil
}
return child.Parent()
}
// WithFields creates a new Logger that wraps the parent logger, adding the specified
// fields when the returned Logger is used, but leaving the parent unmodified.
func WithFields(log Logger, fielders ...Fielder) Logger {
return newCustomizerLogger(log, nil, fielders)
}
// WithOptions creates a new Logger that wraps the passed Logger, adding the specified
// PrinterOptions when the returned Logger is used, but leaving the parent unmodified.
func WithOptions(log Logger, opts ...PrinterOption) Logger {
return newCustomizerLogger(log, opts, nil)
}
// WithOptionsAndFields creates a new Logger that wraps the passed Logger, adding the
// specified fields and PrinterOptions when the return Logger is used, but leaving
// the parent unmodified.
func WithOptionsAndFields(log Logger, opts []PrinterOption, fielders []Fielder) Logger {
return newCustomizerLogger(log, opts, fielders)
}