Newer
Older
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
package orusapi
import (
"fmt"
"io"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"golang.org/x/crypto/ssh/terminal"
)
// DefaultLogger ...
func DefaultLogger(output io.Writer) zerolog.Logger {
return zerolog.
New(output).
With().
Timestamp().
Logger().
Level(zerolog.WarnLevel)
}
// LoggingOptions holds the logging options
type LoggingOptions struct {
Level func(string) error `long:"log-level" env:"LOG_LEVEL" ini-name:"log-level" choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal" choice:"panic" choice:"auto" default:"auto" description:"log level. 'auto' selects 'info' when stdout is a tty, 'error' otherwise."`
Format func(string) error `long:"log-format" env:"LOG_FORMAT" ini-name:"log-format" choice:"json" choice:"pretty" choice:"auto" default:"auto" description:"Logs format. 'auto' selects 'pretty' if stdout is a tty."`
Verbose func() `short:"v" long:"verbose" no-ini:"t" description:"Increase log verbosity. Can be repeated"`
logFinalOutput io.Writer `no-flag:"t"`
logOutput io.Writer `no-flag:"t"`
logWrappers []func(io.Writer) io.Writer `no-flag:"t"`
log *zerolog.Logger `no-flag:"t"`
}
func (o *LoggingOptions) resetOutput() {
out := o.logOutput
for _, wrapper := range o.logWrappers {
out = wrapper(out)
}
*o.log = o.log.Output(out)
}
// AddLogWrapper adds a log wrapper to the stack
func (o *LoggingOptions) AddLogWrapper(wrapper func(io.Writer) io.Writer) {
o.logWrappers = append(o.logWrappers, wrapper)
o.resetOutput()
}
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
// SetMinLoggingLevel makes sure the logging level is not under a given value
func (o *LoggingOptions) SetMinLoggingLevel(level zerolog.Level) {
if level < o.log.GetLevel() {
*o.log = log.Level(level)
}
}
// Setup ...
func (o *LoggingOptions) Setup(log *zerolog.Logger, output io.Writer) error {
var logLevelAutoLocked = false
o.logFinalOutput = output
o.log = log
*o.log = DefaultLogger(output)
o.Format = func(format string) error {
if format == "auto" {
if outputFile, hasFd := o.logFinalOutput.(interface{ Fd() uintptr }); hasFd && terminal.IsTerminal(int(outputFile.Fd())) {
format = "pretty"
} else {
format = "json"
}
}
switch format {
case "pretty":
o.logOutput = ConsoleWriter{Out: o.logFinalOutput}
case "json":
o.logOutput = o.logFinalOutput
default:
return fmt.Errorf("invalid log-format: %s", format)
}
o.resetOutput()
return nil
}
o.Verbose = func() {
*o.log = o.log.Level(o.log.GetLevel() - zerolog.Level(1))
}
o.Level = func(value string) error {
if value == "auto" {
if logLevelAutoLocked {
// The current call is at best redondant, at worse called by
// default after some potential --verbose that would be ignored
return nil
}
if outputFile, hasFd := o.logFinalOutput.(interface{ Fd() uintptr }); hasFd && terminal.IsTerminal(int(outputFile.Fd())) {
value = "info"
} else {
value = "warn"
}
}
level, err := zerolog.ParseLevel(value)
if err != nil {
return err
}
*o.log = o.log.Level(level)
return nil
}
if err := o.Format("auto"); err != nil {
return err
}
if err := o.Level("auto"); err != nil {
return err
}
logLevelAutoLocked = true
return nil
}