parent
1050a04a88
commit
11378d6bc2
|
@ -48,4 +48,6 @@ Beaver allows you to customize the colors of various parts of the message
|
|||
```go
|
||||
// Set Trace logging to Magenta instead of Bold-Cyan
|
||||
color.Trace = color.New(color.FgMagenta)
|
||||
```
|
||||
```
|
||||
|
||||
[More info for the `color` package](color/README.md)
|
|
@ -0,0 +1,46 @@
|
|||
# Color
|
||||
|
||||
Beaver comes with the `color` sub-package that can be used even without Beaver calls.
|
||||
|
||||
## Formatting a string with a single attribute
|
||||
```go
|
||||
text := color.FgRed.Format("red")
|
||||
```
|
||||
|
||||
## Formatting a string with a full color
|
||||
```go
|
||||
c := color.New(color.BgGreen, color.FgRed, color.Bold)
|
||||
text := c.Format("green background, red text, and bold")
|
||||
```
|
||||
|
||||
## Formatting strings with multiple colors
|
||||
The following are different ways to print `This is a color test!`
|
||||
where the word `color` is red while everything else is `green`.
|
||||
|
||||
### setup
|
||||
Assuming each example is preceded by
|
||||
```go
|
||||
green := color.New(color.FgGreen)
|
||||
red := color.New(color.FgRed)
|
||||
```
|
||||
|
||||
#### pure `fmt.Println`
|
||||
```go
|
||||
fmt.Println(green.Format("This is a"), red.Format("color"), green.Format("test!"))
|
||||
```
|
||||
|
||||
#### `color.Wrap`
|
||||
```go
|
||||
fmt.Println(green.Wrap("This is a #{color} test!", red))
|
||||
```
|
||||
|
||||
#### string formatting with `fmt.Printf` and `color.Wrap`
|
||||
```go
|
||||
fmt.Printf(green.Wrap("This is a #{%s} test!\n", red), "color")
|
||||
```
|
||||
|
||||
#### using a different directive prefix
|
||||
```go
|
||||
color.DirectivePrefix('$')
|
||||
fmt.Printf(green.Wrap("This is a ${%s} test!\n", red), "color")
|
||||
```
|
|
@ -0,0 +1,87 @@
|
|||
package color
|
||||
|
||||
// Attribute defines a single SGR Code
|
||||
type Attribute int
|
||||
|
||||
// Logger attributes
|
||||
const (
|
||||
Reset Attribute = iota
|
||||
Bold
|
||||
Faint
|
||||
Italic
|
||||
Underline
|
||||
BlinkSlow
|
||||
BlinkRapid
|
||||
ReverseVideo
|
||||
Concealed
|
||||
CrossedOut
|
||||
)
|
||||
|
||||
// Foreground text colors
|
||||
const (
|
||||
FgBlack Attribute = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta
|
||||
FgCyan
|
||||
FgWhite
|
||||
)
|
||||
|
||||
// Foreground Hi-Intensity text colors
|
||||
const (
|
||||
FgHiBlack Attribute = iota + 90
|
||||
FgHiRed
|
||||
FgHiGreen
|
||||
FgHiYellow
|
||||
FgHiBlue
|
||||
FgHiMagenta
|
||||
FgHiCyan
|
||||
FgHiWhite
|
||||
)
|
||||
|
||||
// Background text colors
|
||||
const (
|
||||
BgBlack Attribute = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
)
|
||||
|
||||
// Background Hi-Intensity text colors
|
||||
const (
|
||||
BgHiBlack Attribute = iota + 100
|
||||
BgHiRed
|
||||
BgHiGreen
|
||||
BgHiYellow
|
||||
BgHiBlue
|
||||
BgHiMagenta
|
||||
BgHiCyan
|
||||
BgHiWhite
|
||||
)
|
||||
|
||||
var attrCache = make(map[string]*Color)
|
||||
|
||||
func attr(a Attribute) *Color {
|
||||
if c, ok := attrCache[string(a)]; ok {
|
||||
return c
|
||||
}
|
||||
c := New(a)
|
||||
attrCache[string(a)] = c
|
||||
return c
|
||||
}
|
||||
|
||||
// Format is a quick way to format a string using a single attribute
|
||||
func (a Attribute) Format(text string) string {
|
||||
return attr(a).Format(text)
|
||||
}
|
||||
|
||||
// Format is a quick way to format a formatted string using a single attribute
|
||||
func (a Attribute) Formatf(text string, v ...interface{}) string {
|
||||
return attr(a).Formatf(text, v...)
|
||||
}
|
121
color/color.go
121
color/color.go
|
@ -2,82 +2,28 @@ package color
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
var (
|
||||
directive = `{[^}]*}`
|
||||
directiveRe = regexp.MustCompile("[#]" + directive)
|
||||
)
|
||||
|
||||
// DirectivePrefix changes the directive prefix for parsing color wrap directives
|
||||
func DirectivePrefix(p rune) {
|
||||
directiveRe = regexp.MustCompile("[" + string(p) + "]" + directive)
|
||||
}
|
||||
|
||||
// Color defines a custom color object which is defined by SGR parameters.
|
||||
type Color struct {
|
||||
Attrs []Attribute
|
||||
}
|
||||
|
||||
// Attribute defines a single SGR Code
|
||||
type Attribute int
|
||||
|
||||
const escape = "\x1b"
|
||||
|
||||
// Logger attributes
|
||||
const (
|
||||
Reset Attribute = iota
|
||||
Bold
|
||||
Faint
|
||||
Italic
|
||||
Underline
|
||||
BlinkSlow
|
||||
BlinkRapid
|
||||
ReverseVideo
|
||||
Concealed
|
||||
CrossedOut
|
||||
)
|
||||
|
||||
// Foreground text colors
|
||||
const (
|
||||
FgBlack Attribute = iota + 30
|
||||
FgRed
|
||||
FgGreen
|
||||
FgYellow
|
||||
FgBlue
|
||||
FgMagenta
|
||||
FgCyan
|
||||
FgWhite
|
||||
)
|
||||
|
||||
// Foreground Hi-Intensity text colors
|
||||
const (
|
||||
FgHiBlack Attribute = iota + 90
|
||||
FgHiRed
|
||||
FgHiGreen
|
||||
FgHiYellow
|
||||
FgHiBlue
|
||||
FgHiMagenta
|
||||
FgHiCyan
|
||||
FgHiWhite
|
||||
)
|
||||
|
||||
// Background text colors
|
||||
const (
|
||||
BgBlack Attribute = iota + 40
|
||||
BgRed
|
||||
BgGreen
|
||||
BgYellow
|
||||
BgBlue
|
||||
BgMagenta
|
||||
BgCyan
|
||||
BgWhite
|
||||
)
|
||||
|
||||
// Background Hi-Intensity text colors
|
||||
const (
|
||||
BgHiBlack Attribute = iota + 100
|
||||
BgHiRed
|
||||
BgHiGreen
|
||||
BgHiYellow
|
||||
BgHiBlue
|
||||
BgHiMagenta
|
||||
BgHiCyan
|
||||
BgHiWhite
|
||||
)
|
||||
|
||||
// New returns a new Color with attrs Attributes
|
||||
func New(attrs ...Attribute) *Color {
|
||||
return &Color{Attrs: attrs}
|
||||
|
@ -129,6 +75,7 @@ func unformat() string {
|
|||
return fmt.Sprintf("%s[%dm", escape, Reset)
|
||||
}
|
||||
|
||||
// Format returns a string wrapped in the color
|
||||
func (c *Color) Format(text string) string {
|
||||
if len(c.Attrs) > 0 {
|
||||
return c.wrap(text)
|
||||
|
@ -136,20 +83,26 @@ func (c *Color) Format(text string) string {
|
|||
return text
|
||||
}
|
||||
|
||||
// Formatf returns a formatted string wrapped in the color
|
||||
func (c *Color) Formatf(format string, v ...interface{}) string {
|
||||
return c.Format(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func (c *Color) Wrap(color *Color, text string) string {
|
||||
return unformat() + c.Format(text) + color.format()
|
||||
func parse(text string, primary, secondary *Color) string {
|
||||
for {
|
||||
loc := directiveRe.FindStringIndex(text)
|
||||
if loc == nil {
|
||||
break
|
||||
}
|
||||
text = text[:loc[0]] + unformat() + secondary.Format(text[loc[0]+2:loc[1]-1]) + primary.format() + text[loc[1]:]
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func (c *Color) Wrapf(color *Color, format string, v ...interface{}) string {
|
||||
args := make([]interface{}, len(v))
|
||||
for idx, arg := range v {
|
||||
args[idx] = color.Wrap(c, fmt.Sprintf("%v", arg))
|
||||
}
|
||||
return unformat() + c.Formatf(format, args...) + color.format()
|
||||
// Wrap returns a string wrapped in a primary color, with #{} directives wrapped in a secondary color
|
||||
func (c *Color) Wrap(text string, secondary *Color) string {
|
||||
text = parse(text, c, secondary)
|
||||
return c.Format(text)
|
||||
}
|
||||
|
||||
// ParseLevel parses a string and returns a Beaver Level's Color, defaulting to Info
|
||||
|
@ -172,18 +125,12 @@ func ParseLevel(level string) *Color {
|
|||
}
|
||||
|
||||
var (
|
||||
Trace = New(FgCyan)
|
||||
Tracef = New(Bold, FgCyan)
|
||||
Debug = New(FgBlue)
|
||||
Debugf = New(Bold, FgBlue)
|
||||
Info = New(FgGreen)
|
||||
Infof = New(Bold, FgGreen)
|
||||
Warn = New(FgYellow)
|
||||
Warnf = New(Bold, FgYellow)
|
||||
Error = New(FgRed)
|
||||
Errorf = New(Bold, FgRed)
|
||||
Fatal = New(BgRed)
|
||||
Fatalf = New(Bold, BgRed)
|
||||
Trace = New(Bold, FgCyan)
|
||||
Debug = New(Bold, FgBlue)
|
||||
Info = New(Bold, FgGreen)
|
||||
Warn = New(Bold, FgYellow)
|
||||
Error = New(Bold, FgRed)
|
||||
Fatal = New(Bold, BgRed)
|
||||
Default = New()
|
||||
Time = Default
|
||||
Stack = Default
|
||||
|
|
25
level.go
25
level.go
|
@ -8,10 +8,7 @@ import (
|
|||
"go.jolheiser.com/beaver/color"
|
||||
)
|
||||
|
||||
var (
|
||||
bold = color.New(color.Bold)
|
||||
italic = color.New(color.Italic)
|
||||
)
|
||||
var bold = color.New(color.Bold)
|
||||
|
||||
// Level defines a Beaver logging level
|
||||
type Level int
|
||||
|
@ -85,26 +82,6 @@ func (l Level) Color() *color.Color {
|
|||
}
|
||||
}
|
||||
|
||||
// Color returns a Level's colorf, defaulting to italic
|
||||
func (l Level) Colorf() *color.Color {
|
||||
switch l {
|
||||
case TRACE:
|
||||
return color.Tracef
|
||||
case DEBUG:
|
||||
return color.Debugf
|
||||
case INFO:
|
||||
return color.Infof
|
||||
case WARN:
|
||||
return color.Warnf
|
||||
case ERROR:
|
||||
return color.Errorf
|
||||
case FATAL:
|
||||
return color.Fatalf
|
||||
default:
|
||||
return italic
|
||||
}
|
||||
}
|
||||
|
||||
// Levels returns a list of Beaver logging levels
|
||||
func Levels() []Level {
|
||||
return []Level{TRACE, DEBUG, INFO, WARN, ERROR, FATAL}
|
||||
|
|
|
@ -26,7 +26,6 @@ type FormatOptions struct {
|
|||
LevelPrefix bool
|
||||
LevelColor bool
|
||||
MessageColor bool
|
||||
StyleArgs bool
|
||||
}
|
||||
|
||||
// New returns a new Beaver logger
|
||||
|
@ -41,12 +40,12 @@ func New(writer io.Writer, level Level, opts FormatOptions) *Logger {
|
|||
|
||||
func (l *Logger) write(level Level, text string) {
|
||||
if l.Level <= level {
|
||||
_, file, line, _ := runtime.Caller(l.skip)
|
||||
var message string
|
||||
if l.Format.TimePrefix {
|
||||
message += color.Time.Format(timePrefix(time.Now())) + " "
|
||||
}
|
||||
if l.Format.StackPrefix {
|
||||
_, file, line, _ := runtime.Caller(l.skip)
|
||||
idx := len(file) - l.Format.StackLimit
|
||||
if l.Format.StackLimit <= 0 {
|
||||
idx = 0
|
||||
|
@ -81,9 +80,6 @@ func (l *Logger) log(level Level, v ...interface{}) {
|
|||
|
||||
func (l *Logger) logf(level Level, format string, v ...interface{}) {
|
||||
text := fmt.Sprintf(format, v...)
|
||||
if l.Format.StyleArgs {
|
||||
|
||||
}
|
||||
l.write(level, text)
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue