0
0
forked from toolshed/abra

chore: vendor

This commit is contained in:
2024-08-04 11:06:58 +02:00
parent 2a5985e44e
commit 04aec8232f
3557 changed files with 981078 additions and 1 deletions

17
vendor/github.com/charmbracelet/log/.gitignore generated vendored Normal file
View File

@ -0,0 +1,17 @@
*.txt
*.gif
examples/batch2/batch2
examples/chocolate-chips/chocolate-chips
examples/cookie/cookie
examples/error/error
examples/format/format
examples/log/log
examples/new/new
examples/options/options
examples/oven/oven
examples/temperature/temperature
.vscode
.history
go.work

34
vendor/github.com/charmbracelet/log/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,34 @@
run:
tests: false
issues:
include:
- EXC0001
- EXC0005
- EXC0011
- EXC0012
- EXC0013
max-issues-per-linter: 0
max-same-issues: 0
linters:
enable:
- bodyclose
- dupl
- exportloopref
- goconst
- godot
- godox
- goimports
- goprintffuncname
- gosec
- misspell
- nolintlint
- prealloc
- revive
- rowserrcheck
- sqlclosecheck
- unconvert
- unparam
- whitespace

3
vendor/github.com/charmbracelet/log/.goreleaser.yml generated vendored Normal file
View File

@ -0,0 +1,3 @@
includes:
- from_url:
url: charmbracelet/meta/main/goreleaser-lib.yaml

21
vendor/github.com/charmbracelet/log/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

367
vendor/github.com/charmbracelet/log/README.md generated vendored Normal file
View File

@ -0,0 +1,367 @@
# Log
<p>
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/25087/219742757-c8afe0d9-608a-4845-a555-ef59c0af9ebc.png" width="359">
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/25087/219743408-3d7bef51-1409-40c0-8159-acc6e52f078e.png" width="359">
<img src="https://user-images.githubusercontent.com/25087/219742757-c8afe0d9-608a-4845-a555-ef59c0af9ebc.png" width="359" />
</picture>
<br>
<a href="https://github.com/charmbracelet/log/releases"><img src="https://img.shields.io/github/release/charmbracelet/log.svg" alt="Latest Release"></a>
<a href="https://pkg.go.dev/github.com/charmbracelet/log?tab=doc"><img src="https://godoc.org/github.com/golang/gddo?status.svg" alt="Go Docs"></a>
<a href="https://github.com/charmbracelet/log/actions"><img src="https://github.com/charmbracelet/log/workflows/build/badge.svg" alt="Build Status"></a>
<a href="https://codecov.io/gh/charmbracelet/log"><img alt="Codecov branch" src="https://img.shields.io/codecov/c/github/charmbracelet/log/main.svg"></a>
<a href="https://goreportcard.com/report/github.com/charmbracelet/log"><img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/charmbracelet/log"></a>
</p>
A minimal and colorful Go logging library. 🪵
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://vhs.charm.sh/vhs-1wBImk2iSIuiiD7Ib9rufi.gif">
<source media="(prefers-color-scheme: light)" srcset="https://vhs.charm.sh/vhs-1wBImk2iSIuiiD7Ib9rufi.gif">
<!-- <source media="(prefers-color-scheme: light)" srcset="https://vhs.charm.sh/vhs-2NvOYS29AauVRgRRPmquXx.gif"> -->
<img src="https://vhs.charm.sh/vhs-1wBImk2iSIuiiD7Ib9rufi.gif" alt="Made with VHS" />
</picture>
It provides a leveled structured human readable logger with a small API. Unlike
[standard `log`][stdlog], the Charm logger provides customizable colorful human
readable logging with batteries included.
- Uses [Lip Gloss][lipgloss] to style and colorize the output.
- Colorful, human readable format.
- Ability to customize the time stamp format.
- Skips caller frames and marks function as helpers.
- Leveled logging.
- Text, JSON, and Logfmt formatters.
- Store and retrieve logger in and from context.
- Slog handler.
- Standard log adapter.
## Usage
Use `go get` to download the dependency.
```bash
go get github.com/charmbracelet/log@latest
```
Then, `import` it in your Go files:
```go
import "github.com/charmbracelet/log"
```
The Charm logger comes with a global package-wise logger with timestamps turned
on, and the logging level set to `info`.
```go
log.Debug("Cookie 🍪") // won't print anything
log.Info("Hello World!")
```
<picture>
<source media="(prefers-color-scheme: dark)" width="400" srcset="https://vhs.charm.sh/vhs-cKiS8OuRrF1VVVpscM9e3.gif">
<source media="(prefers-color-scheme: light)" width="400" srcset="https://vhs.charm.sh/vhs-cKiS8OuRrF1VVVpscM9e3.gif">
<!-- <source media="(prefers-color-scheme: light)" width="400" srcset="https://vhs.charm.sh/vhs-4AeLaEuO3tDbECR1qe9Jvp.gif"> -->
<img width="400" src="https://vhs.charm.sh/vhs-4AeLaEuO3tDbECR1qe9Jvp.gif" alt="Made with VHS" />
</picture>
All logging levels accept optional key/value pairs to be printed along with a
message.
```go
err := fmt.Errorf("too much sugar")
log.Error("failed to bake cookies", "err", err)
```
<picture>
<source media="(prefers-color-scheme: dark)" width="600" srcset="https://vhs.charm.sh/vhs-65KIpGw4FTESK0IzkDB9VQ.gif" >
<source media="(prefers-color-scheme: light)" width="600" srcset="https://vhs.charm.sh/vhs-65KIpGw4FTESK0IzkDB9VQ.gif" >
<!-- <source media="(prefers-color-scheme: light)" width="600" srcset="https://vhs.charm.sh/vhs-7rk8wALXRDoFw8SLFwn9rW.gif"> -->
<img width="600" src="https://vhs.charm.sh/vhs-65KIpGw4FTESK0IzkDB9VQ.gif" alt="Made with VHS">
</picture>
You can use `log.Print()` to print messages without a level prefix.
```go
log.Print("Baking 101")
// 2023/01/04 10:04:06 Baking 101
```
### New loggers
Use `New()` to create new loggers.
```go
logger := log.New(os.Stderr)
if butter {
logger.Warn("chewy!", "butter", true)
}
```
<picture>
<source media="(prefers-color-scheme: dark)" width="300" srcset="https://vhs.charm.sh/vhs-3QQdzOW4Zc0bN2tOhAest9.gif">
<source media="(prefers-color-scheme: light)" width="300" srcset="https://vhs.charm.sh/vhs-3QQdzOW4Zc0bN2tOhAest9.gif">
<!-- <source media="(prefers-color-scheme: light)" width="300" srcset="https://vhs.charm.sh/vhs-1nrhNSuFnQkxWD4RoMlE4O.gif"> -->
<img width="300" src="https://vhs.charm.sh/vhs-3QQdzOW4Zc0bN2tOhAest9.gif">
</picture>
### Levels
Log offers multiple levels to filter your logs on. Available levels are:
```go
log.DebugLevel
log.InfoLevel
log.WarnLevel
log.ErrorLevel
log.FatalLevel
```
Use `log.SetLevel()` to set the log level. You can also create a new logger with
a specific log level using `log.Options{Level: }`.
Use the corresponding function to log a message:
```go
err := errors.New("Baking error 101")
log.Debug(err)
log.Info(err)
log.Warn(err)
log.Error(err)
log.Fatal(err) // this calls os.Exit(1)
log.Print(err) // prints regardless of log level
```
Or use the formatter variant:
```go
format := "%s %d"
log.Debugf(format, "chocolate", 10)
log.Warnf(format, "adding more", 5)
log.Errorf(format, "increasing temp", 420)
log.Fatalf(format, "too hot!", 500) // this calls os.Exit(1)
log.Printf(format, "baking cookies") // prints regardless of log level
// Use these in conjunction with `With(...)` to add more context
log.With("err", err).Errorf("unable to start %s", "oven")
```
### Structured
All the functions above take a message and key-value pairs of anything. The
message can also be of type any.
```go
ingredients := []string{"flour", "butter", "sugar", "chocolate"}
log.Debug("Available ingredients", "ingredients", ingredients)
// DEBUG Available ingredients ingredients="[flour butter sugar chocolate]"
```
### Options
You can customize the logger with options. Use `log.NewWithOptions()` and
`log.Options{}` to customize your new logger.
```go
logger := log.NewWithOptions(os.Stderr, log.Options{
ReportCaller: true,
ReportTimestamp: true,
TimeFormat: time.Kitchen,
Prefix: "Baking 🍪 ",
})
logger.Info("Starting oven!", "degree", 375)
time.Sleep(10 * time.Minute)
logger.Info("Finished baking")
```
<picture>
<source media="(prefers-color-scheme: dark)" width="700" srcset="https://vhs.charm.sh/vhs-6oSCJcQ5EmFKKELcskJhLo.gif">
<source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-6oSCJcQ5EmFKKELcskJhLo.gif">
<!-- <source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-2X8Esd8ZsHo4DVPVgR36yx.gif"> -->
<img width="700" src="https://vhs.charm.sh/vhs-6oSCJcQ5EmFKKELcskJhLo.gif">
</picture>
You can also use logger setters to customize the logger.
```go
logger := log.New(os.Stderr)
logger.SetReportTimestamp(false)
logger.SetReportCaller(false)
logger.SetLevel(log.DebugLevel)
```
Use `log.SetFormatter()` or `log.Options{Formatter: }` to change the output
format. Available options are:
- `log.TextFormatter` (_default_)
- `log.JSONFormatter`
- `log.LogfmtFormatter`
> **Note** styling only affects the `TextFormatter`. Styling is disabled if the
> output is not a TTY.
For a list of available options, refer to [options.go](./options.go).
### Styles
You can customize the logger styles using [Lipgloss][lipgloss]. The styles are
defined at a global level in [styles.go](./styles.go).
```go
// Override the default error level style.
styles := log.DefaultStyles()
styles.Levels[log.ErrorLevel] = lipgloss.NewStyle().
SetString("ERROR!!").
Padding(0, 1, 0, 1).
Background(lipgloss.Color("204")).
Foreground(lipgloss.Color("0"))
// Add a custom style for key `err`
styles.Keys["err"] = lipgloss.NewStyle().Foreground(lipgloss.Color("204"))
styles.Values["err"] = lipgloss.NewStyle().Bold(true)
logger := log.New(os.Stderr)
logger.SetStyles(styles)
logger.Error("Whoops!", "err", "kitchen on fire")
```
<picture>
<source media="(prefers-color-scheme: dark)" width="400" srcset="https://vhs.charm.sh/vhs-4LXsGvzyH4RdjJaTF4a9MG.gif">
<source media="(prefers-color-scheme: light)" width="400" srcset="https://vhs.charm.sh/vhs-4LXsGvzyH4RdjJaTF4a9MG.gif">
<!-- <source media="(prefers-color-scheme: light)" width="400" srcset="https://vhs.charm.sh/vhs-4f6qLnIfudMMLDD9sxXUrv.gif"> -->
<img width="400" src="https://vhs.charm.sh/vhs-4LXsGvzyH4RdjJaTF4a9MG.gif">
</picture>
### Sub-logger
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")
```
<picture>
<source media="(prefers-color-scheme: dark)" width="700" srcset="https://vhs.charm.sh/vhs-1JgP5ZRL0oXVspeg50CczR.gif">
<source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-1JgP5ZRL0oXVspeg50CczR.gif">
<img width="700" src="https://vhs.charm.sh/vhs-1JgP5ZRL0oXVspeg50CczR.gif">
</picture>
### Format Messages
You can use `fmt.Sprintf()` to format messages.
```go
for item := 1; i <= 100; i++ {
log.Info(fmt.Sprintf("Baking %d/100...", item))
}
```
<picture>
<source media="(prefers-color-scheme: dark)" width="500" srcset="https://vhs.charm.sh/vhs-4nX5I7qHT09aJ2gU7OaGV5.gif">
<source media="(prefers-color-scheme: light)" width="500" srcset="https://vhs.charm.sh/vhs-4nX5I7qHT09aJ2gU7OaGV5.gif">
<!-- <source media="(prefers-color-scheme: light)" width="500" srcset="https://vhs.charm.sh/vhs-4RHXd4JSucomcPqJGZTpKh.gif"> -->
<img width="500" src="https://vhs.charm.sh/vhs-4nX5I7qHT09aJ2gU7OaGV5.gif">
</picture>
Or arguments:
```go
for temp := 375; temp <= 400; temp++ {
log.Info("Increasing temperature", "degree", fmt.Sprintf("%d°F", temp))
}
```
<picture>
<source media="(prefers-color-scheme: dark)" width="700" srcset="https://vhs.charm.sh/vhs-79YvXcDOsqgHte3bv42UTr.gif">
<source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-79YvXcDOsqgHte3bv42UTr.gif">
<!-- <source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-4AvAnoA2S53QTOteX8krp4.gif"> -->
<img width="700" src="https://vhs.charm.sh/vhs-79YvXcDOsqgHte3bv42UTr.gif">
</picture>
### Helper Functions
Skip caller frames in helper functions. Similar to what you can do with
`testing.TB().Helper()`.
```go
func startOven(degree int) {
log.Helper()
log.Info("Starting oven", "degree", degree)
}
log.SetReportCaller(true)
startOven(400) // INFO <cookies/oven.go:123> Starting oven degree=400
```
<picture>
<source media="(prefers-color-scheme: dark)" width="700" srcset="https://vhs.charm.sh/vhs-6CeQGIV8Ovgr8GD0N6NgTq.gif">
<source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-6CeQGIV8Ovgr8GD0N6NgTq.gif">
<!-- <source media="(prefers-color-scheme: light)" width="700" srcset="https://vhs.charm.sh/vhs-6DPg0bVL4K4TkfoHkAn2ap.gif"> -->
<img width="700" src="https://vhs.charm.sh/vhs-6CeQGIV8Ovgr8GD0N6NgTq.gif">
</picture>
This will use the _caller_ function (`startOven`) line number instead of the
logging function (`log.Info`) to report the source location.
### Slog Handler
You can use Log as an [`log/slog`](https://pkg.go.dev/log/slog) handler. Just
pass a logger instance to Slog and you're good to go.
```go
handler := log.New(os.Stderr)
logger := slog.New(handler)
logger.Error("meow?")
```
### Standard Log Adapter
Some Go libraries, especially the ones in the standard library, will only accept
the [standard logger][stdlog] interface. For instance, the HTTP Server from
`net/http` will only take a `*log.Logger` for its `ErrorLog` field.
For this, you can use the standard log adapter, which simply wraps the logger in
a `*log.Logger` interface.
```go
logger := log.NewWithOptions(os.Stderr, log.Options{Prefix: "http"})
stdlog := logger.StandardLog(log.StandardLogOptions{
ForceLevel: log.ErrorLevel,
})
s := &http.Server{
Addr: ":8080",
Handler: handler,
ErrorLog: stdlog,
}
stdlog.Printf("Failed to make bake request, %s", fmt.Errorf("temperature is too low"))
// ERROR http: Failed to make bake request, temperature is too low
```
## Gum
<img src="https://vhs.charm.sh/vhs-6jupuFM0s2fXiUrBE0I1vU.gif" width="600" alt="Running gum log with debug and error levels" />
Log integrates with [Gum][gum] to log messages to output. Use `gum log [flags]
[message]` to handle logging in your shell scripts. See
[charmbracelet/gum](https://github.com/charmbracelet/gum#log) for more
information.
[gum]: https://github.com/charmbracelet/gum
[lipgloss]: https://github.com/charmbracelet/lipgloss
[stdlog]: https://pkg.go.dev/log
## License
[MIT](https://github.com/charmbracelet/log/raw/master/LICENSE)
---
Part of [Charm](https://charm.sh).
<a href="https://charm.sh/"><img alt="the Charm logo" src="https://stuff.charm.sh/charm-badge.jpg" width="400"></a>
Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة

23
vendor/github.com/charmbracelet/log/context.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
package log
import "context"
// WithContext wraps the given logger in context.
func WithContext(ctx context.Context, logger *Logger) context.Context {
return context.WithValue(ctx, ContextKey, logger)
}
// FromContext returns the logger from the given context.
// This will return the default package logger if no logger
// found in context.
func FromContext(ctx context.Context) *Logger {
if logger, ok := ctx.Value(ContextKey).(*Logger); ok {
return logger
}
return Default()
}
type contextKey struct{ string }
// ContextKey is the key used to store the logger in context.
var ContextKey = contextKey{"log"}

27
vendor/github.com/charmbracelet/log/formatter.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
package log
// Formatter is a formatter for log messages.
type Formatter uint8
const (
// TextFormatter is a formatter that formats log messages as text. Suitable for
// console output and log files.
TextFormatter Formatter = iota
// JSONFormatter is a formatter that formats log messages as JSON.
JSONFormatter
// LogfmtFormatter is a formatter that formats log messages as logfmt.
LogfmtFormatter
)
var (
// TimestampKey is the key for the timestamp.
TimestampKey = "time"
// MessageKey is the key for the message.
MessageKey = "msg"
// LevelKey is the key for the level.
LevelKey = "level"
// CallerKey is the key for the caller.
CallerKey = "caller"
// PrefixKey is the key for the prefix.
PrefixKey = "prefix"
)

61
vendor/github.com/charmbracelet/log/json.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
package log
import (
"encoding/json"
"fmt"
"time"
)
func (l *Logger) jsonFormatter(keyvals ...interface{}) {
m := make(map[string]interface{}, len(keyvals)/2)
for i := 0; i < len(keyvals); i += 2 {
switch keyvals[i] {
case TimestampKey:
if t, ok := keyvals[i+1].(time.Time); ok {
m[TimestampKey] = t.Format(l.timeFormat)
}
case LevelKey:
if level, ok := keyvals[i+1].(Level); ok {
m[LevelKey] = level.String()
}
case CallerKey:
if caller, ok := keyvals[i+1].(string); ok {
m[CallerKey] = caller
}
case PrefixKey:
if prefix, ok := keyvals[i+1].(string); ok {
m[PrefixKey] = prefix
}
case MessageKey:
if msg := keyvals[i+1]; msg != nil {
m[MessageKey] = fmt.Sprint(msg)
}
default:
var (
key string
val interface{}
)
switch k := keyvals[i].(type) {
case fmt.Stringer:
key = k.String()
case error:
key = k.Error()
default:
key = fmt.Sprint(k)
}
switch v := keyvals[i+1].(type) {
case error:
val = v.Error()
case fmt.Stringer:
val = v.String()
default:
val = v
}
m[key] = val
}
}
e := json.NewEncoder(&l.b)
e.SetEscapeHTML(false)
_ = e.Encode(m)
}

65
vendor/github.com/charmbracelet/log/level.go generated vendored Normal file
View File

@ -0,0 +1,65 @@
package log
import (
"errors"
"fmt"
"math"
"strings"
)
// Level is a logging level.
type Level int32
const (
// DebugLevel is the debug level.
DebugLevel Level = -4
// InfoLevel is the info level.
InfoLevel Level = 0
// WarnLevel is the warn level.
WarnLevel Level = 4
// ErrorLevel is the error level.
ErrorLevel Level = 8
// FatalLevel is the fatal level.
FatalLevel Level = 12
// noLevel is used with log.Print.
noLevel Level = math.MaxInt32
)
// String returns the string representation of the level.
func (l Level) String() string {
switch l {
case DebugLevel:
return "debug"
case InfoLevel:
return "info"
case WarnLevel:
return "warn"
case ErrorLevel:
return "error"
case FatalLevel:
return "fatal"
default:
return ""
}
}
// ErrInvalidLevel is an error returned when parsing an invalid level string.
var ErrInvalidLevel = errors.New("invalid level")
// ParseLevel converts level in string to Level type. Default level is InfoLevel.
func ParseLevel(level string) (Level, error) {
switch strings.ToLower(level) {
case DebugLevel.String():
return DebugLevel, nil
case InfoLevel.String():
return InfoLevel, nil
case WarnLevel.String():
return WarnLevel, nil
case ErrorLevel.String():
return ErrorLevel, nil
case FatalLevel.String():
return FatalLevel, nil
default:
return 0, fmt.Errorf("%w: %q", ErrInvalidLevel, level)
}
}

15
vendor/github.com/charmbracelet/log/level_121.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
//go:build go1.21
// +build go1.21
package log
import "log/slog"
// fromSlogLevel converts slog.Level to log.Level.
var fromSlogLevel = map[slog.Level]Level{
slog.LevelDebug: DebugLevel,
slog.LevelInfo: InfoLevel,
slog.LevelWarn: WarnLevel,
slog.LevelError: ErrorLevel,
slog.Level(12): FatalLevel,
}

15
vendor/github.com/charmbracelet/log/level_no121.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
//go:build !go1.21
// +build !go1.21
package log
import "golang.org/x/exp/slog"
// fromSlogLevel converts slog.Level to log.Level.
var fromSlogLevel = map[slog.Level]Level{
slog.LevelDebug: DebugLevel,
slog.LevelInfo: InfoLevel,
slog.LevelWarn: WarnLevel,
slog.LevelError: ErrorLevel,
slog.Level(12): FatalLevel,
}

32
vendor/github.com/charmbracelet/log/logfmt.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package log
import (
"errors"
"fmt"
"time"
"github.com/go-logfmt/logfmt"
)
func (l *Logger) logfmtFormatter(keyvals ...interface{}) {
e := logfmt.NewEncoder(&l.b)
for i := 0; i < len(keyvals); i += 2 {
switch keyvals[i] {
case TimestampKey:
if t, ok := keyvals[i+1].(time.Time); ok {
keyvals[i+1] = t.Format(l.timeFormat)
}
default:
if key := fmt.Sprint(keyvals[i]); key != "" {
keyvals[i] = key
}
}
err := e.EncodeKeyval(keyvals[i], keyvals[i+1])
if err != nil && errors.Is(err, logfmt.ErrUnsupportedValueType) {
// If the value is not supported by logfmt, we try to convert it to a string.
_ = e.EncodeKeyval(keyvals[i], fmt.Sprintf("%+v", keyvals[i+1]))
}
}
_ = e.EndRecord()
}

409
vendor/github.com/charmbracelet/log/logger.go generated vendored Normal file
View File

@ -0,0 +1,409 @@
package log
import (
"bytes"
"fmt"
"io"
"os"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
)
// ErrMissingValue is returned when a key is missing a value.
var ErrMissingValue = fmt.Errorf("missing value")
// LoggerOption is an option for a logger.
type LoggerOption = func(*Logger)
// Logger is a Logger that implements Logger.
type Logger struct {
w io.Writer
b bytes.Buffer
mu *sync.RWMutex
re *lipgloss.Renderer
isDiscard uint32
level int32
prefix string
timeFunc TimeFunction
timeFormat string
callerOffset int
callerFormatter CallerFormatter
formatter Formatter
reportCaller bool
reportTimestamp bool
fields []interface{}
helpers *sync.Map
styles *Styles
}
// Logf logs a message with formatting.
func (l *Logger) Logf(level Level, format string, args ...interface{}) {
l.Log(level, fmt.Sprintf(format, args...))
}
// Log logs the given message with the given keyvals for the given level.
func (l *Logger) Log(level Level, msg interface{}, keyvals ...interface{}) {
if atomic.LoadUint32(&l.isDiscard) != 0 {
return
}
// check if the level is allowed
if atomic.LoadInt32(&l.level) > int32(level) {
return
}
var frame runtime.Frame
if l.reportCaller {
// Skip log.log, the caller, and any offset added.
frames := l.frames(l.callerOffset + 2)
for {
f, more := frames.Next()
_, helper := l.helpers.Load(f.Function)
if !helper || !more {
// Found a frame that wasn't a helper function.
// Or we ran out of frames to check.
frame = f
break
}
}
}
l.handle(level, l.timeFunc(time.Now()), []runtime.Frame{frame}, msg, keyvals...)
}
func (l *Logger) handle(level Level, ts time.Time, frames []runtime.Frame, msg interface{}, keyvals ...interface{}) {
var kvs []interface{}
if l.reportTimestamp && !ts.IsZero() {
kvs = append(kvs, TimestampKey, ts)
}
_, ok := l.styles.Levels[level]
if ok {
kvs = append(kvs, LevelKey, level)
}
if l.reportCaller && len(frames) > 0 && frames[0].PC != 0 {
file, line, fn := l.location(frames)
if file != "" {
caller := l.callerFormatter(file, line, fn)
kvs = append(kvs, CallerKey, caller)
}
}
if l.prefix != "" {
kvs = append(kvs, PrefixKey, l.prefix)
}
if msg != nil {
if m := fmt.Sprint(msg); m != "" {
kvs = append(kvs, MessageKey, m)
}
}
// append logger fields
kvs = append(kvs, l.fields...)
if len(l.fields)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
// append the rest
kvs = append(kvs, keyvals...)
if len(keyvals)%2 != 0 {
kvs = append(kvs, ErrMissingValue)
}
l.mu.Lock()
defer l.mu.Unlock()
switch l.formatter {
case LogfmtFormatter:
l.logfmtFormatter(kvs...)
case JSONFormatter:
l.jsonFormatter(kvs...)
default:
l.textFormatter(kvs...)
}
// WriteTo will reset the buffer
l.b.WriteTo(l.w) //nolint: errcheck
}
// Helper marks the calling function as a helper
// and skips it for source location information.
// It's the equivalent of testing.TB.Helper().
func (l *Logger) Helper() {
l.helper(1)
}
func (l *Logger) helper(skip int) {
var pcs [1]uintptr
// Skip runtime.Callers, and l.helper
n := runtime.Callers(skip+2, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
frame, _ := frames.Next()
l.helpers.LoadOrStore(frame.Function, struct{}{})
}
// frames returns the runtime.Frames for the caller.
func (l *Logger) frames(skip int) *runtime.Frames {
// Copied from testing.T
const maxStackLen = 50
var pc [maxStackLen]uintptr
// Skip runtime.Callers, and l.frame
n := runtime.Callers(skip+2, pc[:])
frames := runtime.CallersFrames(pc[:n])
return frames
}
func (l *Logger) location(frames []runtime.Frame) (file string, line int, fn string) {
if len(frames) == 0 {
return "", 0, ""
}
f := frames[0]
return f.File, f.Line, f.Function
}
// Cleanup a path by returning the last n segments of the path only.
func trimCallerPath(path string, n int) string {
// lovely borrowed from zap
// nb. To make sure we trim the path correctly on Windows too, we
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
// because the path given originates from Go stdlib, specifically
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
// Windows.
//
// See https://github.com/golang/go/issues/3335
// and https://github.com/golang/go/issues/18151
//
// for discussion on the issue on Go side.
// Return the full path if n is 0.
if n <= 0 {
return path
}
// Find the last separator.
idx := strings.LastIndexByte(path, '/')
if idx == -1 {
return path
}
for i := 0; i < n-1; i++ {
// Find the penultimate separator.
idx = strings.LastIndexByte(path[:idx], '/')
if idx == -1 {
return path
}
}
return path[idx+1:]
}
// SetReportTimestamp sets whether the timestamp should be reported.
func (l *Logger) SetReportTimestamp(report bool) {
l.mu.Lock()
defer l.mu.Unlock()
l.reportTimestamp = report
}
// SetReportCaller sets whether the caller location should be reported.
func (l *Logger) SetReportCaller(report bool) {
l.mu.Lock()
defer l.mu.Unlock()
l.reportCaller = report
}
// GetLevel returns the current level.
func (l *Logger) GetLevel() Level {
l.mu.RLock()
defer l.mu.RUnlock()
return Level(l.level)
}
// SetLevel sets the current level.
func (l *Logger) SetLevel(level Level) {
l.mu.Lock()
defer l.mu.Unlock()
atomic.StoreInt32(&l.level, int32(level))
}
// GetPrefix returns the current prefix.
func (l *Logger) GetPrefix() string {
l.mu.RLock()
defer l.mu.RUnlock()
return l.prefix
}
// SetPrefix sets the current prefix.
func (l *Logger) SetPrefix(prefix string) {
l.mu.Lock()
defer l.mu.Unlock()
l.prefix = prefix
}
// SetTimeFormat sets the time format.
func (l *Logger) SetTimeFormat(format string) {
l.mu.Lock()
defer l.mu.Unlock()
l.timeFormat = format
}
// SetTimeFunction sets the time function.
func (l *Logger) SetTimeFunction(f TimeFunction) {
l.mu.Lock()
defer l.mu.Unlock()
l.timeFunc = f
}
// SetOutput sets the output destination.
func (l *Logger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
if w == nil {
w = os.Stderr
}
l.w = w
var isDiscard uint32
if w == io.Discard {
isDiscard = 1
}
atomic.StoreUint32(&l.isDiscard, isDiscard)
// 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.
func (l *Logger) SetFormatter(f Formatter) {
l.mu.Lock()
defer l.mu.Unlock()
l.formatter = f
}
// SetCallerFormatter sets the caller formatter.
func (l *Logger) SetCallerFormatter(f CallerFormatter) {
l.mu.Lock()
defer l.mu.Unlock()
l.callerFormatter = f
}
// SetCallerOffset sets the caller offset.
func (l *Logger) SetCallerOffset(offset int) {
l.mu.Lock()
defer l.mu.Unlock()
l.callerOffset = offset
}
// SetColorProfile force sets the underlying Lip Gloss renderer color profile
// for the TextFormatter.
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
}
// WithPrefix returns a new logger with the given prefix.
func (l *Logger) WithPrefix(prefix string) *Logger {
sl := l.With()
sl.SetPrefix(prefix)
return sl
}
// Debug prints a debug message.
func (l *Logger) Debug(msg interface{}, keyvals ...interface{}) {
l.Log(DebugLevel, msg, keyvals...)
}
// Info prints an info message.
func (l *Logger) Info(msg interface{}, keyvals ...interface{}) {
l.Log(InfoLevel, msg, keyvals...)
}
// Warn prints a warning message.
func (l *Logger) Warn(msg interface{}, keyvals ...interface{}) {
l.Log(WarnLevel, msg, keyvals...)
}
// Error prints an error message.
func (l *Logger) Error(msg interface{}, keyvals ...interface{}) {
l.Log(ErrorLevel, msg, keyvals...)
}
// Fatal prints a fatal message and exits.
func (l *Logger) Fatal(msg interface{}, keyvals ...interface{}) {
l.Log(FatalLevel, msg, keyvals...)
os.Exit(1)
}
// Print prints a message with no level.
func (l *Logger) Print(msg interface{}, keyvals ...interface{}) {
l.Log(noLevel, msg, keyvals...)
}
// Debugf prints a debug message with formatting.
func (l *Logger) Debugf(format string, args ...interface{}) {
l.Log(DebugLevel, fmt.Sprintf(format, args...))
}
// Infof prints an info message with formatting.
func (l *Logger) Infof(format string, args ...interface{}) {
l.Log(InfoLevel, fmt.Sprintf(format, args...))
}
// Warnf prints a warning message with formatting.
func (l *Logger) Warnf(format string, args ...interface{}) {
l.Log(WarnLevel, fmt.Sprintf(format, args...))
}
// Errorf prints an error message with formatting.
func (l *Logger) Errorf(format string, args ...interface{}) {
l.Log(ErrorLevel, fmt.Sprintf(format, args...))
}
// Fatalf prints a fatal message with formatting and exits.
func (l *Logger) Fatalf(format string, args ...interface{}) {
l.Log(FatalLevel, fmt.Sprintf(format, args...))
os.Exit(1)
}
// Printf prints a message with no level and formatting.
func (l *Logger) Printf(format string, args ...interface{}) {
l.Log(noLevel, fmt.Sprintf(format, args...))
}

62
vendor/github.com/charmbracelet/log/logger_121.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
//go:build go1.21
// +build go1.21
package log
import (
"context"
"log/slog"
"runtime"
"sync/atomic"
)
// Enabled reports whether the logger is enabled for the given level.
//
// Implements slog.Handler.
func (l *Logger) Enabled(_ context.Context, level slog.Level) bool {
return atomic.LoadInt32(&l.level) <= int32(fromSlogLevel[level])
}
// Handle handles the Record. It will only be called if Enabled returns true.
//
// Implements slog.Handler.
func (l *Logger) Handle(ctx context.Context, record slog.Record) error {
if !l.Enabled(ctx, record.Level) {
return nil
}
fields := make([]interface{}, 0, record.NumAttrs()*2)
record.Attrs(func(a slog.Attr) bool {
fields = append(fields, a.Key, a.Value.String())
return true
})
// Get the caller frame using the record's PC.
frames := runtime.CallersFrames([]uintptr{record.PC})
frame, _ := frames.Next()
l.handle(fromSlogLevel[record.Level], l.timeFunc(record.Time), []runtime.Frame{frame}, record.Message, fields...)
return nil
}
// WithAttrs returns a new Handler with the given attributes added.
//
// Implements slog.Handler.
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
fields := make([]interface{}, 0, len(attrs)*2)
for _, attr := range attrs {
fields = append(fields, attr.Key, attr.Value)
}
return l.With(fields...)
}
// WithGroup returns a new Handler with the given group name prepended to the
// current group name or prefix.
//
// Implements slog.Handler.
func (l *Logger) WithGroup(name string) slog.Handler {
if l.prefix != "" {
name = l.prefix + "." + name
}
return l.WithPrefix(name)
}
var _ slog.Handler = (*Logger)(nil)

59
vendor/github.com/charmbracelet/log/logger_no121.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
//go:build !go1.21
// +build !go1.21
package log
import (
"context"
"runtime"
"sync/atomic"
"golang.org/x/exp/slog"
)
// Enabled reports whether the logger is enabled for the given level.
//
// Implements slog.Handler.
func (l *Logger) Enabled(_ context.Context, level slog.Level) bool {
return atomic.LoadInt32(&l.level) <= int32(fromSlogLevel[level])
}
// Handle handles the Record. It will only be called if Enabled returns true.
//
// Implements slog.Handler.
func (l *Logger) Handle(_ context.Context, record slog.Record) error {
fields := make([]interface{}, 0, record.NumAttrs()*2)
record.Attrs(func(a slog.Attr) bool {
fields = append(fields, a.Key, a.Value.String())
return true
})
// Get the caller frame using the record's PC.
frames := runtime.CallersFrames([]uintptr{record.PC})
frame, _ := frames.Next()
l.handle(fromSlogLevel[record.Level], l.timeFunc(record.Time), []runtime.Frame{frame}, record.Message, fields...)
return nil
}
// WithAttrs returns a new Handler with the given attributes added.
//
// Implements slog.Handler.
func (l *Logger) WithAttrs(attrs []slog.Attr) slog.Handler {
fields := make([]interface{}, 0, len(attrs)*2)
for _, attr := range attrs {
fields = append(fields, attr.Key, attr.Value)
}
return l.With(fields...)
}
// WithGroup returns a new Handler with the given group name prepended to the
// current group name or prefix.
//
// Implements slog.Handler.
func (l *Logger) WithGroup(name string) slog.Handler {
if l.prefix != "" {
name = l.prefix + "." + name
}
return l.WithPrefix(name)
}
var _ slog.Handler = (*Logger)(nil)

61
vendor/github.com/charmbracelet/log/options.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
package log
import (
"fmt"
"time"
)
// DefaultTimeFormat is the default time format.
const DefaultTimeFormat = "2006/01/02 15:04:05"
// TimeFunction is a function that returns a time.Time.
type TimeFunction = func(time.Time) time.Time
// NowUTC is a convenient function that returns the
// current time in UTC timezone.
//
// This is to be used as a time function.
// For example:
//
// log.SetTimeFunction(log.NowUTC)
func NowUTC(t time.Time) time.Time {
return t.UTC()
}
// CallerFormatter is the caller formatter.
type CallerFormatter func(string, int, string) string
// ShortCallerFormatter is a caller formatter that returns the last 2 levels of the path
// and line number.
func ShortCallerFormatter(file string, line int, _ string) string {
return fmt.Sprintf("%s:%d", trimCallerPath(file, 2), line)
}
// LongCallerFormatter is a caller formatter that returns the full path and line number.
func LongCallerFormatter(file string, line int, _ string) string {
return fmt.Sprintf("%s:%d", file, line)
}
// Options is the options for the logger.
type Options struct {
// TimeFunction is the time function for the logger. The default is time.Now.
TimeFunction TimeFunction
// TimeFormat is the time format for the logger. The default is "2006/01/02 15:04:05".
TimeFormat string
// Level is the level for the logger. The default is InfoLevel.
Level Level
// Prefix is the prefix for the logger. The default is no prefix.
Prefix string
// ReportTimestamp is whether the logger should report the timestamp. The default is false.
ReportTimestamp bool
// ReportCaller is whether the logger should report the caller location. The default is false.
ReportCaller bool
// CallerFormatter is the caller format for the logger. The default is ShortCallerFormatter.
CallerFormatter CallerFormatter
// CallerOffset is the caller format for the logger. The default is 0.
CallerOffset int
// Fields is the fields for the logger. The default is no fields.
Fields []interface{}
// Formatter is the formatter for the logger. The default is TextFormatter.
Formatter Formatter
}

246
vendor/github.com/charmbracelet/log/pkg.go generated vendored Normal file
View File

@ -0,0 +1,246 @@
package log
import (
"bytes"
"fmt"
"io"
"log"
"os"
"sync"
"time"
"github.com/muesli/termenv"
)
var (
// registry is a map of all registered lipgloss renderers.
registry = sync.Map{}
// defaultLogger is the default global logger instance.
defaultLoggerOnce sync.Once
defaultLogger *Logger
)
// Default returns the default logger. The default logger comes with timestamp enabled.
func Default() *Logger {
defaultLoggerOnce.Do(func() {
if defaultLogger != nil {
// already set via SetDefault.
return
}
defaultLogger = NewWithOptions(os.Stderr, Options{ReportTimestamp: true})
})
return defaultLogger
}
// SetDefault sets the default global logger.
func SetDefault(logger *Logger) {
defaultLogger = logger
}
// New returns a new logger with the default options.
func New(w io.Writer) *Logger {
return NewWithOptions(w, Options{})
}
// NewWithOptions returns a new logger using the provided options.
func NewWithOptions(w io.Writer, o Options) *Logger {
l := &Logger{
b: bytes.Buffer{},
mu: &sync.RWMutex{},
helpers: &sync.Map{},
level: int32(o.Level),
reportTimestamp: o.ReportTimestamp,
reportCaller: o.ReportCaller,
prefix: o.Prefix,
timeFunc: o.TimeFunction,
timeFormat: o.TimeFormat,
formatter: o.Formatter,
fields: o.Fields,
callerFormatter: o.CallerFormatter,
callerOffset: o.CallerOffset,
}
l.SetOutput(w)
l.SetLevel(Level(l.level))
l.SetStyles(DefaultStyles())
if l.callerFormatter == nil {
l.callerFormatter = ShortCallerFormatter
}
if l.timeFunc == nil {
l.timeFunc = func(t time.Time) time.Time { return t }
}
if l.timeFormat == "" {
l.timeFormat = DefaultTimeFormat
}
return l
}
// SetReportTimestamp sets whether to report timestamp for the default logger.
func SetReportTimestamp(report bool) {
Default().SetReportTimestamp(report)
}
// SetReportCaller sets whether to report caller location for the default logger.
func SetReportCaller(report bool) {
Default().SetReportCaller(report)
}
// SetLevel sets the level for the default logger.
func SetLevel(level Level) {
Default().SetLevel(level)
}
// GetLevel returns the level for the default logger.
func GetLevel() Level {
return Default().GetLevel()
}
// SetTimeFormat sets the time format for the default logger.
func SetTimeFormat(format string) {
Default().SetTimeFormat(format)
}
// SetTimeFunction sets the time function for the default logger.
func SetTimeFunction(f TimeFunction) {
Default().SetTimeFunction(f)
}
// SetOutput sets the output for the default logger.
func SetOutput(w io.Writer) {
Default().SetOutput(w)
}
// SetFormatter sets the formatter for the default logger.
func SetFormatter(f Formatter) {
Default().SetFormatter(f)
}
// SetCallerFormatter sets the caller formatter for the default logger.
func SetCallerFormatter(f CallerFormatter) {
Default().SetCallerFormatter(f)
}
// SetCallerOffset sets the caller offset for the default logger.
func SetCallerOffset(offset int) {
Default().SetCallerOffset(offset)
}
// SetPrefix sets the prefix for the default logger.
func SetPrefix(prefix string) {
Default().SetPrefix(prefix)
}
// SetColorProfile force sets the underlying Lip Gloss renderer color profile
// for the TextFormatter.
func SetColorProfile(profile termenv.Profile) {
Default().SetColorProfile(profile)
}
// SetStyles sets the logger styles for the TextFormatter.
func SetStyles(s *Styles) {
Default().SetStyles(s)
}
// GetPrefix returns the prefix for the default logger.
func GetPrefix() string {
return Default().GetPrefix()
}
// With returns a new logger with the given keyvals.
func With(keyvals ...interface{}) *Logger {
return Default().With(keyvals...)
}
// WithPrefix returns a new logger with the given prefix.
func WithPrefix(prefix string) *Logger {
return Default().WithPrefix(prefix)
}
// Helper marks the calling function as a helper
// and skips it for source location information.
// It's the equivalent of testing.TB.Helper().
func Helper() {
Default().helper(1)
}
// Log logs a message with the given level.
func Log(level Level, msg interface{}, keyvals ...interface{}) {
Default().Log(level, msg, keyvals...)
}
// Debug logs a debug message.
func Debug(msg interface{}, keyvals ...interface{}) {
Default().Log(DebugLevel, msg, keyvals...)
}
// Info logs an info message.
func Info(msg interface{}, keyvals ...interface{}) {
Default().Log(InfoLevel, msg, keyvals...)
}
// Warn logs a warning message.
func Warn(msg interface{}, keyvals ...interface{}) {
Default().Log(WarnLevel, msg, keyvals...)
}
// Error logs an error message.
func Error(msg interface{}, keyvals ...interface{}) {
Default().Log(ErrorLevel, msg, keyvals...)
}
// Fatal logs a fatal message and exit.
func Fatal(msg interface{}, keyvals ...interface{}) {
Default().Log(FatalLevel, msg, keyvals...)
os.Exit(1)
}
// Print logs a message with no level.
func Print(msg interface{}, keyvals ...interface{}) {
Default().Log(noLevel, msg, keyvals...)
}
// Logf logs a message with formatting and level.
func Logf(level Level, format string, args ...interface{}) {
Default().Logf(level, format, args...)
}
// Debugf logs a debug message with formatting.
func Debugf(format string, args ...interface{}) {
Default().Log(DebugLevel, fmt.Sprintf(format, args...))
}
// Infof logs an info message with formatting.
func Infof(format string, args ...interface{}) {
Default().Log(InfoLevel, fmt.Sprintf(format, args...))
}
// Warnf logs a warning message with formatting.
func Warnf(format string, args ...interface{}) {
Default().Log(WarnLevel, fmt.Sprintf(format, args...))
}
// Errorf logs an error message with formatting.
func Errorf(format string, args ...interface{}) {
Default().Log(ErrorLevel, fmt.Sprintf(format, args...))
}
// Fatalf logs a fatal message with formatting and exit.
func Fatalf(format string, args ...interface{}) {
Default().Log(FatalLevel, fmt.Sprintf(format, args...))
os.Exit(1)
}
// Printf logs a message with formatting and no level.
func Printf(format string, args ...interface{}) {
Default().Log(noLevel, fmt.Sprintf(format, args...))
}
// StandardLog returns a standard logger from the default logger.
func StandardLog(opts ...StandardLogOptions) *log.Logger {
return Default().StandardLog(opts...)
}

67
vendor/github.com/charmbracelet/log/stdlog.go generated vendored Normal file
View File

@ -0,0 +1,67 @@
package log
import (
"log"
"strings"
)
type stdLogWriter struct {
l *Logger
opt *StandardLogOptions
}
func (l *stdLogWriter) Write(p []byte) (n int, err error) {
str := strings.TrimSuffix(string(p), "\n")
if l.opt != nil {
switch l.opt.ForceLevel {
case DebugLevel:
l.l.Debug(str)
case InfoLevel:
l.l.Info(str)
case WarnLevel:
l.l.Warn(str)
case ErrorLevel:
l.l.Error(str)
}
} else {
switch {
case strings.HasPrefix(str, "DEBUG"):
l.l.Debug(strings.TrimSpace(str[5:]))
case strings.HasPrefix(str, "INFO"):
l.l.Info(strings.TrimSpace(str[4:]))
case strings.HasPrefix(str, "WARN"):
l.l.Warn(strings.TrimSpace(str[4:]))
case strings.HasPrefix(str, "ERROR"):
l.l.Error(strings.TrimSpace(str[5:]))
case strings.HasPrefix(str, "ERR"):
l.l.Error(strings.TrimSpace(str[3:]))
default:
l.l.Info(str)
}
}
return len(p), nil
}
// StandardLogOptions can be used to configure the standard log adapter.
type StandardLogOptions struct {
ForceLevel Level
}
// StandardLog returns a standard logger from Logger. The returned logger
// can infer log levels from message prefix. Expected prefixes are DEBUG, INFO,
// WARN, ERROR, and ERR.
func (l *Logger) StandardLog(opts ...StandardLogOptions) *log.Logger {
nl := l.With()
// The caller stack is
// log.Printf() -> l.Output() -> l.out.Write(stdLogger.Write)
nl.callerOffset += 3
sl := &stdLogWriter{
l: nl,
}
if len(opts) > 0 {
sl.opt = &opts[0]
}
return log.New(sl, "", 0)
}

82
vendor/github.com/charmbracelet/log/styles.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package log
import (
"strings"
"github.com/charmbracelet/lipgloss"
)
// Styles defines the styles for the text logger.
type Styles struct {
// Timestamp is the style for timestamps.
Timestamp lipgloss.Style
// Caller is the style for source caller.
Caller lipgloss.Style
// Prefix is the style for prefix.
Prefix lipgloss.Style
// Message is the style for messages.
Message lipgloss.Style
// Key is the style for keys.
Key lipgloss.Style
// Value is the style for values.
Value lipgloss.Style
// Separator is the style for separators.
Separator lipgloss.Style
// Levels are the styles for each level.
Levels map[Level]lipgloss.Style
// Keys overrides styles for specific keys.
Keys map[string]lipgloss.Style
// Values overrides value styles for specific keys.
Values map[string]lipgloss.Style
}
// 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.Color("63")),
InfoLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(InfoLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.Color("86")),
WarnLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(WarnLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.Color("192")),
ErrorLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(ErrorLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.Color("204")),
FatalLevel: lipgloss.NewStyle().
SetString(strings.ToUpper(FatalLevel.String())).
Bold(true).
MaxWidth(4).
Foreground(lipgloss.Color("134")),
},
Keys: map[string]lipgloss.Style{},
Values: map[string]lipgloss.Style{},
}
}

272
vendor/github.com/charmbracelet/log/text.go generated vendored Normal file
View File

@ -0,0 +1,272 @@
package log
import (
"fmt"
"io"
"strings"
"sync"
"time"
"unicode"
"unicode/utf8"
)
const (
separator = "="
indentSeparator = " │ "
)
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 := st.Values[key]; ok {
val = valueStyle.Renderer(l.re).Render(val)
} else {
val = st.Value.Renderer(l.re).Render(val)
}
_, _ = w.Write([]byte(val))
if newline {
_, _ = w.Write([]byte{'\n'})
}
}
return
}
_, _ = w.Write([]byte(indent))
val := escapeStringForOutput(str[:nl], false)
val = st.Value.Renderer(l.re).Render(val)
_, _ = w.Write([]byte(val))
_, _ = w.Write([]byte{'\n'})
str = str[nl+1:]
}
}
func needsEscaping(str string) bool {
for _, b := range str {
if !unicode.IsPrint(b) || b == '"' {
return true
}
}
return false
}
const (
lowerhex = "0123456789abcdef"
)
var bufPool = sync.Pool{
New: func() interface{} {
return new(strings.Builder)
},
}
func escapeStringForOutput(str string, escapeQuotes bool) string {
// kindly borrowed from hclog
if !needsEscaping(str) {
return str
}
bb := bufPool.Get().(*strings.Builder)
bb.Reset()
defer bufPool.Put(bb)
for _, r := range str {
if escapeQuotes && r == '"' {
bb.WriteString(`\"`)
} else if unicode.IsPrint(r) {
bb.WriteRune(r)
} else {
switch r {
case '\a':
bb.WriteString(`\a`)
case '\b':
bb.WriteString(`\b`)
case '\f':
bb.WriteString(`\f`)
case '\n':
bb.WriteString(`\n`)
case '\r':
bb.WriteString(`\r`)
case '\t':
bb.WriteString(`\t`)
case '\v':
bb.WriteString(`\v`)
default:
switch {
case r < ' ':
bb.WriteString(`\x`)
bb.WriteByte(lowerhex[byte(r)>>4])
bb.WriteByte(lowerhex[byte(r)&0xF])
case !utf8.ValidRune(r):
r = 0xFFFD
fallthrough
case r < 0x10000:
bb.WriteString(`\u`)
for s := 12; s >= 0; s -= 4 {
bb.WriteByte(lowerhex[r>>uint(s)&0xF])
}
default:
bb.WriteString(`\U`)
for s := 28; s >= 0; s -= 4 {
bb.WriteByte(lowerhex[r>>uint(s)&0xF])
}
}
}
}
}
return bb.String()
}
func needsQuoting(s string) bool {
for i := 0; i < len(s); {
b := s[i]
if b < utf8.RuneSelf {
if needsQuotingSet[b] {
return true
}
i++
continue
}
r, size := utf8.DecodeRuneInString(s[i:])
if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
return true
}
i += size
}
return false
}
var needsQuotingSet = [utf8.RuneSelf]bool{
'"': true,
'=': true,
}
func init() {
for i := 0; i < utf8.RuneSelf; i++ {
r := rune(i)
if unicode.IsSpace(r) || !unicode.IsPrint(r) {
needsQuotingSet[i] = true
}
}
}
func writeSpace(w io.Writer, first bool) {
if !first {
w.Write([]byte{' '}) //nolint: errcheck
}
}
func (l *Logger) textFormatter(keyvals ...interface{}) {
st := l.styles
lenKeyvals := len(keyvals)
for i := 0; i < lenKeyvals; i += 2 {
firstKey := i == 0
moreKeys := i < lenKeyvals-2
switch keyvals[i] {
case TimestampKey:
if t, ok := keyvals[i+1].(time.Time); ok {
ts := t.Format(l.timeFormat)
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 {
var lvl string
lvlStyle, ok := st.Levels[level]
if !ok {
continue
}
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 = 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 = 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 = st.Message.Renderer(l.re).Render(m)
writeSpace(&l.b, firstKey)
l.b.WriteString(m)
}
default:
sep := separator
indentSep := indentSeparator
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 == ""
if raw {
val = `""`
}
if key == "" {
continue
}
actualKey := key
valueStyle := st.Value
if vs, ok := st.Values[actualKey]; ok {
valueStyle = vs
}
if keyStyle, ok := st.Keys[key]; ok {
key = keyStyle.Renderer(l.re).Render(key)
} else {
key = st.Key.Renderer(l.re).Render(key)
}
// Values may contain multiple lines, and that format
// is preserved, with each line prefixed with a " | "
// to show it's part of a collection of lines.
//
// Values may also need quoting, if not all the runes
// in the value string are "normal", like if they
// contain ANSI escape sequences.
if strings.Contains(val, "\n") {
l.b.WriteString("\n ")
l.b.WriteString(key)
l.b.WriteString(sep + "\n")
l.writeIndent(&l.b, val, indentSep, moreKeys, actualKey)
} else if !raw && needsQuoting(val) {
writeSpace(&l.b, firstKey)
l.b.WriteString(key)
l.b.WriteString(sep)
l.b.WriteString(valueStyle.Renderer(l.re).Render(fmt.Sprintf(`"%s"`,
escapeStringForOutput(val, true))))
} else {
val = valueStyle.Renderer(l.re).Render(val)
writeSpace(&l.b, firstKey)
l.b.WriteString(key)
l.b.WriteString(sep)
l.b.WriteString(val)
}
}
}
// Add a newline to the end of the log message.
l.b.WriteByte('\n')
}