diff --git a/LICENSE b/LICENSE index 967c67a..3d2e904 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Charmbracelet, Inc +Copyright (c) 2022-2023 Charmbracelet, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f9e67ec..a43ac7b 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,9 @@ log.Error("Whoops!", "err", "kitchen on fire") Create sub-loggers with their specific fields. ```go +logger := log.NewWithOptions(os.Stderr, log.Options{ + Prefix: "Baking 🍪 " +}) batch2 := logger.With("batch", 2, "chocolateChips", true) batch2.Debug("Preparing batch 2...") batch2.Debug("Adding chocolate chips") diff --git a/go.mod b/go.mod index 1bf2b41..e6a13ea 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/charmbracelet/lipgloss v0.7.1 github.com/go-logfmt/logfmt v0.6.0 - github.com/mattn/go-isatty v0.0.17 + github.com/muesli/termenv v0.15.1 github.com/stretchr/testify v1.8.2 golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 ) @@ -14,9 +14,9 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/muesli/reflow v0.3.0 // indirect - github.com/muesli/termenv v0.15.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect golang.org/x/sys v0.6.0 // indirect diff --git a/go.sum b/go.sum index 2a0d427..3065d4d 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,9 @@ github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= diff --git a/logger.go b/logger.go index b81aaf0..f4db590 100644 --- a/logger.go +++ b/logger.go @@ -15,6 +15,7 @@ import ( "github.com/charmbracelet/lipgloss" "golang.org/x/exp/slog" + "github.com/muesli/termenv" ) var ( @@ -319,7 +320,13 @@ func (l *Logger) SetOutput(w io.Writer) { isDiscard = 1 } atomic.StoreUint32(&l.isDiscard, isDiscard) - l.re = lipgloss.NewRenderer(w) + // Reuse cached renderers + if v, ok := registry.Load(w); ok { + l.re = v.(*lipgloss.Renderer) + } else { + l.re = lipgloss.NewRenderer(w, termenv.WithColorCache(true)) + registry.Store(w, l.re) + } } // SetFormatter sets the formatter. diff --git a/pkg.go b/pkg.go index b0e938a..234da28 100644 --- a/pkg.go +++ b/pkg.go @@ -10,7 +10,13 @@ import ( "time" ) -var defaultLogger = NewWithOptions(os.Stderr, Options{ReportTimestamp: true}) +var ( + // registry is a map of all registered lipgloss renderers. + registry = sync.Map{} + + // defaultLogger is the default global logger instance. + defaultLogger = NewWithOptions(os.Stderr, Options{ReportTimestamp: true}) +) // Default returns the default logger. The default logger comes with timestamp enabled. func Default() *Logger { diff --git a/terminal.go b/terminal.go deleted file mode 100644 index b2fc332..0000000 --- a/terminal.go +++ /dev/null @@ -1,22 +0,0 @@ -package log - -import ( - "io" - "os" - - "github.com/mattn/go-isatty" -) - -func isTerminal(w io.Writer) bool { - if len(os.Getenv("CI")) > 0 { - return false - } - - if f, ok := w.(interface { - Fd() uintptr - }); ok { - return isatty.IsTerminal(f.Fd()) - } - - return false -}