Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: set custom styles #84

Merged
merged 1 commit into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Logger struct {
fields []interface{}

helpers *sync.Map
styles *Styles
}

func (l *Logger) log(level Level, msg interface{}, keyvals ...interface{}) {
Expand Down Expand Up @@ -290,15 +291,28 @@ func (l *Logger) SetColorProfile(profile termenv.Profile) {
l.re.SetColorProfile(profile)
}

// SetStyles sets the logger styles for the TextFormatter.
func (l *Logger) SetStyles(s *Styles) {
if s == nil {
s = DefaultStyles()
}
l.mu.Lock()
defer l.mu.Unlock()
l.styles = s
}

// With returns a new logger with the given keyvals added.
func (l *Logger) With(keyvals ...interface{}) *Logger {
var st Styles
l.mu.Lock()
sl := *l
st = *l.styles
l.mu.Unlock()
sl.b = bytes.Buffer{}
sl.mu = &sync.RWMutex{}
sl.helpers = &sync.Map{}
sl.fields = append(l.fields, keyvals...)
sl.styles = &st
return &sl
}

Expand Down
6 changes: 6 additions & 0 deletions pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@

l.SetOutput(w)
l.SetLevel(Level(l.level))
l.SetStyles(DefaultStyles())

if l.callerFormatter == nil {
l.callerFormatter = ShortCallerFormatter
Expand Down Expand Up @@ -132,6 +133,11 @@
defaultLogger.SetColorProfile(profile)
}

// SetStyles sets the logger styles for the TextFormatter.
func SetStyles(s *Styles) {
defaultLogger.SetStyles(s)

Check warning on line 138 in pkg.go

View check run for this annotation

Codecov / codecov/patch

pkg.go#L137-L138

Added lines #L137 - L138 were not covered by tests
}

// GetPrefix returns the prefix for the default logger.
func GetPrefix() string {
return defaultLogger.GetPrefix()
Expand Down
161 changes: 77 additions & 84 deletions styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,99 +6,92 @@ import (
"github.com/charmbracelet/lipgloss"
)

var (
// TimestampStyle is the style for timestamps.
TimestampStyle = lipgloss.NewStyle()
// Styles defines the styles for the text logger.
type Styles struct {
// Timestamp is the style for timestamps.
Timestamp lipgloss.Style

// CallerStyle is the style for caller.
CallerStyle = lipgloss.NewStyle().Faint(true)
// Caller is the style for source caller.
Caller lipgloss.Style

// PrefixStyle is the style for prefix.
PrefixStyle = lipgloss.NewStyle().Bold(true).Faint(true)
// Prefix is the style for prefix.
Prefix lipgloss.Style

// MessageStyle is the style for messages.
MessageStyle = lipgloss.NewStyle()
// Message is the style for messages.
Message lipgloss.Style

// KeyStyle is the style for keys.
KeyStyle = lipgloss.NewStyle().Faint(true)
// Key is the style for keys.
Key lipgloss.Style

// ValueStyle is the style for values.
ValueStyle = lipgloss.NewStyle()
// Value is the style for values.
Value lipgloss.Style

// SeparatorStyle is the style for separators.
SeparatorStyle = lipgloss.NewStyle().Faint(true)
// Separator is the style for separators.
Separator lipgloss.Style

// DebugLevel is the style for debug level.
DebugLevelStyle = lipgloss.NewStyle().
SetString(strings.ToUpper(DebugLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "63",
Dark: "63",
})
// Levels are the styles for each level.
Levels map[Level]lipgloss.Style

// InfoLevel is the style for info level.
InfoLevelStyle = lipgloss.NewStyle().
SetString(strings.ToUpper(InfoLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "39",
Dark: "86",
})
// Keys overrides styles for specific keys.
Keys map[string]lipgloss.Style

// WarnLevel is the style for warn level.
WarnLevelStyle = lipgloss.NewStyle().
SetString(strings.ToUpper(WarnLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "208",
Dark: "192",
})

// ErrorLevel is the style for error level.
ErrorLevelStyle = lipgloss.NewStyle().
SetString(strings.ToUpper(ErrorLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "203",
Dark: "204",
})

// FatalLevel is the style for error level.
FatalLevelStyle = lipgloss.NewStyle().
SetString(strings.ToUpper(FatalLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "133",
Dark: "134",
})

// KeyStyles overrides styles for specific keys.
KeyStyles = map[string]lipgloss.Style{}

// ValueStyles overrides value styles for specific keys.
ValueStyles = map[string]lipgloss.Style{}
)
// Values overrides value styles for specific keys.
Values map[string]lipgloss.Style
}

// levelStyle is a helper function to get the style for a level.
func levelStyle(level Level) lipgloss.Style {
switch level {
case DebugLevel:
return DebugLevelStyle
case InfoLevel:
return InfoLevelStyle
case WarnLevel:
return WarnLevelStyle
case ErrorLevel:
return ErrorLevelStyle
case FatalLevel:
return FatalLevelStyle
default:
return lipgloss.NewStyle()
// DefaultStyles returns the default styles.
func DefaultStyles() *Styles {
return &Styles{
Timestamp: lipgloss.NewStyle(),
Caller: lipgloss.NewStyle().Faint(true),
Prefix: lipgloss.NewStyle().Bold(true).Faint(true),
Message: lipgloss.NewStyle(),
Key: lipgloss.NewStyle().Faint(true),
Value: lipgloss.NewStyle(),
Separator: lipgloss.NewStyle().Faint(true),
Levels: map[Level]lipgloss.Style{
DebugLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(DebugLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "63",
Dark: "63",
}),
InfoLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(InfoLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "39",
Dark: "86",
}),
WarnLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(WarnLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "208",
Dark: "192",
}),
ErrorLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(ErrorLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "203",
Dark: "204",
}),
FatalLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(FatalLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.AdaptiveColor{
Light: "133",
Dark: "134",
}),
},
Keys: map[string]lipgloss.Style{},
Values: map[string]lipgloss.Style{},
}
}
40 changes: 24 additions & 16 deletions text.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ const (
)

func (l *Logger) writeIndent(w io.Writer, str string, indent string, newline bool, key string) {
st := l.styles

// kindly borrowed from hclog
for {
nl := strings.IndexByte(str, '\n')
if nl == -1 {
if str != "" {
_, _ = w.Write([]byte(indent))
val := escapeStringForOutput(str, false)
if valueStyle, ok := ValueStyles[key]; ok {
if valueStyle, ok := st.Values[key]; ok {
val = valueStyle.Renderer(l.re).Render(val)
} else {
val = ValueStyle.Renderer(l.re).Render(val)
val = st.Value.Renderer(l.re).Render(val)
}
_, _ = w.Write([]byte(val))
if newline {
Expand All @@ -38,7 +40,7 @@ func (l *Logger) writeIndent(w io.Writer, str string, indent string, newline boo

_, _ = w.Write([]byte(indent))
val := escapeStringForOutput(str[:nl], false)
val = ValueStyle.Renderer(l.re).Render(val)
val = st.Value.Renderer(l.re).Render(val)
_, _ = w.Write([]byte(val))
_, _ = w.Write([]byte{'\n'})
str = str[nl+1:]
Expand Down Expand Up @@ -148,6 +150,7 @@ func writeSpace(w io.Writer, first bool) {
}

func (l *Logger) textFormatter(keyvals ...interface{}) {
st := l.styles
lenKeyvals := len(keyvals)

for i := 0; i < lenKeyvals; i += 2 {
Expand All @@ -158,41 +161,46 @@ func (l *Logger) textFormatter(keyvals ...interface{}) {
case TimestampKey:
if t, ok := keyvals[i+1].(time.Time); ok {
ts := t.Format(l.timeFormat)
ts = TimestampStyle.Renderer(l.re).Render(ts)
ts = st.Timestamp.Renderer(l.re).Render(ts)
writeSpace(&l.b, firstKey)
l.b.WriteString(ts)
}
case LevelKey:
if level, ok := keyvals[i+1].(Level); ok {
lvl := levelStyle(level).Renderer(l.re).String()
writeSpace(&l.b, firstKey)
l.b.WriteString(lvl)
var lvl string
if lvlStyle, ok := st.Levels[level]; ok {
lvl = lvlStyle.Renderer(l.re).String()
}
if lvl != "" {
writeSpace(&l.b, firstKey)
l.b.WriteString(lvl)
}
}
case CallerKey:
if caller, ok := keyvals[i+1].(string); ok {
caller = fmt.Sprintf("<%s>", caller)
caller = CallerStyle.Renderer(l.re).Render(caller)
caller = st.Caller.Renderer(l.re).Render(caller)
writeSpace(&l.b, firstKey)
l.b.WriteString(caller)
}
case PrefixKey:
if prefix, ok := keyvals[i+1].(string); ok {
prefix = PrefixStyle.Renderer(l.re).Render(prefix + ":")
prefix = st.Prefix.Renderer(l.re).Render(prefix + ":")
writeSpace(&l.b, firstKey)
l.b.WriteString(prefix)
}
case MessageKey:
if msg := keyvals[i+1]; msg != nil {
m := fmt.Sprint(msg)
m = MessageStyle.Renderer(l.re).Render(m)
m = st.Message.Renderer(l.re).Render(m)
writeSpace(&l.b, firstKey)
l.b.WriteString(m)
}
default:
sep := separator
indentSep := indentSeparator
sep = SeparatorStyle.Renderer(l.re).Render(sep)
indentSep = SeparatorStyle.Renderer(l.re).Render(indentSep)
sep = st.Separator.Renderer(l.re).Render(sep)
indentSep = st.Separator.Renderer(l.re).Render(indentSep)
key := fmt.Sprint(keyvals[i])
val := fmt.Sprintf("%+v", keyvals[i+1])
raw := val == ""
Expand All @@ -203,14 +211,14 @@ func (l *Logger) textFormatter(keyvals ...interface{}) {
continue
}
actualKey := key
valueStyle := ValueStyle
if vs, ok := ValueStyles[actualKey]; ok {
valueStyle := st.Value
if vs, ok := st.Values[actualKey]; ok {
valueStyle = vs
}
if keyStyle, ok := KeyStyles[key]; ok {
if keyStyle, ok := st.Keys[key]; ok {
key = keyStyle.Renderer(l.re).Render(key)
} else {
key = KeyStyle.Renderer(l.re).Render(key)
key = st.Key.Renderer(l.re).Render(key)
}

// Values may contain multiple lines, and that format
Expand Down
Loading
Loading