This repository has been archived by the owner on Aug 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
/
clog.go
136 lines (118 loc) · 3.39 KB
/
clog.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 clog
import (
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/fatih/color"
"golang.org/x/xerrors"
)
var writer io.Writer = os.Stderr
// SetOutput sets the package-level writer target for log functions.
func SetOutput(w io.Writer) {
writer = w
}
// CLIMessage provides a human-readable message for CLI errors and messages.
type CLIMessage struct {
Level string
Color color.Attribute
Header string
Lines []string
}
// CLIError wraps a CLIMessage and allows consumers to treat it as a normal error.
type CLIError struct {
CLIMessage
error
}
// String formats the CLI message for consumption by a human.
func (m CLIMessage) String() string {
var str strings.Builder
str.WriteString(fmt.Sprintf("%s: %s\n",
color.New(m.Color).Sprint(m.Level),
color.New(color.Bold).Sprint(m.Header)),
)
for _, line := range m.Lines {
str.WriteString(fmt.Sprintf(" %s %s\n", color.New(m.Color).Sprint("|"), line))
}
return str.String()
}
// Log logs the given error to stderr, defaulting to "fatal" if the error is not a CLIError.
// If the error is a CLIError, the plain error chain is ignored and the CLIError
// is logged on its own.
func Log(err error) {
var cliErr CLIError
if !xerrors.As(err, &cliErr) {
cliErr = Fatal(err.Error())
}
fmt.Fprintln(writer, cliErr.String())
}
// LogInfo prints the given info message to stderr.
func LogInfo(header string, lines ...string) {
fmt.Fprint(writer, CLIMessage{
Level: "info",
Color: color.FgBlue,
Header: header,
Lines: lines,
}.String())
}
// LogSuccess prints the given info message to stderr.
func LogSuccess(header string, lines ...string) {
fmt.Fprint(writer, CLIMessage{
Level: "success",
Color: color.FgGreen,
Header: header,
Lines: lines,
}.String())
}
// LogWarn prints the given warn message to stderr.
func LogWarn(header string, lines ...string) {
fmt.Fprint(writer, CLIMessage{
Level: "warning",
Color: color.FgYellow,
Header: header,
Lines: lines,
}.String())
}
// Error creates an error with the level "error".
func Error(header string, lines ...string) CLIError {
return CLIError{
CLIMessage: CLIMessage{
Color: color.FgRed,
Level: "error",
Header: header,
Lines: lines,
},
error: errors.New(header),
}
}
// Fatal creates an error with the level "fatal".
func Fatal(header string, lines ...string) CLIError {
return CLIError{
CLIMessage: CLIMessage{
Color: color.FgRed,
Level: "fatal",
Header: header,
Lines: lines,
},
error: errors.New(header),
}
}
// Bold provides a convenience wrapper around color.New for brevity when logging.
func Bold(a string) string {
return color.New(color.Bold).Sprint(a)
}
// Tipf formats according to the given format specifier and prepends a bolded "tip: " header.
func Tipf(format string, a ...interface{}) string {
return fmt.Sprintf("%s %s", Bold("tip:"), fmt.Sprintf(format, a...))
}
// Hintf formats according to the given format specifier and prepends a bolded "hint: " header.
func Hintf(format string, a ...interface{}) string {
return fmt.Sprintf("%s %s", Bold("hint:"), fmt.Sprintf(format, a...))
}
// Causef formats according to the given format specifier and prepends a bolded "cause: " header.
func Causef(format string, a ...interface{}) string {
return fmt.Sprintf("%s %s", Bold("cause:"), fmt.Sprintf(format, a...))
}
// BlankLine is an empty string meant to be used in CLIMessage and CLIError construction.
const BlankLine = ""