mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Bump github.com/sirupsen/logrus from 1.9.4 to 1.10.1
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.9.4 to 1.10.1. - [Release notes](https://github.com/sirupsen/logrus/releases) - [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md) - [Commits](https://github.com/sirupsen/logrus/compare/v1.9.4...v1.10.1) --- updated-dependencies: - dependency-name: github.com/sirupsen/logrus dependency-version: 1.10.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
parent
ea91639546
commit
db677b12a8
6
go.mod
6
go.mod
|
|
@ -34,11 +34,11 @@ require (
|
|||
github.com/samber/lo v1.53.0
|
||||
github.com/sanity-io/litter v1.5.8
|
||||
github.com/sasha-s/go-deadlock v0.3.9
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
github.com/sirupsen/logrus v1.10.1
|
||||
github.com/spf13/afero v1.15.0
|
||||
github.com/spkg/bom v1.0.1
|
||||
github.com/stefanhaller/git-todo-parser v0.0.7-0.20250905083220-c50528f08304
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.12.0
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||
golang.org/x/sync v0.22.0
|
||||
|
|
@ -53,7 +53,6 @@ require (
|
|||
github.com/cli/safeexec v1.0.1 // indirect
|
||||
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
|
|
@ -65,7 +64,6 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
github.com/onsi/gomega v1.34.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
golang.org/x/mod v0.38.0 // indirect
|
||||
golang.org/x/term v0.45.0 // indirect
|
||||
|
|
|
|||
11
go.sum
11
go.sum
|
|
@ -25,8 +25,6 @@ github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
|||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
|
|
@ -100,7 +98,6 @@ github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeD
|
|||
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe h1:vHpqOnPlnkba8iSxU4j/CvDSS9J4+F4473esQsYLGoE=
|
||||
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
|
|
@ -114,8 +111,8 @@ github.com/sanity-io/litter v1.5.8 h1:uM/2lKrWdGbRXDrIq08Lh9XtVYoeGtcQxk9rtQ7+rY
|
|||
github.com/sanity-io/litter v1.5.8/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
|
||||
github.com/sasha-s/go-deadlock v0.3.9 h1:fiaT9rB7g5sr5ddNZvlwheclN9IP86eFW9WgqlEQV+w=
|
||||
github.com/sasha-s/go-deadlock v0.3.9/go.mod h1:KuZj51ZFmx42q/mPaYbRk0P1xcwe697zsJKE03vD4/Y=
|
||||
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
github.com/sirupsen/logrus v1.10.1 h1:xi4336Zh11WpU14fXR6I67V3yaTPQYwRx2WEtHbRg4Q=
|
||||
github.com/sirupsen/logrus v1.10.1/go.mod h1:vsQHnG7xzNsxk3NrwboUiWPnIC3dmbjcGPykD7+tiHk=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spkg/bom v1.0.1 h1:tl8kQ2sufL/wDEJa9me1jnQYEpDB7LqYGNkwCVR5GLs=
|
||||
|
|
@ -125,8 +122,8 @@ github.com/stefanhaller/git-todo-parser v0.0.7-0.20250905083220-c50528f08304/go.
|
|||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI=
|
||||
github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw=
|
||||
github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
|
|
|
|||
48
vendor/github.com/sirupsen/logrus/.golangci.yml
generated
vendored
48
vendor/github.com/sirupsen/logrus/.golangci.yml
generated
vendored
|
|
@ -1,12 +1,9 @@
|
|||
version: "2"
|
||||
run:
|
||||
tests: false
|
||||
linters:
|
||||
enable:
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- contextcheck
|
||||
- durationcheck
|
||||
- errchkjson
|
||||
|
|
@ -22,46 +19,21 @@ linters:
|
|||
- nilerr
|
||||
- nilnesserr
|
||||
- noctx
|
||||
- protogetter
|
||||
- reassign
|
||||
- recvcheck
|
||||
- rowserrcheck
|
||||
- spancheck
|
||||
- sqlclosecheck
|
||||
- testifylint
|
||||
- unparam
|
||||
- zerologlint
|
||||
disable:
|
||||
- prealloc
|
||||
settings:
|
||||
errcheck:
|
||||
check-type-assertions: false
|
||||
check-blank: false
|
||||
lll:
|
||||
line-length: 100
|
||||
tab-width: 4
|
||||
prealloc:
|
||||
simple: false
|
||||
range-loops: false
|
||||
for-loops: false
|
||||
whitespace:
|
||||
multi-if: false
|
||||
multi-func: false
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
rules:
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gosec
|
||||
- musttag
|
||||
- noctx # TODO: enable once we switch to Go 1.24+.
|
||||
- linters: # TODO: remove once golangci-lint is updated with https://github.com/golangci/golangci-lint/pull/6584
|
||||
- gocheckcompilerdirectives
|
||||
text: 'compiler directive unrecognized: //go:fix'
|
||||
|
|
|
|||
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
language: go
|
||||
go_import_path: github.com/sirupsen/logrus
|
||||
git:
|
||||
depth: 1
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
go: 1.15.x
|
||||
os: linux
|
||||
install:
|
||||
- ./travis/install.sh
|
||||
script:
|
||||
- cd ci
|
||||
- go run mage.go -v -w ../ crossBuild
|
||||
- go run mage.go -v -w ../ lint
|
||||
- go run mage.go -v -w ../ test
|
||||
239
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
239
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
|
|
@ -1,90 +1,246 @@
|
|||
# 1.8.1
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## 1.10.1
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix a regression introduced in v1.10.0 where `TextFormatter` could panic
|
||||
when formatting nil or panicking `error` and `fmt.Stringer` values.
|
||||
* Allow function-backed implementations of `error` as field values.
|
||||
|
||||
## 1.10.0
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix reentrant logging deadlocks in formatter paths.
|
||||
* Fix race conditions in formatter and entry handling.
|
||||
* Fix generic `Log`, `Logf`, `Logln`, and `LogFn` methods unexpectedly
|
||||
panicking when called with `PanicLevel`. Use the corresponding `Panic`
|
||||
methods when panic behavior is desired.
|
||||
* Improve concurrency safety around formatter and hook access.
|
||||
|
||||
Features:
|
||||
|
||||
* Add `slog` hook for forwarding Logrus entries to `log/slog`.
|
||||
* Add `slog.Handler` for forwarding `log/slog` records to a Logrus logger,
|
||||
including levels, fields, groups, context, time, and optional caller
|
||||
reporting. The hook and handler can also be combined to help migrate
|
||||
between Logrus and `log/slog`.
|
||||
* Add minimal, composable logging interfaces for each log level. This enables
|
||||
consumers to depend on narrower interfaces, making it easier to substitute
|
||||
or adapt logging implementations.
|
||||
* Allow `Entry.Caller` to be set explicitly and preserve it across derived
|
||||
entries, enabling custom caller detection without Logrus overwriting
|
||||
caller information when `ReportCaller` is enabled.
|
||||
|
||||
Changed:
|
||||
|
||||
* Raise minimum supported Go version to 1.23.
|
||||
* TextFormatter now renders `[]byte` values as raw/quoted strings instead of slice-of-ints.
|
||||
* TextFormatter now uses distinct dimmed colors for debug and trace output.
|
||||
* TextFormatter now automatically enables colors on Windows terminals with ANSI support,
|
||||
matching the behavior on other platforms.
|
||||
* `Entry.HasCaller` is now deprecated in favor of checking `Entry.Caller` directly.
|
||||
* Deprecated `MutexWrap`, which was unintentionally exposed as public API.
|
||||
It remains available as an alias for compatibility but should not be used
|
||||
directly.
|
||||
|
||||
Performance:
|
||||
|
||||
* Significantly improve TextFormatter performance and reduce allocations.
|
||||
* Optimize common Entry and Logger hot paths.
|
||||
* Reduce allocations in caller reporting.
|
||||
* ~17% lower geomean runtime and ~27% higher formatter throughput overall.
|
||||
* Common enabled logging paths are ~30–44% faster.
|
||||
* TextFormatter paths are up to ~40% faster, with allocation counts reduced
|
||||
by 25–74% across the measured formatter cases.
|
||||
|
||||
|
||||
## 1.9.4
|
||||
|
||||
Fixes:
|
||||
|
||||
* Remove uses of deprecated `ioutil` package
|
||||
|
||||
Features:
|
||||
|
||||
* Add GNU/Hurd support
|
||||
* Add WASI wasip1 support
|
||||
|
||||
Code quality:
|
||||
|
||||
* Update minimum supported Go version to 1.17
|
||||
* Documentation updates
|
||||
|
||||
|
||||
## 1.9.3
|
||||
|
||||
Fixes:
|
||||
|
||||
* Re-apply fix for potential denial of service in logrus.Writer() when logging >64KB single-line payloads without newlines (#1376)
|
||||
* Fix panic in Writer
|
||||
|
||||
|
||||
## 1.9.2
|
||||
|
||||
Fixes:
|
||||
|
||||
* Revert Writer DoS fix (#1376) due to regression
|
||||
|
||||
|
||||
## 1.9.1
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix potential denial of service in logrus.Writer() when logging >64KB single-line payloads without newlines (#1376)
|
||||
|
||||
|
||||
## 1.9.0
|
||||
|
||||
Fixes:
|
||||
|
||||
* Multiple concurrency and race condition fixes
|
||||
* Improve Windows terminal and ANSI handling
|
||||
|
||||
Code quality:
|
||||
|
||||
* Internal cleanups and modernization
|
||||
|
||||
|
||||
## 1.8.3
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix potential denial of service in logrus.Writer() when logging >64KB single-line payloads without newlines (#1376)
|
||||
|
||||
|
||||
## 1.8.2
|
||||
|
||||
Features:
|
||||
|
||||
* Add support for the logger private buffer pool (#1253)
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix race condition for SetFormatter and SetReportCaller
|
||||
* Fix data race in hooks test package
|
||||
|
||||
## 1.8.1
|
||||
|
||||
Code quality:
|
||||
|
||||
* move magefile in its own subdir/submodule to remove magefile dependency on logrus consumer
|
||||
* improve timestamp format documentation
|
||||
|
||||
Fixes:
|
||||
|
||||
* fix race condition on logger hooks
|
||||
|
||||
|
||||
# 1.8.0
|
||||
## 1.8.0
|
||||
|
||||
Correct versioning number replacing v1.7.1.
|
||||
|
||||
# 1.7.1
|
||||
## 1.7.1
|
||||
|
||||
Beware this release has introduced a new public API and its semver is therefore incorrect.
|
||||
|
||||
Code quality:
|
||||
|
||||
* use go 1.15 in travis
|
||||
* use magefile as task runner
|
||||
|
||||
Fixes:
|
||||
|
||||
* small fixes about new go 1.13 error formatting system
|
||||
* Fix for long time race condiction with mutating data hooks
|
||||
|
||||
Features:
|
||||
|
||||
* build support for zos
|
||||
|
||||
# 1.7.0
|
||||
## 1.7.0
|
||||
|
||||
Fixes:
|
||||
|
||||
* the dependency toward a windows terminal library has been removed
|
||||
|
||||
Features:
|
||||
|
||||
* a new buffer pool management API has been added
|
||||
* a set of `<LogLevel>Fn()` functions have been added
|
||||
|
||||
# 1.6.0
|
||||
## 1.6.0
|
||||
|
||||
Fixes:
|
||||
|
||||
* end of line cleanup
|
||||
* revert the entry concurrency bug fix which leads to deadlock under some circumstances
|
||||
* update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
|
||||
|
||||
Features:
|
||||
|
||||
* add an option to the `TextFormatter` to completely disable fields quoting
|
||||
|
||||
# 1.5.0
|
||||
## 1.5.0
|
||||
|
||||
Code quality:
|
||||
|
||||
* add golangci linter run on travis
|
||||
|
||||
Fixes:
|
||||
|
||||
* add mutex for hooks concurrent access on `Entry` data
|
||||
* caller function field for go1.14
|
||||
* fix build issue for gopherjs target
|
||||
|
||||
Feature:
|
||||
|
||||
* add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level
|
||||
* add a `DisableHTMLEscape` option in the `JSONFormatter`
|
||||
* add `ForceQuote` and `PadLevelText` options in the `TextFormatter`
|
||||
|
||||
# 1.4.2
|
||||
## 1.4.2
|
||||
|
||||
* Fixes build break for plan9, nacl, solaris
|
||||
# 1.4.1
|
||||
|
||||
## 1.4.1
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* Enhance TextFormatter to not print caller information when they are empty (#944)
|
||||
* Remove dependency on golang.org/x/crypto (#932, #943)
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
|
||||
|
||||
# 1.4.0
|
||||
## 1.4.0
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
||||
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911)
|
||||
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
|
||||
|
||||
Fixes:
|
||||
|
||||
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
|
||||
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
|
||||
* Fix infinite recursion on unknown `Level.String()` (#907)
|
||||
* Fix race condition in `getCaller` (#916).
|
||||
|
||||
|
||||
# 1.3.0
|
||||
## 1.3.0
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* Log, Logf, Logln functions for Logger and Entry that take a Level
|
||||
|
||||
Fixes:
|
||||
|
||||
* Building prometheus node_exporter on AIX (#840)
|
||||
* Race condition in TextFormatter (#468)
|
||||
* Travis CI import path (#868)
|
||||
|
|
@ -92,20 +248,26 @@ Fixes:
|
|||
* Pointer to func as field in JSONFormatter (#870)
|
||||
* Properly marshal Levels (#873)
|
||||
|
||||
# 1.2.0
|
||||
## 1.2.0
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
||||
* A new trace level named `Trace` whose level is below `Debug`
|
||||
* A configurable exit function to be called upon a Fatal trace
|
||||
* The `Level` object now implements `encoding.TextUnmarshaler` interface
|
||||
|
||||
# 1.1.1
|
||||
## 1.1.1
|
||||
|
||||
This is a bug fix release.
|
||||
|
||||
* fix the build break on Solaris
|
||||
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
|
||||
|
||||
# 1.1.0
|
||||
## 1.1.0
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* several fixes:
|
||||
* a fix for a race condition on entry formatting
|
||||
* proper cleanup of previously used entries before putting them back in the pool
|
||||
|
|
@ -122,9 +284,10 @@ This new release introduces:
|
|||
* the field sort function is now configurable for text formatter
|
||||
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
|
||||
|
||||
# 1.0.6
|
||||
## 1.0.6
|
||||
|
||||
This new release introduces:
|
||||
|
||||
* a new api WithTime which allows to easily force the time of the log entry
|
||||
which is mostly useful for logger wrapper
|
||||
* a fix reverting the immutability of the entry given as parameter to the hooks
|
||||
|
|
@ -134,71 +297,71 @@ This new release introduces:
|
|||
* a new configuration of the textformatter to configure the name of the default keys
|
||||
* a new configuration of the text formatter to disable the level truncation
|
||||
|
||||
# 1.0.5
|
||||
## 1.0.5
|
||||
|
||||
* Fix hooks race (#707)
|
||||
* Fix panic deadlock (#695)
|
||||
|
||||
# 1.0.4
|
||||
## 1.0.4
|
||||
|
||||
* Fix race when adding hooks (#612)
|
||||
* Fix terminal check in AppEngine (#635)
|
||||
|
||||
# 1.0.3
|
||||
## 1.0.3
|
||||
|
||||
* Replace example files with testable examples
|
||||
|
||||
# 1.0.2
|
||||
## 1.0.2
|
||||
|
||||
* bug: quote non-string values in text formatter (#583)
|
||||
* Make (*Logger) SetLevel a public method
|
||||
|
||||
# 1.0.1
|
||||
## 1.0.1
|
||||
|
||||
* bug: fix escaping in text formatter (#575)
|
||||
|
||||
# 1.0.0
|
||||
## 1.0.0
|
||||
|
||||
* Officially changed name to lower-case
|
||||
* bug: colors on Windows 10 (#541)
|
||||
* bug: fix race in accessing level (#512)
|
||||
|
||||
# 0.11.5
|
||||
## 0.11.5
|
||||
|
||||
* feature: add writer and writerlevel to entry (#372)
|
||||
|
||||
# 0.11.4
|
||||
## 0.11.4
|
||||
|
||||
* bug: fix undefined variable on solaris (#493)
|
||||
|
||||
# 0.11.3
|
||||
## 0.11.3
|
||||
|
||||
* formatter: configure quoting of empty values (#484)
|
||||
* formatter: configure quoting character (default is `"`) (#484)
|
||||
* bug: fix not importing io correctly in non-linux environments (#481)
|
||||
|
||||
# 0.11.2
|
||||
## 0.11.2
|
||||
|
||||
* bug: fix windows terminal detection (#476)
|
||||
|
||||
# 0.11.1
|
||||
## 0.11.1
|
||||
|
||||
* bug: fix tty detection with custom out (#471)
|
||||
|
||||
# 0.11.0
|
||||
## 0.11.0
|
||||
|
||||
* performance: Use bufferpool to allocate (#370)
|
||||
* terminal: terminal detection for app-engine (#343)
|
||||
* feature: exit handler (#375)
|
||||
|
||||
# 0.10.0
|
||||
## 0.10.0
|
||||
|
||||
* feature: Add a test hook (#180)
|
||||
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||
* performance: avoid re-allocations on `WithFields` (#335)
|
||||
|
||||
# 0.9.0
|
||||
## 0.9.0
|
||||
|
||||
* logrus/text_formatter: don't emit empty msg
|
||||
* logrus/hooks/airbrake: move out of main repository
|
||||
|
|
@ -210,25 +373,25 @@ This new release introduces:
|
|||
* logrus/core: support `WithError` on logger
|
||||
* logrus/core: Solaris support
|
||||
|
||||
# 0.8.7
|
||||
## 0.8.7
|
||||
|
||||
* logrus/core: fix possible race (#216)
|
||||
* logrus/doc: small typo fixes and doc improvements
|
||||
|
||||
|
||||
# 0.8.6
|
||||
## 0.8.6
|
||||
|
||||
* hooks/raven: allow passing an initialized client
|
||||
|
||||
# 0.8.5
|
||||
## 0.8.5
|
||||
|
||||
* logrus/core: revert #208
|
||||
|
||||
# 0.8.4
|
||||
## 0.8.4
|
||||
|
||||
* formatter/text: fix data race (#218)
|
||||
|
||||
# 0.8.3
|
||||
## 0.8.3
|
||||
|
||||
* logrus/core: fix entry log level (#208)
|
||||
* logrus/core: improve performance of text formatter by 40%
|
||||
|
|
@ -236,24 +399,24 @@ This new release introduces:
|
|||
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||
* formatter/text: print structs more verbosely
|
||||
|
||||
# 0.8.2
|
||||
## 0.8.2
|
||||
|
||||
* logrus: fix more Fatal family functions
|
||||
|
||||
# 0.8.1
|
||||
## 0.8.1
|
||||
|
||||
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||
|
||||
# 0.8.0
|
||||
## 0.8.0
|
||||
|
||||
* logrus: defaults to stderr instead of stdout
|
||||
* hooks/sentry: add special field for `*http.Request`
|
||||
* formatter/text: ignore Windows for colors
|
||||
|
||||
# 0.7.3
|
||||
## 0.7.3
|
||||
|
||||
* formatter/\*: allow configuration of timestamp layout
|
||||
|
||||
# 0.7.2
|
||||
## 0.7.2
|
||||
|
||||
* formatter/text: Add configuration option for time format (#158)
|
||||
|
|
|
|||
92
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
92
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
|
|
@ -3,13 +3,10 @@
|
|||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger.
|
||||
|
||||
**Logrus is in maintenance-mode.** We will not be introducing new features. It's
|
||||
simply too hard to do in a way that won't break many people's projects, which is
|
||||
the last thing you want from your Logging library (again...).
|
||||
|
||||
This does not mean Logrus is dead. Logrus will continue to be maintained for
|
||||
security, (backwards compatible) bug fixes, and performance (where we are
|
||||
limited by the interface).
|
||||
**Logrus is in maintenance mode.** The project focuses on security, bug fixes,
|
||||
and performance improvements. New features are not planned, aside from changes
|
||||
required to provide interoperability with other logging ecosystems (e.g., Go's
|
||||
[log/slog](https://pkg.go.dev/log/slog)).
|
||||
|
||||
I believe Logrus' biggest contribution is to have played a part in today's
|
||||
widespread use of structured logging in Golang. There doesn't seem to be a
|
||||
|
|
@ -23,18 +20,6 @@ about structured logging in Go today. Check out, for example,
|
|||
[zap]: https://github.com/uber-go/zap
|
||||
[apex]: https://github.com/apex/log
|
||||
|
||||
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
||||
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
||||
this caused issues in the community and we needed a standard. Some environments
|
||||
experienced problems with the upper-case variant, so the lower-case was decided.
|
||||
Everything using `logrus` will need to use the lower-case:
|
||||
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
||||
|
||||
To fix Glide, see [these
|
||||
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
||||
For an in-depth explanation of the casing issue, see [this
|
||||
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
||||
|
||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||
plain text):
|
||||
|
||||
|
|
@ -43,35 +28,27 @@ plain text):
|
|||
With `logrus.SetFormatter(&logrus.JSONFormatter{})`, for easy parsing by logstash
|
||||
or Splunk:
|
||||
|
||||
```text
|
||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||
|
||||
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||
|
||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||
```json lines
|
||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||
{"level":"warning","msg":"The group's number increased tremendously!","number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!","size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.","size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||
```
|
||||
|
||||
With the default `logrus.SetFormatter(&logrus.TextFormatter{})` when a TTY is not
|
||||
attached, the output is compatible with the
|
||||
[logfmt](https://pkg.go.dev/github.com/kr/logfmt) format:
|
||||
|
||||
```text
|
||||
```bash
|
||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" animal=orca err="It's over 9000!" number=100 omg=true size=9009
|
||||
```
|
||||
|
||||
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
||||
|
||||
```go
|
||||
|
|
@ -88,29 +65,32 @@ If you wish to add the calling method as a field, instruct the logger via:
|
|||
```go
|
||||
logrus.SetReportCaller(true)
|
||||
```
|
||||
|
||||
This adds the caller as 'method' like so:
|
||||
|
||||
```json
|
||||
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
||||
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by","time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||
```
|
||||
|
||||
```text
|
||||
```bash
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
||||
```
|
||||
|
||||
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
||||
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
||||
environment via benchmarks:
|
||||
|
||||
```bash
|
||||
go test -bench=.*CallerTracing
|
||||
go test -bench=ReportCaller
|
||||
```
|
||||
|
||||
#### Case-sensitivity
|
||||
|
||||
The organization's name was changed to lower-case--and this will not be changed
|
||||
back. If you are getting import conflicts due to case sensitivity, please use
|
||||
the lower-case import: `github.com/sirupsen/logrus`.
|
||||
The organization's name was [changed to lower-case][1]. If you are getting import
|
||||
conflicts due to case sensitivity, please use the lower-case import:
|
||||
`github.com/sirupsen/logrus`.
|
||||
|
||||
[1]: https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276
|
||||
|
||||
#### Example
|
||||
|
||||
|
|
@ -289,6 +269,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: Syslog hooks also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||
|
||||
A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
||||
|
|
@ -367,18 +348,21 @@ Splunk or Logstash.
|
|||
|
||||
The built-in logging formatters are:
|
||||
|
||||
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||
without colors.
|
||||
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||
* [`logrus.TextFormatter`](https://pkg.go.dev/github.com/sirupsen/logrus#TextFormatter)
|
||||
logs the event in colors if the logger output is a TTY, otherwise without colors.
|
||||
* To force colored output when there is no TTY, set the `ForceColors`
|
||||
field to `true`. To force no colored output even if there is a TTY set the
|
||||
`DisableColors` field to `true`. For Windows, see
|
||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||
`DisableColors` field to `true`.
|
||||
* On modern Windows terminals with ANSI (Virtual Terminal) support, TextFormatter
|
||||
automatically enables colored output.
|
||||
* If your environment does not support ANSI escape sequences, wrap the logger output
|
||||
using [github.com/mattn/go-colorable](https://github.com/mattn/go-colorable)
|
||||
and set `ForceColors` (or `CLICOLOR_FORCE=1`) to enable colors through the wrapper.
|
||||
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||
truncation set the `DisableLevelTruncation` field to `true`.
|
||||
* When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
|
||||
* All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#TextFormatter).
|
||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||
* All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter).
|
||||
* [`logrus.JSONFormatter`](https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter)
|
||||
logs fields as JSON.
|
||||
|
||||
Third-party logging formatters:
|
||||
|
||||
|
|
@ -390,10 +374,12 @@ Third-party logging formatters:
|
|||
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
|
||||
* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Save log to files.
|
||||
* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
|
||||
* [`easy-logrus-formatter`](https://github.com/WeiZhixiong/easy-logrus-formatter). Provide a user-friendly formatter for logrus.
|
||||
* [`redactrus`](https://github.com/ibreakthecloud/redactrus). Redacts sensitive information like password, apikeys, email, etc. from logs.
|
||||
|
||||
You can define your formatter by implementing the `Formatter` interface,
|
||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||
`Fields` type (`map[string]any`) with all your fields as well as the
|
||||
default ones (see Entries section above):
|
||||
|
||||
```go
|
||||
|
|
@ -516,4 +502,4 @@ Situations when locking is not needed include:
|
|||
|
||||
2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)
|
||||
|
||||
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
|
||||
(Refer to <http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/>)
|
||||
|
|
|
|||
4
vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
4
vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
|
|
@ -57,7 +57,7 @@ func Exit(code int) {
|
|||
//
|
||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||
// message but also needs to gracefully shutdown. An example usecase could be
|
||||
// closing database connections, or sending a alert that the application is
|
||||
// closing database connections, or sending an alert that the application is
|
||||
// closing.
|
||||
func RegisterExitHandler(handler func()) {
|
||||
handlers = append(handlers, handler)
|
||||
|
|
@ -69,7 +69,7 @@ func RegisterExitHandler(handler func()) {
|
|||
//
|
||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||
// message but also needs to gracefully shutdown. An example usecase could be
|
||||
// closing database connections, or sending a alert that the application is
|
||||
// closing database connections, or sending an alert that the application is
|
||||
// closing.
|
||||
func DeferExitHandler(handler func()) {
|
||||
handlers = append([]func(){handler}, handlers...)
|
||||
|
|
|
|||
22
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
22
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
|
|
@ -5,9 +5,13 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
bufferPool BufferPool
|
||||
)
|
||||
var bufferPool BufferPool = &defaultPool{
|
||||
pool: &sync.Pool{
|
||||
New: func() any {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type BufferPool interface {
|
||||
Put(*bytes.Buffer)
|
||||
|
|
@ -27,17 +31,7 @@ func (p *defaultPool) Get() *bytes.Buffer {
|
|||
}
|
||||
|
||||
// SetBufferPool allows to replace the default logrus buffer pool
|
||||
// to better meets the specific needs of an application.
|
||||
// to better meet the specific needs of an application.
|
||||
func SetBufferPool(bp BufferPool) {
|
||||
bufferPool = bp
|
||||
}
|
||||
|
||||
func init() {
|
||||
SetBufferPool(&defaultPool{
|
||||
pool: &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
26
vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
26
vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
|
|
@ -1,25 +1,25 @@
|
|||
/*
|
||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
|
||||
package main
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 1,
|
||||
"size": 10,
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 1,
|
||||
"size": 10,
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
|
||||
Output:
|
||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||
|
||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||
|
||||
For a full guide visit https://github.com/sirupsen/logrus
|
||||
*/
|
||||
|
|
|
|||
414
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
414
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
|
|
@ -4,9 +4,11 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -17,8 +19,10 @@ var (
|
|||
// qualified package name, cached at first use
|
||||
logrusPackage string
|
||||
|
||||
// Positions in the call stack when tracing to report the calling method
|
||||
minimumCallerDepth int
|
||||
// Positions in the call stack when tracing to report the calling method.
|
||||
//
|
||||
// Start at the bottom of the stack before the package-name cache is primed.
|
||||
minimumCallerDepth = 1
|
||||
|
||||
// Used for caller information initialisation
|
||||
callerInitOnce sync.Once
|
||||
|
|
@ -29,68 +33,116 @@ const (
|
|||
knownLogrusFrames int = 4
|
||||
)
|
||||
|
||||
func init() {
|
||||
// start at the bottom of the stack before the package-name cache is primed
|
||||
minimumCallerDepth = 1
|
||||
}
|
||||
|
||||
// ErrorKey defines the key when adding errors using [WithError], [Logger.WithError].
|
||||
var ErrorKey = "error"
|
||||
|
||||
// Entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
||||
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
||||
// reused and passed around as much as you wish to avoid field duplication.
|
||||
// Entry represents a single log event. It may be either an intermediate
|
||||
// entry (created via WithField(s), WithContext, etc.) or a final entry
|
||||
// that is emitted when one of the level methods (Trace, Debug, Info,
|
||||
// Warn, Error, Fatal, Panic) is called.
|
||||
//
|
||||
//nolint:recvcheck // the methods of "Entry" use pointer receiver and non-pointer receiver.
|
||||
// An Entry always belongs to a Logger. A nil Logger is invalid and will
|
||||
// cause a panic when the entry is logged. Use [NewEntry] or Logger methods
|
||||
// to construct entries.
|
||||
//
|
||||
// Entries are safe to reuse for adding fields and may be passed around
|
||||
// to avoid field duplication. Each log operation operates on a copy
|
||||
// of the Entry’s data to avoid mutation during formatting.
|
||||
//
|
||||
//nolint:recvcheck // Entry methods intentionally use both pointer and value receivers.
|
||||
type Entry struct {
|
||||
// Logger is the Logger that owns this entry and is responsible for
|
||||
// formatting, hooks, and output. It must not be nil. An Entry without
|
||||
// a Logger is invalid and will panic when logged.
|
||||
Logger *Logger
|
||||
|
||||
// Contains all the fields set by the user.
|
||||
// Data contains all user-defined fields attached to this entry.
|
||||
Data Fields
|
||||
|
||||
// Time at which the log entry was created
|
||||
// Time is the timestamp for the log event. If zero when the entry is
|
||||
// logged, it defaults to the current time.
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||
// Level is the severity of the log entry. It is set when the entry
|
||||
// is fired and reflects the level used for that log call.
|
||||
Level Level
|
||||
|
||||
// Calling method, with package name
|
||||
// Caller contains the calling method information.
|
||||
//
|
||||
// When [Logger.ReportCaller] is enabled, Caller is populated automatically at
|
||||
// log time if it is nil. Hooks and formatters may inspect Caller.
|
||||
//
|
||||
// Applications generally should not modify Caller unless they intentionally
|
||||
// want to provide custom caller information.
|
||||
Caller *runtime.Frame
|
||||
|
||||
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
// Message is the log message supplied to one of the logging methods
|
||||
// (Trace, Debug, Info, Warn, Error, Fatal, or Panic). It is set when
|
||||
// the entry is logged.
|
||||
Message string
|
||||
|
||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||
// Buffer is a reusable buffer provided to the formatter. It is set
|
||||
// before formatting in the normal log path; when nil, formatters
|
||||
// allocate their own.
|
||||
Buffer *bytes.Buffer
|
||||
|
||||
// Contains the context set by the user. Useful for hook processing etc.
|
||||
// Context carries user-provided context for hooks and formatters.
|
||||
Context context.Context
|
||||
|
||||
// err may contain a field formatting error
|
||||
// err contains internal field-formatting errors.
|
||||
err string
|
||||
}
|
||||
|
||||
// NewEntry creates a new [Entry] associated with the provided Logger.
|
||||
// The logger must not be nil. Passing a nil logger results in a
|
||||
// panic when a logging method (e.g., [Entry.Info], [Entry.Error], etc.)
|
||||
// is called.
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, plus one optional. Give a little extra room.
|
||||
Data: make(Fields, 6),
|
||||
// Reserve default predefined fields and a little extra room.
|
||||
Data: make(Fields, defaultFields+3),
|
||||
}
|
||||
}
|
||||
|
||||
// Dup creates a copy of the entry for further modification.
|
||||
//
|
||||
// Data is cloned to avoid mutating the original entry. Other fields
|
||||
// (Logger, Time, Context, etc.) are copied by value.
|
||||
func (entry *Entry) Dup() *Entry {
|
||||
data := make(Fields, len(entry.Data))
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
dup := entry.dup()
|
||||
dup.Data = maps.Clone(entry.Data)
|
||||
return dup
|
||||
}
|
||||
|
||||
// dup copies the entry fields shared by derived entries except Data, which
|
||||
// callers must copy or initialize as appropriate for their use.
|
||||
func (entry *Entry) dup() *Entry {
|
||||
return &Entry{
|
||||
Logger: entry.Logger,
|
||||
Time: entry.Time,
|
||||
Caller: entry.Caller,
|
||||
Context: entry.Context,
|
||||
err: entry.err,
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err}
|
||||
}
|
||||
|
||||
// Bytes returns the bytes representation of this entry from the formatter.
|
||||
func (entry *Entry) Bytes() ([]byte, error) {
|
||||
return entry.Logger.Formatter.Format(entry)
|
||||
// Snapshot the formatter under the lock to protect against concurrent
|
||||
// SetFormatter calls, then release the lock before formatting.
|
||||
// This avoids a data race and prevents a deadlock if Format() triggers
|
||||
// reentrant logging (e.g., a field's MarshalJSON calls logrus).
|
||||
//
|
||||
// See:
|
||||
//
|
||||
// - https://github.com/sirupsen/logrus/issues/1440
|
||||
// - https://github.com/sirupsen/logrus/issues/1448
|
||||
entry.Logger.mu.Lock()
|
||||
formatter := entry.Logger.Formatter
|
||||
entry.Logger.mu.Unlock()
|
||||
|
||||
return formatter.Format(entry)
|
||||
}
|
||||
|
||||
// String returns the string representation from the reader and ultimately the
|
||||
|
|
@ -112,58 +164,61 @@ func (entry *Entry) WithError(err error) *Entry {
|
|||
|
||||
// WithContext adds a context to the Entry.
|
||||
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
||||
dataCopy := make(Fields, len(entry.Data))
|
||||
for k, v := range entry.Data {
|
||||
dataCopy[k] = v
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
|
||||
dup := entry.dup()
|
||||
dup.Data = maps.Clone(entry.Data)
|
||||
dup.Context = ctx
|
||||
return dup
|
||||
}
|
||||
|
||||
// WithField adds a single field to the Entry.
|
||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||
return entry.WithFields(Fields{key: value})
|
||||
func (entry *Entry) WithField(key string, value any) *Entry {
|
||||
dup := entry.dup()
|
||||
dup.Data = maps.Clone(entry.Data)
|
||||
dup.addField(key, value)
|
||||
return dup
|
||||
}
|
||||
|
||||
// WithFields adds a map of fields to the Entry.
|
||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
data := make(Fields, len(entry.Data)+len(fields))
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
dup := entry.dup()
|
||||
dup.Data = make(Fields, len(entry.Data)+len(fields))
|
||||
maps.Copy(dup.Data, entry.Data)
|
||||
|
||||
for key, value := range fields {
|
||||
dup.addField(key, value)
|
||||
}
|
||||
fieldErr := entry.err
|
||||
for k, v := range fields {
|
||||
isErrField := false
|
||||
if t := reflect.TypeOf(v); t != nil {
|
||||
switch {
|
||||
case t.Kind() == reflect.Func, t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func:
|
||||
isErrField = true
|
||||
}
|
||||
}
|
||||
if isErrField {
|
||||
tmp := fmt.Sprintf("can not add field %q", k)
|
||||
if fieldErr != "" {
|
||||
fieldErr = entry.err + ", " + tmp
|
||||
} else {
|
||||
fieldErr = tmp
|
||||
}
|
||||
} else {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
|
||||
return dup
|
||||
}
|
||||
|
||||
// WithTime overrides the time of the Entry.
|
||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||
dataCopy := make(Fields, len(entry.Data))
|
||||
for k, v := range entry.Data {
|
||||
dataCopy[k] = v
|
||||
dup := entry.dup()
|
||||
dup.Data = maps.Clone(entry.Data)
|
||||
dup.Time = t
|
||||
return dup
|
||||
}
|
||||
|
||||
func (entry *Entry) addField(key string, value any) {
|
||||
if _, ok := value.(error); !ok {
|
||||
t := reflect.TypeOf(value)
|
||||
if t != nil && (t.Kind() == reflect.Func || t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Func) {
|
||||
if entry.err != "" {
|
||||
entry.err += ", skipping unsupported field " + strconv.Quote(key)
|
||||
} else {
|
||||
entry.err = "skipping unsupported field " + strconv.Quote(key)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
|
||||
|
||||
if entry.Data == nil {
|
||||
entry.Data = make(Fields, 1)
|
||||
}
|
||||
entry.Data[key] = value
|
||||
}
|
||||
|
||||
// getPackageName reduces a fully qualified function name to the package name
|
||||
// There really ought to be to be a better way...
|
||||
// There really ought to be a better way...
|
||||
func getPackageName(f string) string {
|
||||
for {
|
||||
lastPeriod := strings.LastIndex(f, ".")
|
||||
|
|
@ -186,7 +241,7 @@ func getCaller() *runtime.Frame {
|
|||
_ = runtime.Callers(0, pcs)
|
||||
|
||||
// dynamic get the package name and the minimum caller depth
|
||||
for i := 0; i < maximumCallerDepth; i++ {
|
||||
for i := range maximumCallerDepth {
|
||||
funcName := runtime.FuncForPC(pcs[i]).Name()
|
||||
if strings.Contains(funcName, "getCaller") {
|
||||
logrusPackage = getPackageName(funcName)
|
||||
|
|
@ -215,16 +270,47 @@ func getCaller() *runtime.Frame {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (entry Entry) HasCaller() (has bool) {
|
||||
return entry.Logger != nil &&
|
||||
entry.Logger.ReportCaller &&
|
||||
entry.Caller != nil
|
||||
// HasCaller reports whether this Entry contains caller information.
|
||||
//
|
||||
// Caller may be set explicitly, or populated at log time when
|
||||
// [Logger.ReportCaller] is enabled.
|
||||
//
|
||||
// Deprecated: use [Entry.Caller] != nil instead.
|
||||
//
|
||||
//go:fix inline
|
||||
func (entry Entry) HasCaller() bool {
|
||||
return entry.Caller != nil
|
||||
}
|
||||
|
||||
func (entry *Entry) log(level Level, msg string) {
|
||||
var buffer *bytes.Buffer
|
||||
func (entry *Entry) logArgs(level Level, panicAfter bool, args ...any) {
|
||||
entry.log(level, panicAfter, sprint(args...))
|
||||
}
|
||||
|
||||
newEntry := entry.Dup()
|
||||
func (entry *Entry) logf(level Level, panicAfter bool, format string, args ...any) {
|
||||
entry.log(level, panicAfter, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// logln uses Sprintln for multiple arguments to preserve Println-style
|
||||
// spacing between args, then trims the trailing newline.
|
||||
func (entry *Entry) logln(level Level, panicAfter bool, args ...any) {
|
||||
if len(args) <= 1 {
|
||||
entry.log(level, panicAfter, sprint(args...))
|
||||
return
|
||||
}
|
||||
msg := fmt.Sprintln(args...)
|
||||
msg = msg[:len(msg)-1] // Trim the newline added by Sprintln; logging adds its own.
|
||||
entry.log(level, panicAfter, msg)
|
||||
}
|
||||
|
||||
// log writes msg at level. If panicAfter is true, it panics with the fully
|
||||
// populated entry after hooks and output have completed.
|
||||
//
|
||||
// The explicit flag keeps panic behavior limited to Panic, Panicf, and
|
||||
// Panicln while avoiding a return value used only as the panic value.
|
||||
// See #1283 and commits f96066e and 5f8c666.
|
||||
func (entry *Entry) log(level Level, panicAfter bool, msg string) {
|
||||
newEntry := entry.dup()
|
||||
newEntry.Data = maps.Clone(entry.Data)
|
||||
|
||||
if newEntry.Time.IsZero() {
|
||||
newEntry.Time = time.Now()
|
||||
|
|
@ -233,17 +319,24 @@ func (entry *Entry) log(level Level, msg string) {
|
|||
newEntry.Level = level
|
||||
newEntry.Message = msg
|
||||
|
||||
newEntry.Logger.mu.Lock()
|
||||
reportCaller := newEntry.Logger.ReportCaller
|
||||
logger := newEntry.Logger
|
||||
logger.mu.Lock()
|
||||
reportCaller := logger.ReportCaller
|
||||
bufPool := newEntry.getBufferPool()
|
||||
newEntry.Logger.mu.Unlock()
|
||||
logger.mu.Unlock()
|
||||
|
||||
if reportCaller {
|
||||
// Preserve explicitly set caller information.
|
||||
if reportCaller && newEntry.Caller == nil {
|
||||
newEntry.Caller = getCaller()
|
||||
}
|
||||
|
||||
newEntry.fireHooks()
|
||||
buffer = bufPool.Get()
|
||||
// Select hooks based on the level for this log call. Hooks receive the
|
||||
// Entry and may mutate it, but that does not affect which hooks are
|
||||
// fired for this event.
|
||||
hooks := logger.hooksForLevel(level)
|
||||
newEntry.fireHooks(hooks)
|
||||
|
||||
buffer := bufPool.Get()
|
||||
defer func() {
|
||||
newEntry.Buffer = nil
|
||||
buffer.Reset()
|
||||
|
|
@ -251,15 +344,12 @@ func (entry *Entry) log(level Level, msg string) {
|
|||
}()
|
||||
buffer.Reset()
|
||||
newEntry.Buffer = buffer
|
||||
|
||||
newEntry.write()
|
||||
|
||||
newEntry.Buffer = nil
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
// directly here.
|
||||
if level <= PanicLevel {
|
||||
// Panic here so the panic value contains the fully populated entry without
|
||||
// requiring log to return it to the caller.
|
||||
if panicAfter {
|
||||
panic(newEntry)
|
||||
}
|
||||
}
|
||||
|
|
@ -271,175 +361,207 @@ func (entry *Entry) getBufferPool() (pool BufferPool) {
|
|||
return bufferPool
|
||||
}
|
||||
|
||||
func (entry *Entry) fireHooks() {
|
||||
var tmpHooks LevelHooks
|
||||
entry.Logger.mu.Lock()
|
||||
tmpHooks = make(LevelHooks, len(entry.Logger.Hooks))
|
||||
for k, v := range entry.Logger.Hooks {
|
||||
tmpHooks[k] = v
|
||||
}
|
||||
entry.Logger.mu.Unlock()
|
||||
|
||||
err := tmpHooks.Fire(entry.Level, entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
func (entry *Entry) fireHooks(hooks []Hook) {
|
||||
for _, hook := range hooks {
|
||||
if err := hook.Fire(entry); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Failed to fire hook:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) write() {
|
||||
// Snapshot the formatter under the lock to protect against concurrent
|
||||
// SetFormatter calls, then release the lock before formatting.
|
||||
// This avoids a deadlock when Format() triggers reentrant logging (e.g.,
|
||||
// a field's MarshalJSON calls logrus). See #1448, #1440.
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
formatter := entry.Logger.Formatter
|
||||
entry.Logger.mu.Unlock()
|
||||
|
||||
serialized, err := formatter.Format(entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Failed to format entry:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Re-acquire the lock to serialize writes to the underlying io.Writer.
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
if _, err := entry.Logger.Out.Write(serialized); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
_, _ = fmt.Fprintln(os.Stderr, "Failed to write to log:", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Log will log a message at the level given as parameter.
|
||||
// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
|
||||
// For this behaviour Entry.Panic or Entry.Fatal should be used instead.
|
||||
func (entry *Entry) Log(level Level, args ...interface{}) {
|
||||
// Log logs a message at the specified level.
|
||||
//
|
||||
// Using Log with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Log treats the level as logging severity only;
|
||||
// use [Entry.Panic] or [Entry.Fatal] when those side effects are desired.
|
||||
func (entry *Entry) Log(level Level, args ...any) {
|
||||
const panicAfter = false
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.log(level, fmt.Sprint(args...))
|
||||
entry.logArgs(level, panicAfter, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Trace(args ...interface{}) {
|
||||
func (entry *Entry) Trace(args ...any) {
|
||||
entry.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
func (entry *Entry) Debug(args ...any) {
|
||||
entry.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
func (entry *Entry) Print(args ...any) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
func (entry *Entry) Info(args ...any) {
|
||||
entry.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
func (entry *Entry) Warn(args ...any) {
|
||||
entry.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
func (entry *Entry) Warning(args ...any) {
|
||||
entry.Warn(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
func (entry *Entry) Error(args ...any) {
|
||||
entry.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
func (entry *Entry) Fatal(args ...any) {
|
||||
entry.Log(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
entry.Log(PanicLevel, args...)
|
||||
func (entry *Entry) Panic(args ...any) {
|
||||
const panicAfter = true
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.logArgs(PanicLevel, panicAfter, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||
// Logf logs a formatted message at the specified level.
|
||||
//
|
||||
// Using Logf with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Logf treats the level as logging severity only;
|
||||
// use [Entry.Panicf] or [Entry.Fatalf] when those side effects are desired.
|
||||
func (entry *Entry) Logf(level Level, format string, args ...any) {
|
||||
const panicAfter = false
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.Log(level, fmt.Sprintf(format, args...))
|
||||
entry.logf(level, panicAfter, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||
func (entry *Entry) Tracef(format string, args ...any) {
|
||||
entry.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Debugf(format string, args ...any) {
|
||||
entry.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
func (entry *Entry) Infof(format string, args ...any) {
|
||||
entry.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Printf(format string, args ...any) {
|
||||
entry.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Warnf(format string, args ...any) {
|
||||
entry.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Warningf(format string, args ...any) {
|
||||
entry.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Errorf(format string, args ...any) {
|
||||
entry.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
func (entry *Entry) Fatalf(format string, args ...any) {
|
||||
entry.Logf(FatalLevel, format, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
entry.Logf(PanicLevel, format, args...)
|
||||
func (entry *Entry) Panicf(format string, args ...any) {
|
||||
const panicAfter = true
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.logf(PanicLevel, panicAfter, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Logln(level Level, args ...interface{}) {
|
||||
// Logln logs a message at the specified level with Println-style spacing.
|
||||
//
|
||||
// Using Logln with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Logln treats the level as logging severity only;
|
||||
// use [Entry.Panicln] or [Entry.Fatalln] when those side effects are desired.
|
||||
func (entry *Entry) Logln(level Level, args ...any) {
|
||||
const panicAfter = false
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.Log(level, entry.sprintlnn(args...))
|
||||
entry.logln(level, panicAfter, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Traceln(args ...interface{}) {
|
||||
func (entry *Entry) Traceln(args ...any) {
|
||||
entry.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
func (entry *Entry) Debugln(args ...any) {
|
||||
entry.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
func (entry *Entry) Infoln(args ...any) {
|
||||
entry.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
func (entry *Entry) Println(args ...any) {
|
||||
entry.Infoln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
func (entry *Entry) Warnln(args ...any) {
|
||||
entry.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
func (entry *Entry) Warningln(args ...any) {
|
||||
entry.Warnln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
func (entry *Entry) Errorln(args ...any) {
|
||||
entry.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
func (entry *Entry) Fatalln(args ...any) {
|
||||
entry.Logln(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
entry.Logln(PanicLevel, args...)
|
||||
func (entry *Entry) Panicln(args ...any) {
|
||||
const panicAfter = true
|
||||
if entry.Logger.IsLevelEnabled(PanicLevel) {
|
||||
entry.logln(PanicLevel, panicAfter, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||
// string allocation, we do the simplest thing.
|
||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||
msg := fmt.Sprintln(args...)
|
||||
return msg[:len(msg)-1]
|
||||
// sprint is fmt.Sprint with fast paths for zero or one string argument.
|
||||
func sprint(args ...any) string {
|
||||
switch len(args) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
if msg, ok := args[0].(string); ok {
|
||||
return msg
|
||||
}
|
||||
}
|
||||
return fmt.Sprint(args...)
|
||||
}
|
||||
|
|
|
|||
169
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
169
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
|
|
@ -6,11 +6,12 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// std is the name of the standard logger in stdlib `log`
|
||||
std = New()
|
||||
)
|
||||
// std is the package-level standard logger, similar to the default logger
|
||||
// in the stdlib [log] package.
|
||||
var std = New()
|
||||
|
||||
// StandardLogger returns the package-level standard logger used by
|
||||
// the top-level logging functions.
|
||||
func StandardLogger() *Logger {
|
||||
return std
|
||||
}
|
||||
|
|
@ -41,7 +42,7 @@ func GetLevel() Level {
|
|||
return std.GetLevel()
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
||||
// IsLevelEnabled checks if logging for the given level is enabled for the standard logger.
|
||||
func IsLevelEnabled(level Level) bool {
|
||||
return std.IsLevelEnabled(level)
|
||||
}
|
||||
|
|
@ -51,9 +52,10 @@ func AddHook(hook Hook) {
|
|||
std.AddHook(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
// WithError creates an entry from the standard logger and adds an error to it,
|
||||
// using the value defined in [ErrorKey] as key.
|
||||
func WithError(err error) *Entry {
|
||||
return std.WithField(ErrorKey, err)
|
||||
return std.WithError(err)
|
||||
}
|
||||
|
||||
// WithContext creates an entry from the standard logger and adds a context to it.
|
||||
|
|
@ -61,210 +63,203 @@ func WithContext(ctx context.Context) *Entry {
|
|||
return std.WithContext(ctx)
|
||||
}
|
||||
|
||||
// WithField creates an entry from the standard logger and adds a field to
|
||||
// it. If you want multiple fields, use `WithFields`.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithField(key string, value interface{}) *Entry {
|
||||
// WithField creates an entry from the standard logger and adds a single field.
|
||||
// For multiple fields, prefer [WithFields] over chaining WithField calls.
|
||||
func WithField(key string, value any) *Entry {
|
||||
return std.WithField(key, value)
|
||||
}
|
||||
|
||||
// WithFields creates an entry from the standard logger and adds multiple
|
||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||
// once for each field.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
// WithFields creates an entry from the standard logger and adds the fields to it.
|
||||
func WithFields(fields Fields) *Entry {
|
||||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// WithTime creates an entry from the standard logger and overrides the time of
|
||||
// logs generated with it.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
// WithTime creates an entry from the standard logger and overrides the time
|
||||
// used for logs generated with it.
|
||||
func WithTime(t time.Time) *Entry {
|
||||
return std.WithTime(t)
|
||||
}
|
||||
|
||||
// Trace logs a message at level Trace on the standard logger.
|
||||
func Trace(args ...interface{}) {
|
||||
// Trace logs a message at level [TraceLevel] on the standard logger.
|
||||
func Trace(args ...any) {
|
||||
std.Trace(args...)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
// Debug logs a message at level [DebugLevel] on the standard logger.
|
||||
func Debug(args ...any) {
|
||||
std.Debug(args...)
|
||||
}
|
||||
|
||||
// Print logs a message at level Info on the standard logger.
|
||||
func Print(args ...interface{}) {
|
||||
// Print logs a message at level [InfoLevel] on the standard logger.
|
||||
func Print(args ...any) {
|
||||
std.Print(args...)
|
||||
}
|
||||
|
||||
// Info logs a message at level Info on the standard logger.
|
||||
func Info(args ...interface{}) {
|
||||
// Info logs a message at level [InfoLevel] on the standard logger.
|
||||
func Info(args ...any) {
|
||||
std.Info(args...)
|
||||
}
|
||||
|
||||
// Warn logs a message at level Warn on the standard logger.
|
||||
func Warn(args ...interface{}) {
|
||||
// Warn logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warn(args ...any) {
|
||||
std.Warn(args...)
|
||||
}
|
||||
|
||||
// Warning logs a message at level Warn on the standard logger.
|
||||
func Warning(args ...interface{}) {
|
||||
// Warning logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warning(args ...any) {
|
||||
std.Warning(args...)
|
||||
}
|
||||
|
||||
// Error logs a message at level Error on the standard logger.
|
||||
func Error(args ...interface{}) {
|
||||
// Error logs a message at level [ErrorLevel] on the standard logger.
|
||||
func Error(args ...any) {
|
||||
std.Error(args...)
|
||||
}
|
||||
|
||||
// Panic logs a message at level Panic on the standard logger.
|
||||
func Panic(args ...interface{}) {
|
||||
// Panic logs a message at level [PanicLevel] on the standard logger.
|
||||
func Panic(args ...any) {
|
||||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatal(args ...interface{}) {
|
||||
// Fatal logs a message at level [FatalLevel] on the standard logger,
|
||||
// then exits the process with status 1.
|
||||
func Fatal(args ...any) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// TraceFn logs a message from a func at level Trace on the standard logger.
|
||||
// TraceFn logs a message from a func at level [TraceLevel] on the standard logger.
|
||||
func TraceFn(fn LogFunction) {
|
||||
std.TraceFn(fn)
|
||||
}
|
||||
|
||||
// DebugFn logs a message from a func at level Debug on the standard logger.
|
||||
// DebugFn logs a message from a func at level [DebugLevel] on the standard logger.
|
||||
func DebugFn(fn LogFunction) {
|
||||
std.DebugFn(fn)
|
||||
}
|
||||
|
||||
// PrintFn logs a message from a func at level Info on the standard logger.
|
||||
// PrintFn logs a message from a func at level [InfoLevel] on the standard logger.
|
||||
func PrintFn(fn LogFunction) {
|
||||
std.PrintFn(fn)
|
||||
}
|
||||
|
||||
// InfoFn logs a message from a func at level Info on the standard logger.
|
||||
// InfoFn logs a message from a func at level [InfoLevel] on the standard logger.
|
||||
func InfoFn(fn LogFunction) {
|
||||
std.InfoFn(fn)
|
||||
}
|
||||
|
||||
// WarnFn logs a message from a func at level Warn on the standard logger.
|
||||
// WarnFn logs a message from a func at level [WarnLevel] on the standard logger.
|
||||
func WarnFn(fn LogFunction) {
|
||||
std.WarnFn(fn)
|
||||
}
|
||||
|
||||
// WarningFn logs a message from a func at level Warn on the standard logger.
|
||||
// WarningFn logs a message from a func at level [WarnLevel] on the standard logger.
|
||||
func WarningFn(fn LogFunction) {
|
||||
std.WarningFn(fn)
|
||||
}
|
||||
|
||||
// ErrorFn logs a message from a func at level Error on the standard logger.
|
||||
// ErrorFn logs a message from a func at level [ErrorLevel] on the standard logger.
|
||||
func ErrorFn(fn LogFunction) {
|
||||
std.ErrorFn(fn)
|
||||
}
|
||||
|
||||
// PanicFn logs a message from a func at level Panic on the standard logger.
|
||||
// PanicFn logs a message from a func at level [PanicLevel] on the standard logger.
|
||||
func PanicFn(fn LogFunction) {
|
||||
std.PanicFn(fn)
|
||||
}
|
||||
|
||||
// FatalFn logs a message from a func at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
// FatalFn logs a message from a func at level [FatalLevel] on the standard logger,
|
||||
// then exits the process with status 1.
|
||||
func FatalFn(fn LogFunction) {
|
||||
std.FatalFn(fn)
|
||||
}
|
||||
|
||||
// Tracef logs a message at level Trace on the standard logger.
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
// Tracef logs a message at level [TraceLevel] on the standard logger.
|
||||
func Tracef(format string, args ...any) {
|
||||
std.Tracef(format, args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
// Debugf logs a message at level [DebugLevel] on the standard logger.
|
||||
func Debugf(format string, args ...any) {
|
||||
std.Debugf(format, args...)
|
||||
}
|
||||
|
||||
// Printf logs a message at level Info on the standard logger.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
// Printf logs a message at level [InfoLevel] on the standard logger.
|
||||
func Printf(format string, args ...any) {
|
||||
std.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Infof logs a message at level Info on the standard logger.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
// Infof logs a message at level [InfoLevel] on the standard logger.
|
||||
func Infof(format string, args ...any) {
|
||||
std.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Warnf logs a message at level Warn on the standard logger.
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
// Warnf logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warnf(format string, args ...any) {
|
||||
std.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Warningf logs a message at level Warn on the standard logger.
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
// Warningf logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warningf(format string, args ...any) {
|
||||
std.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Errorf logs a message at level Error on the standard logger.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
// Errorf logs a message at level [ErrorLevel] on the standard logger.
|
||||
func Errorf(format string, args ...any) {
|
||||
std.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf logs a message at level Panic on the standard logger.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
// Panicf logs a message at level [PanicLevel] on the standard logger.
|
||||
func Panicf(format string, args ...any) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
// Fatalf logs a message at level [FatalLevel] on the standard logger,
|
||||
// then exits the process with status 1.
|
||||
func Fatalf(format string, args ...any) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Traceln logs a message at level Trace on the standard logger.
|
||||
func Traceln(args ...interface{}) {
|
||||
// Traceln logs a message at level [TraceLevel] on the standard logger.
|
||||
func Traceln(args ...any) {
|
||||
std.Traceln(args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
// Debugln logs a message at level [DebugLevel] on the standard logger.
|
||||
func Debugln(args ...any) {
|
||||
std.Debugln(args...)
|
||||
}
|
||||
|
||||
// Println logs a message at level Info on the standard logger.
|
||||
func Println(args ...interface{}) {
|
||||
// Println logs a message at level [InfoLevel] on the standard logger.
|
||||
func Println(args ...any) {
|
||||
std.Println(args...)
|
||||
}
|
||||
|
||||
// Infoln logs a message at level Info on the standard logger.
|
||||
func Infoln(args ...interface{}) {
|
||||
// Infoln logs a message at level [InfoLevel] on the standard logger.
|
||||
func Infoln(args ...any) {
|
||||
std.Infoln(args...)
|
||||
}
|
||||
|
||||
// Warnln logs a message at level Warn on the standard logger.
|
||||
func Warnln(args ...interface{}) {
|
||||
// Warnln logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warnln(args ...any) {
|
||||
std.Warnln(args...)
|
||||
}
|
||||
|
||||
// Warningln logs a message at level Warn on the standard logger.
|
||||
func Warningln(args ...interface{}) {
|
||||
// Warningln logs a message at level [WarnLevel] on the standard logger.
|
||||
func Warningln(args ...any) {
|
||||
std.Warningln(args...)
|
||||
}
|
||||
|
||||
// Errorln logs a message at level Error on the standard logger.
|
||||
func Errorln(args ...interface{}) {
|
||||
// Errorln logs a message at level [ErrorLevel] on the standard logger.
|
||||
func Errorln(args ...any) {
|
||||
std.Errorln(args...)
|
||||
}
|
||||
|
||||
// Panicln logs a message at level Panic on the standard logger.
|
||||
func Panicln(args ...interface{}) {
|
||||
// Panicln logs a message at level [PanicLevel] on the standard logger.
|
||||
func Panicln(args ...any) {
|
||||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalln(args ...interface{}) {
|
||||
// Fatalln logs a message at level [FatalLevel] on the standard logger,
|
||||
// then exits the process with status 1.
|
||||
func Fatalln(args ...any) {
|
||||
std.Fatalln(args...)
|
||||
}
|
||||
|
|
|
|||
47
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
47
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
|
|
@ -2,27 +2,40 @@ package logrus
|
|||
|
||||
import "time"
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
// defaultTimestampFormat is the layout used to format entry timestamps
|
||||
// when a formatter has not specified a custom TimestampFormat.
|
||||
// It follows time.RFC3339 and is applied unless timestamps are disabled.
|
||||
defaultTimestampFormat = time.RFC3339
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
FieldKeyLogrusError = "logrus_error"
|
||||
FieldKeyFunc = "func"
|
||||
FieldKeyFile = "file"
|
||||
|
||||
// defaultFields is the number of commonly included predefined log entry fields
|
||||
// (msg, level, time). It is used as a capacity hint when constructing
|
||||
// intermediate collections during formatting (for example, the fixed key list).
|
||||
//
|
||||
// It does not include the optional "logrus_error", "func", or "file" fields.
|
||||
defaultFields = 3
|
||||
)
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
FieldKeyLogrusError = "logrus_error"
|
||||
FieldKeyFunc = "func"
|
||||
FieldKeyFile = "file"
|
||||
)
|
||||
|
||||
// Formatter is implemented by types that format log entries. It receives an
|
||||
// [*Entry], which contains:
|
||||
//
|
||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||
// * `entry.Data["time"]`. The timestamp.
|
||||
// * `entry.Data["level"]. The level the entry was logged at.
|
||||
// - entry.Message: the message passed to logging methods such as [Info], [Warn], [Error]
|
||||
// - entry.Time: the timestamp
|
||||
// - entry.Level: the log level
|
||||
//
|
||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||
// logged to `logger.Out`.
|
||||
// Additional fields added with [WithField] or [WithFields] are available in
|
||||
// [Entry.Data]. Format should return the formatted log entry as a byte slice,
|
||||
// which is written to [Logger.Out].
|
||||
type Formatter interface {
|
||||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
|
@ -30,12 +43,12 @@ type Formatter interface {
|
|||
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
//
|
||||
// Would just silently drop the user provided level. Instead with this code
|
||||
// it'll logged as:
|
||||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
|
|
|
|||
37
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
37
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type fieldKey string
|
||||
|
|
@ -20,7 +21,13 @@ func (f FieldMap) resolve(key fieldKey) string {
|
|||
return string(key)
|
||||
}
|
||||
|
||||
// JSONFormatter formats logs into parsable json
|
||||
// JSONFormatter formats logs into parsable JSON.
|
||||
//
|
||||
// Fields from [Entry.Data] are included in the JSON object together with the
|
||||
// standard fields derived from the entry. If a field conflicts with a standard
|
||||
// field, it is prefixed with "fields.". Standard field names can be customized
|
||||
// through FieldMap. When DataKey is set, fields from [Entry.Data] are nested
|
||||
// under that key instead.
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
// The format to use is the same than for time.Format or time.Parse from the standard
|
||||
|
|
@ -61,7 +68,8 @@ type JSONFormatter struct {
|
|||
|
||||
// Format renders a single log entry
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+4)
|
||||
caller := entry.Caller
|
||||
data := make(Fields, len(entry.Data)+defaultFields)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
|
|
@ -73,13 +81,14 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if f.DataKey != "" {
|
||||
newData := make(Fields, 4)
|
||||
if f.DataKey != "" && len(entry.Data) > 0 {
|
||||
newData := make(Fields, defaultFields+1)
|
||||
newData[f.DataKey] = data
|
||||
data = newData
|
||||
}
|
||||
|
||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||
hasCaller := caller != nil
|
||||
prefixFieldClashes(data, f.FieldMap, hasCaller)
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
|
|
@ -94,11 +103,13 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
}
|
||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||
if entry.HasCaller() {
|
||||
funcVal := entry.Caller.Function
|
||||
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
if caller != nil {
|
||||
var funcVal, fileVal string
|
||||
if f.CallerPrettyfier != nil {
|
||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||
funcVal, fileVal = f.CallerPrettyfier(caller)
|
||||
} else {
|
||||
funcVal = caller.Function
|
||||
fileVal = caller.File + ":" + strconv.FormatInt(int64(caller.Line), 10)
|
||||
}
|
||||
if funcVal != "" {
|
||||
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
|
||||
|
|
@ -108,11 +119,9 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
b := entry.Buffer
|
||||
if b == nil {
|
||||
b = new(bytes.Buffer)
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(b)
|
||||
|
|
|
|||
101
vendor/github.com/sirupsen/logrus/level.go
generated
vendored
Normal file
101
vendor/github.com/sirupsen/logrus/level.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
ansiReset = "\x1b[0m" // reset attributes
|
||||
ansiRed = "\x1b[31m" // red
|
||||
ansiYellow = "\x1b[33m" // yellow
|
||||
ansiCyan = "\x1b[36m" // cyan
|
||||
ansiDimCyan = "\x1b[2;36m" // dim cyan
|
||||
ansiDimWhite = "\x1b[2;37m" // dim white (light gray)
|
||||
)
|
||||
|
||||
type lvlPrefix struct {
|
||||
full string
|
||||
truncated string
|
||||
padded string
|
||||
}
|
||||
|
||||
func colorize(level Level, s string) string {
|
||||
color := ansiCyan
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
color = ansiDimWhite
|
||||
case DebugLevel:
|
||||
color = ansiDimCyan
|
||||
case WarnLevel:
|
||||
color = ansiYellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
color = ansiRed
|
||||
case InfoLevel:
|
||||
color = ansiCyan
|
||||
}
|
||||
return color + s + ansiReset
|
||||
}
|
||||
|
||||
func formatLevel(level Level, disableTrunc, pad bool, maxLen int) string {
|
||||
upper := strings.ToUpper(level.String())
|
||||
|
||||
if pad && maxLen > len(upper) {
|
||||
upper += strings.Repeat(" ", maxLen-len(upper))
|
||||
}
|
||||
|
||||
if !pad && !disableTrunc && len(upper) > 4 {
|
||||
upper = upper[:4]
|
||||
}
|
||||
|
||||
return colorize(level, upper)
|
||||
}
|
||||
|
||||
var levelPrefixOnce = sync.OnceValues(func() (map[Level]lvlPrefix, lvlPrefix) {
|
||||
var maxLevel Level
|
||||
maxLen := 0
|
||||
for _, lvl := range AllLevels {
|
||||
if lvl > maxLevel {
|
||||
maxLevel = lvl
|
||||
}
|
||||
if l := len(lvl.String()); l > maxLen {
|
||||
maxLen = l
|
||||
}
|
||||
}
|
||||
|
||||
prefix := make(map[Level]lvlPrefix, len(AllLevels))
|
||||
for _, lvl := range AllLevels {
|
||||
prefix[lvl] = lvlPrefix{
|
||||
full: formatLevel(lvl, true, false, maxLen),
|
||||
truncated: formatLevel(lvl, false, false, maxLen),
|
||||
padded: formatLevel(lvl, true, true, maxLen),
|
||||
}
|
||||
}
|
||||
|
||||
unknownLevel := maxLevel + 1
|
||||
unknown := lvlPrefix{
|
||||
full: formatLevel(unknownLevel, true, false, maxLen),
|
||||
truncated: formatLevel(unknownLevel, false, false, maxLen),
|
||||
padded: formatLevel(unknownLevel, true, true, maxLen),
|
||||
}
|
||||
|
||||
return prefix, unknown
|
||||
})
|
||||
|
||||
func levelPrefix(level Level, disableTrunc, pad bool) string {
|
||||
prefix, unknown := levelPrefixOnce()
|
||||
|
||||
p, ok := prefix[level]
|
||||
if !ok {
|
||||
p = unknown
|
||||
}
|
||||
|
||||
switch {
|
||||
case pad:
|
||||
return p.padded
|
||||
case !disableTrunc:
|
||||
return p.truncated
|
||||
default:
|
||||
return p.full
|
||||
}
|
||||
}
|
||||
156
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
156
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
|
|
@ -12,17 +12,19 @@ import (
|
|||
// LogFunction For big messages, it can be more efficient to pass a function
|
||||
// and only call it if the log level is actually enables rather than
|
||||
// generating the log message and then checking if the level is enabled
|
||||
type LogFunction func() []interface{}
|
||||
type LogFunction func() []any
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventurous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
// service, log to StatsD or dump the core on fatal errors.
|
||||
Hooks LevelHooks
|
||||
|
||||
// All log entries pass through the formatter before logged to Out. The
|
||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||
|
|
@ -38,37 +40,44 @@ type Logger struct {
|
|||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged.
|
||||
Level Level
|
||||
|
||||
// Used to sync writing to the log. Locking is enabled by Default
|
||||
mu MutexWrap
|
||||
mu mutexWrap
|
||||
|
||||
// Reusable empty entry
|
||||
entryPool sync.Pool
|
||||
|
||||
// Function to exit the application, defaults to `os.Exit()`
|
||||
ExitFunc exitFunc
|
||||
ExitFunc func(int)
|
||||
|
||||
// The buffer pool used to format the log. If it is nil, the default global
|
||||
// buffer pool will be used.
|
||||
BufferPool BufferPool
|
||||
}
|
||||
|
||||
type exitFunc func(int)
|
||||
// MutexWrap is the mutex implementation used by [Logger].
|
||||
//
|
||||
// Deprecated: MutexWrap is an implementation detail of Logger and should not be used directly.
|
||||
type MutexWrap = mutexWrap
|
||||
|
||||
type MutexWrap struct {
|
||||
type mutexWrap struct {
|
||||
lock sync.Mutex
|
||||
disabled bool
|
||||
}
|
||||
|
||||
func (mw *MutexWrap) Lock() {
|
||||
func (mw *mutexWrap) Lock() {
|
||||
if !mw.disabled {
|
||||
mw.lock.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
func (mw *MutexWrap) Unlock() {
|
||||
func (mw *mutexWrap) Unlock() {
|
||||
if !mw.disabled {
|
||||
mw.lock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (mw *MutexWrap) Disable() {
|
||||
func (mw *mutexWrap) Disable() {
|
||||
mw.disabled = true
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +113,7 @@ func (logger *Logger) newEntry() *Entry {
|
|||
}
|
||||
|
||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||
entry.Data = map[string]interface{}{}
|
||||
entry.Data = map[string]any{}
|
||||
logger.entryPool.Put(entry)
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +121,7 @@ func (logger *Logger) releaseEntry(entry *Entry) {
|
|||
// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
|
||||
// this new returned entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
func (logger *Logger) WithField(key string, value any) *Entry {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
return entry.WithField(key, value)
|
||||
|
|
@ -148,7 +157,12 @@ func (logger *Logger) WithTime(t time.Time) *Entry {
|
|||
return entry.WithTime(t)
|
||||
}
|
||||
|
||||
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
||||
// Logf logs a formatted message at the specified level.
|
||||
//
|
||||
// Using Logf with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Logf treats the level as logging severity only;
|
||||
// use [Logger.Panicf] or [Logger.Fatalf] when those side effects are desired.
|
||||
func (logger *Logger) Logf(level Level, format string, args ...any) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Logf(level, format, args...)
|
||||
|
|
@ -156,49 +170,55 @@ func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
||||
func (logger *Logger) Tracef(format string, args ...any) {
|
||||
logger.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Debugf(format string, args ...any) {
|
||||
logger.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
func (logger *Logger) Infof(format string, args ...any) {
|
||||
logger.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Printf(format string, args ...any) {
|
||||
entry := logger.newEntry()
|
||||
entry.Printf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Warnf(format string, args ...any) {
|
||||
logger.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Warningf(format string, args ...any) {
|
||||
logger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Errorf(format string, args ...any) {
|
||||
logger.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
func (logger *Logger) Fatalf(format string, args ...any) {
|
||||
logger.Logf(FatalLevel, format, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
logger.Logf(PanicLevel, format, args...)
|
||||
func (logger *Logger) Panicf(format string, args ...any) {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
entry.Panicf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Log will log a message at the level given as parameter.
|
||||
// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
|
||||
// For this behaviour Logger.Panic or Logger.Fatal should be used instead.
|
||||
func (logger *Logger) Log(level Level, args ...interface{}) {
|
||||
// Log logs a message at the specified level.
|
||||
//
|
||||
// Using Log with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Log treats the level as logging severity only;
|
||||
// use [Logger.Panic] or [Logger.Fatal] when those side effects are desired.
|
||||
func (logger *Logger) Log(level Level, args ...any) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Log(level, args...)
|
||||
|
|
@ -206,6 +226,11 @@ func (logger *Logger) Log(level Level, args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// LogFn logs a message returned by fn at the specified level.
|
||||
//
|
||||
// Using LogFn with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. LogFn treats the level as logging severity only;
|
||||
// use [Logger.PanicFn] or [Logger.FatalFn] when those side effects are desired.
|
||||
func (logger *Logger) LogFn(level Level, fn LogFunction) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
|
|
@ -214,43 +239,47 @@ func (logger *Logger) LogFn(level Level, fn LogFunction) {
|
|||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Trace(args ...interface{}) {
|
||||
func (logger *Logger) Trace(args ...any) {
|
||||
logger.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
func (logger *Logger) Debug(args ...any) {
|
||||
logger.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
func (logger *Logger) Info(args ...any) {
|
||||
logger.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
func (logger *Logger) Print(args ...any) {
|
||||
entry := logger.newEntry()
|
||||
entry.Print(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
func (logger *Logger) Warn(args ...any) {
|
||||
logger.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
func (logger *Logger) Warning(args ...any) {
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
func (logger *Logger) Error(args ...any) {
|
||||
logger.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
func (logger *Logger) Fatal(args ...any) {
|
||||
logger.Log(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
logger.Log(PanicLevel, args...)
|
||||
func (logger *Logger) Panic(args ...any) {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
entry.Panic(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) TraceFn(fn LogFunction) {
|
||||
|
|
@ -289,10 +318,19 @@ func (logger *Logger) FatalFn(fn LogFunction) {
|
|||
}
|
||||
|
||||
func (logger *Logger) PanicFn(fn LogFunction) {
|
||||
logger.LogFn(PanicLevel, fn)
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
entry.Panic(fn()...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
||||
// Logln logs a message at the specified level with Println-style spacing.
|
||||
//
|
||||
// Using Logln with [PanicLevel] or [FatalLevel] intentionally does not
|
||||
// trigger a panic or exit. Logln treats the level as logging severity only;
|
||||
// use [Logger.Panicln] or [Logger.Fatalln] when those side effects are desired.
|
||||
func (logger *Logger) Logln(level Level, args ...any) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Logln(level, args...)
|
||||
|
|
@ -300,43 +338,47 @@ func (logger *Logger) Logln(level Level, args ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Traceln(args ...interface{}) {
|
||||
func (logger *Logger) Traceln(args ...any) {
|
||||
logger.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
func (logger *Logger) Debugln(args ...any) {
|
||||
logger.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
func (logger *Logger) Infoln(args ...any) {
|
||||
logger.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
func (logger *Logger) Println(args ...any) {
|
||||
entry := logger.newEntry()
|
||||
entry.Println(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
func (logger *Logger) Warnln(args ...any) {
|
||||
logger.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
func (logger *Logger) Warningln(args ...any) {
|
||||
logger.Warnln(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
func (logger *Logger) Errorln(args ...any) {
|
||||
logger.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
func (logger *Logger) Fatalln(args ...any) {
|
||||
logger.Logln(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
logger.Logln(PanicLevel, args...)
|
||||
func (logger *Logger) Panicln(args ...any) {
|
||||
if logger.IsLevelEnabled(PanicLevel) {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
entry.Panicln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Exit(code int) {
|
||||
|
|
@ -375,7 +417,22 @@ func (logger *Logger) AddHook(hook Hook) {
|
|||
logger.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
||||
// hooksForLevel returns a snapshot of the hooks registered for the given level.
|
||||
// The returned slice is a shallow copy and may be used without holding logger.mu.
|
||||
func (logger *Logger) hooksForLevel(level Level) []Hook {
|
||||
logger.mu.Lock()
|
||||
hooks := logger.Hooks[level]
|
||||
if len(hooks) == 0 {
|
||||
logger.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
out := make([]Hook, len(hooks))
|
||||
copy(out, hooks)
|
||||
logger.mu.Unlock()
|
||||
return out
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if logging for the given level is enabled.
|
||||
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
||||
return logger.level() >= level
|
||||
}
|
||||
|
|
@ -394,6 +451,7 @@ func (logger *Logger) SetOutput(output io.Writer) {
|
|||
logger.Out = output
|
||||
}
|
||||
|
||||
// SetReportCaller sets whether the caller stack frame must be logged.
|
||||
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
|
|
@ -403,9 +461,9 @@ func (logger *Logger) SetReportCaller(reportCaller bool) {
|
|||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
oldHooks := logger.Hooks
|
||||
logger.Hooks = hooks
|
||||
logger.mu.Unlock()
|
||||
return oldHooks
|
||||
}
|
||||
|
||||
|
|
|
|||
221
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
221
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
|
|
@ -1,13 +1,13 @@
|
|||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Fields type, used to pass to [WithFields].
|
||||
type Fields map[string]interface{}
|
||||
type Fields map[string]any
|
||||
|
||||
// Level type
|
||||
//
|
||||
|
|
@ -16,39 +16,56 @@ type Level uint32
|
|||
|
||||
// Convert the Level to a string. E.g. [PanicLevel] becomes "panic".
|
||||
func (level Level) String() string {
|
||||
if b, err := level.MarshalText(); err == nil {
|
||||
return string(b)
|
||||
} else {
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
return "trace"
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
return FatalLevel, nil
|
||||
case "error":
|
||||
return ErrorLevel, nil
|
||||
case "warn", "warning":
|
||||
return WarnLevel, nil
|
||||
case "info":
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
case "trace":
|
||||
return TraceLevel, nil
|
||||
}
|
||||
return parseLevel([]byte(lvl))
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
func parseLevel(b []byte) (Level, error) {
|
||||
switch {
|
||||
case bytes.EqualFold(b, []byte("panic")):
|
||||
return PanicLevel, nil
|
||||
case bytes.EqualFold(b, []byte("fatal")):
|
||||
return FatalLevel, nil
|
||||
case bytes.EqualFold(b, []byte("error")):
|
||||
return ErrorLevel, nil
|
||||
case bytes.EqualFold(b, []byte("warn")),
|
||||
bytes.EqualFold(b, []byte("warning")):
|
||||
return WarnLevel, nil
|
||||
case bytes.EqualFold(b, []byte("info")):
|
||||
return InfoLevel, nil
|
||||
case bytes.EqualFold(b, []byte("debug")):
|
||||
return DebugLevel, nil
|
||||
case bytes.EqualFold(b, []byte("trace")):
|
||||
return TraceLevel, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("not a valid logrus Level: %q", b)
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (level *Level) UnmarshalText(text []byte) error {
|
||||
l, err := ParseLevel(string(text))
|
||||
l, err := parseLevel(text)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -60,23 +77,11 @@ func (level *Level) UnmarshalText(text []byte) error {
|
|||
|
||||
func (level Level) MarshalText() ([]byte, error) {
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
return []byte("trace"), nil
|
||||
case DebugLevel:
|
||||
return []byte("debug"), nil
|
||||
case InfoLevel:
|
||||
return []byte("info"), nil
|
||||
case WarnLevel:
|
||||
return []byte("warning"), nil
|
||||
case ErrorLevel:
|
||||
return []byte("error"), nil
|
||||
case FatalLevel:
|
||||
return []byte("fatal"), nil
|
||||
case PanicLevel:
|
||||
return []byte("panic"), nil
|
||||
case TraceLevel, DebugLevel, InfoLevel, WarnLevel, ErrorLevel, FatalLevel, PanicLevel:
|
||||
return []byte(level.String()), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("not a valid logrus level %d", level)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("not a valid logrus level %d", level)
|
||||
}
|
||||
|
||||
// AllLevels exposing all logging levels.
|
||||
|
|
@ -91,7 +96,7 @@ var AllLevels = []Level{
|
|||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
// on your instance of logger, obtained with [logrus.New].
|
||||
const (
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
|
|
@ -113,78 +118,110 @@ const (
|
|||
TraceLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
// Compile-time interface assertions.
|
||||
var (
|
||||
_ StdLogger = &log.Logger{}
|
||||
_ StdLogger = &Entry{}
|
||||
_ StdLogger = &Logger{}
|
||||
_ StdLogger = (*log.Logger)(nil)
|
||||
_ StdLogger = (*Entry)(nil)
|
||||
_ StdLogger = (*Logger)(nil)
|
||||
|
||||
_ FieldLogger = (*Logger)(nil)
|
||||
_ FieldLogger = (*Entry)(nil)
|
||||
_ FieldLogger = Ext1FieldLogger(nil)
|
||||
|
||||
_ DebugLogger = (*Logger)(nil)
|
||||
_ InfoLogger = (*Logger)(nil)
|
||||
_ WarnLogger = (*Logger)(nil)
|
||||
_ ErrorLogger = (*Logger)(nil)
|
||||
_ TraceLogger = (*Logger)(nil)
|
||||
|
||||
_ DebugLogger = (*Entry)(nil)
|
||||
_ InfoLogger = (*Entry)(nil)
|
||||
_ WarnLogger = (*Entry)(nil)
|
||||
_ ErrorLogger = (*Entry)(nil)
|
||||
_ TraceLogger = (*Entry)(nil)
|
||||
|
||||
_ Ext1FieldLogger = (*Logger)(nil)
|
||||
_ Ext1FieldLogger = (*Entry)(nil)
|
||||
)
|
||||
|
||||
// StdLogger is what your logrus-enabled library should take, that way
|
||||
// it'll accept a stdlib logger ([log.Logger]) and a logrus logger.
|
||||
// There's no standard interface, so this is the closest we get, unfortunately.
|
||||
type StdLogger interface {
|
||||
Print(...interface{})
|
||||
Printf(string, ...interface{})
|
||||
Println(...interface{})
|
||||
Print(args ...any)
|
||||
Printf(format string, args ...any)
|
||||
Println(args ...any)
|
||||
|
||||
Fatal(...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
Fatalln(...interface{})
|
||||
Fatal(args ...any)
|
||||
Fatalf(format string, args ...any)
|
||||
Fatalln(args ...any)
|
||||
|
||||
Panic(...interface{})
|
||||
Panicf(string, ...interface{})
|
||||
Panicln(...interface{})
|
||||
Panic(args ...any)
|
||||
Panicf(format string, args ...any)
|
||||
Panicln(args ...any)
|
||||
}
|
||||
|
||||
// FieldLogger extends the [StdLogger] interface, generalizing
|
||||
// the [Entry] and [Logger] types.
|
||||
type FieldLogger interface {
|
||||
WithField(key string, value interface{}) *Entry
|
||||
WithField(key string, value any) *Entry
|
||||
WithFields(fields Fields) *Entry
|
||||
WithError(err error) *Entry
|
||||
|
||||
Debugf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warningf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panicf(format string, args ...interface{})
|
||||
StdLogger
|
||||
DebugLogger
|
||||
InfoLogger
|
||||
WarnLogger
|
||||
ErrorLogger
|
||||
|
||||
Debug(args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Print(args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warning(args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Panic(args ...interface{})
|
||||
// Legacy warning aliases. These are kept on FieldLogger for backwards
|
||||
// compatibility, but are intentionally omitted from [WarnLogger].
|
||||
|
||||
Debugln(args ...interface{})
|
||||
Infoln(args ...interface{})
|
||||
Println(args ...interface{})
|
||||
Warnln(args ...interface{})
|
||||
Warningln(args ...interface{})
|
||||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
|
||||
// IsDebugEnabled() bool
|
||||
// IsInfoEnabled() bool
|
||||
// IsWarnEnabled() bool
|
||||
// IsErrorEnabled() bool
|
||||
// IsFatalEnabled() bool
|
||||
// IsPanicEnabled() bool
|
||||
Warning(args ...any)
|
||||
Warningf(format string, args ...any)
|
||||
Warningln(args ...any)
|
||||
}
|
||||
|
||||
// Ext1FieldLogger (the first extension to [FieldLogger]) is superfluous, it is
|
||||
// here for consistency. Do not use. Use [FieldLogger], [Logger] or [Entry]
|
||||
// instead.
|
||||
// DebugLogger provides convenience functions to log messages at level [DebugLevel].
|
||||
type DebugLogger interface {
|
||||
Debug(args ...any)
|
||||
Debugf(format string, args ...any)
|
||||
Debugln(args ...any)
|
||||
}
|
||||
|
||||
// InfoLogger provides convenience functions to log messages at level [InfoLevel].
|
||||
type InfoLogger interface {
|
||||
Info(args ...any)
|
||||
Infof(format string, args ...any)
|
||||
Infoln(args ...any)
|
||||
}
|
||||
|
||||
// WarnLogger provides convenience functions to log messages at level [WarnLevel].
|
||||
type WarnLogger interface {
|
||||
Warn(args ...any)
|
||||
Warnf(format string, args ...any)
|
||||
Warnln(args ...any)
|
||||
}
|
||||
|
||||
// ErrorLogger provides convenience functions to log messages at level [ErrorLevel].
|
||||
type ErrorLogger interface {
|
||||
Error(args ...any)
|
||||
Errorf(format string, args ...any)
|
||||
Errorln(args ...any)
|
||||
}
|
||||
|
||||
// TraceLogger provides convenience functions to log messages at level [TraceLevel].
|
||||
type TraceLogger interface {
|
||||
Trace(args ...any)
|
||||
Tracef(format string, args ...any)
|
||||
Traceln(args ...any)
|
||||
}
|
||||
|
||||
// Ext1FieldLogger is FieldLogger extended with Trace-level methods.
|
||||
//
|
||||
// New code should prefer the smallest applicable interface, such as
|
||||
// [FieldLogger] or [TraceLogger], or use [Logger] or [Entry] directly.
|
||||
type Ext1FieldLogger interface {
|
||||
FieldLogger
|
||||
Tracef(format string, args ...interface{})
|
||||
Trace(args ...interface{})
|
||||
Traceln(args ...interface{})
|
||||
TraceLogger
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
|
|
@ -1,11 +1,7 @@
|
|||
// +build appengine
|
||||
//go:build appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
func checkIfTerminal(_ any) bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
3
vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
3
vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
|
|
@ -1,5 +1,4 @@
|
|||
// +build darwin dragonfly freebsd netbsd openbsd hurd
|
||||
// +build !js
|
||||
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd || hurd) && !tinygo
|
||||
|
||||
package logrus
|
||||
|
||||
|
|
|
|||
7
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
7
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
|
|
@ -1,7 +0,0 @@
|
|||
// +build js
|
||||
|
||||
package logrus
|
||||
|
||||
func isTerminal(fd int) bool {
|
||||
return false
|
||||
}
|
||||
8
vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
generated
vendored
|
|
@ -1,11 +1,7 @@
|
|||
// +build js nacl plan9
|
||||
//go:build js || nacl || plan9 || wasi || wasip1 || tinygo
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
func checkIfTerminal(_ any) bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// +build !appengine,!js,!windows,!nacl,!plan9
|
||||
//go:build !appengine && !js && !windows && !nacl && !plan9 && !wasi && !wasip1 && !tinygo
|
||||
|
||||
package logrus
|
||||
|
||||
|
|
@ -10,7 +10,11 @@ import (
|
|||
func checkIfTerminal(w io.Writer) bool {
|
||||
switch v := w.(type) {
|
||||
case *os.File:
|
||||
return isTerminal(int(v.Fd()))
|
||||
fd := v.Fd()
|
||||
if fd > uintptr(^uint(0)>>1) {
|
||||
return false
|
||||
}
|
||||
return isTerminal(int(fd))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
generated
vendored
|
|
@ -1,3 +1,5 @@
|
|||
//go:build solaris && !tinygo
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
|
|
|
|||
5
vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
5
vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
|
|
@ -1,7 +1,4 @@
|
|||
//go:build (linux || aix || zos) && !js && !wasi
|
||||
// +build linux aix zos
|
||||
// +build !js
|
||||
// +build !wasi
|
||||
//go:build (linux || aix || zos) && !tinygo
|
||||
|
||||
package logrus
|
||||
|
||||
|
|
|
|||
8
vendor/github.com/sirupsen/logrus/terminal_check_wasi.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_check_wasi.go
generated
vendored
|
|
@ -1,8 +0,0 @@
|
|||
//go:build wasi
|
||||
// +build wasi
|
||||
|
||||
package logrus
|
||||
|
||||
func isTerminal(fd int) bool {
|
||||
return false
|
||||
}
|
||||
8
vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go
generated
vendored
8
vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go
generated
vendored
|
|
@ -1,8 +0,0 @@
|
|||
//go:build wasip1
|
||||
// +build wasip1
|
||||
|
||||
package logrus
|
||||
|
||||
func isTerminal(fd int) bool {
|
||||
return false
|
||||
}
|
||||
2
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// +build !appengine,!js,windows
|
||||
//go:build windows && !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
|
|
|
|||
491
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
491
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
|
|
@ -3,30 +3,32 @@ package logrus
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
red = 31
|
||||
yellow = 33
|
||||
blue = 36
|
||||
gray = 37
|
||||
)
|
||||
var baseTimestamp = time.Now()
|
||||
|
||||
var baseTimestamp time.Time
|
||||
|
||||
func init() {
|
||||
baseTimestamp = time.Now()
|
||||
}
|
||||
|
||||
// TextFormatter formats logs into text
|
||||
// TextFormatter formats logs into text.
|
||||
//
|
||||
// Output is logfmt-like: key=value pairs separated by spaces. Fields from
|
||||
// [Entry.Data] are included together with the standard fields derived from the
|
||||
// entry. If a field conflicts with a standard field, it is prefixed with
|
||||
// "fields.". Standard field names can be customized through FieldMap.
|
||||
//
|
||||
// Field keys are written as-is (unquoted and unescaped) in the plain
|
||||
// (non-colored) format; only field values may be quoted depending on
|
||||
// DisableQuote, ForceQuote, QuoteEmptyFields, and the value content.
|
||||
//
|
||||
// When colors are enabled, ANSI escape sequences may be added for presentation.
|
||||
// For fully escaped structured output (including safe keys), use JSONFormatter.
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
|
|
@ -64,7 +66,7 @@ type TextFormatter struct {
|
|||
// be desired.
|
||||
DisableSorting bool
|
||||
|
||||
// The keys sorting function, when uninitialized it uses sort.Strings.
|
||||
// The keys sorting function, when uninitialized it uses slices.Sort.
|
||||
SortingFunc func([]string)
|
||||
|
||||
// Disables the truncation of the level text to 4 characters.
|
||||
|
|
@ -77,16 +79,22 @@ type TextFormatter struct {
|
|||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||
QuoteEmptyFields bool
|
||||
|
||||
// Whether the logger's out is to a terminal
|
||||
isTerminal bool
|
||||
// Whether the logger's out is to a terminal. Don't use this field
|
||||
// directly; use TextFormatter.isTerminal instead.
|
||||
terminal bool
|
||||
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// Mapped keys are written as-is, so they should be safe for plain-text output.
|
||||
//
|
||||
// As an example:
|
||||
//
|
||||
// formatter := &TextFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message"}}
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message",
|
||||
// },
|
||||
// }
|
||||
FieldMap FieldMap
|
||||
|
||||
// CallerPrettyfier can be set by the user to modify the content
|
||||
|
|
@ -96,54 +104,78 @@ type TextFormatter struct {
|
|||
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
||||
|
||||
terminalInitOnce sync.Once
|
||||
|
||||
// The max length of the level text, generated dynamically on init
|
||||
levelTextMaxLength int
|
||||
}
|
||||
|
||||
func (f *TextFormatter) init(entry *Entry) {
|
||||
if entry.Logger != nil {
|
||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||
}
|
||||
// Get the max length of the level text
|
||||
for _, level := range AllLevels {
|
||||
levelTextLength := utf8.RuneCount([]byte(level.String()))
|
||||
if levelTextLength > f.levelTextMaxLength {
|
||||
f.levelTextMaxLength = levelTextLength
|
||||
}
|
||||
func (f *TextFormatter) isTerminal(entry *Entry) bool {
|
||||
if entry == nil || entry.Logger == nil {
|
||||
// Don't run the terminalInitOnce without a logger, otherwise we'd
|
||||
// cache the default (false) forever even if a logger is attached
|
||||
// later.
|
||||
return false
|
||||
}
|
||||
|
||||
f.terminalInitOnce.Do(func() {
|
||||
entry.Logger.mu.Lock()
|
||||
out := entry.Logger.Out
|
||||
entry.Logger.mu.Unlock()
|
||||
|
||||
f.terminal = checkIfTerminal(out)
|
||||
})
|
||||
|
||||
return f.terminal
|
||||
}
|
||||
|
||||
func (f *TextFormatter) isColored() bool {
|
||||
isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
|
||||
|
||||
if f.EnvironmentOverrideColors {
|
||||
switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); {
|
||||
case ok && force != "0":
|
||||
isColored = true
|
||||
case ok && force == "0", os.Getenv("CLICOLOR") == "0":
|
||||
isColored = false
|
||||
}
|
||||
func (f *TextFormatter) isColored(isTerminal bool) bool {
|
||||
if f.DisableColors {
|
||||
return false
|
||||
}
|
||||
|
||||
return isColored && !f.DisableColors
|
||||
colored := f.ForceColors || isTerminal
|
||||
if !f.EnvironmentOverrideColors {
|
||||
return colored
|
||||
}
|
||||
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok {
|
||||
return force != "0"
|
||||
}
|
||||
if os.Getenv("CLICOLOR") == "0" {
|
||||
return false
|
||||
}
|
||||
return colored
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields)
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||
data := make(Fields, len(entry.Data))
|
||||
maps.Copy(data, entry.Data)
|
||||
isColored := f.isColored(f.isTerminal(entry))
|
||||
|
||||
caller := entry.Caller
|
||||
hasCaller := caller != nil
|
||||
prefixFieldClashes(data, f.FieldMap, hasCaller)
|
||||
keys := make([]string, 0, len(data))
|
||||
for k := range data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
var funcVal, fileVal string
|
||||
b := entry.Buffer
|
||||
if b == nil {
|
||||
b = new(bytes.Buffer)
|
||||
}
|
||||
|
||||
fixedKeys := make([]string, 0, 4+len(data))
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, data)
|
||||
} else {
|
||||
f.printPlain(b, entry, keys, data)
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printPlain(b *bytes.Buffer, entry *Entry, keys []string, data Fields) {
|
||||
caller := entry.Caller
|
||||
hasCaller := caller != nil
|
||||
|
||||
fixedKeys := make([]string, 0, len(keys)+defaultFields)
|
||||
if !f.DisableTimestamp {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||
}
|
||||
|
|
@ -154,12 +186,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
if entry.err != "" {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||
}
|
||||
if entry.HasCaller() {
|
||||
|
||||
var funcVal, fileVal string
|
||||
if caller != nil {
|
||||
if f.CallerPrettyfier != nil {
|
||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||
funcVal, fileVal = f.CallerPrettyfier(caller)
|
||||
} else {
|
||||
funcVal = entry.Caller.Function
|
||||
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
funcVal = caller.Function
|
||||
fileVal = caller.File + ":" + strconv.FormatInt(int64(caller.Line), 10)
|
||||
}
|
||||
|
||||
if funcVal != "" {
|
||||
|
|
@ -172,152 +206,108 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
|
||||
if !f.DisableSorting {
|
||||
if f.SortingFunc == nil {
|
||||
sort.Strings(keys)
|
||||
// Default sorting does not sort the "fixed keys";
|
||||
// see https://github.com/sirupsen/logrus/commit/73bc94e60c753099e8bae902f81fbd6e7dd95f26
|
||||
slices.Sort(keys)
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
} else {
|
||||
if !f.isColored() {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
f.SortingFunc(fixedKeys)
|
||||
} else {
|
||||
f.SortingFunc(keys)
|
||||
}
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
f.SortingFunc(fixedKeys)
|
||||
}
|
||||
} else {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
}
|
||||
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
f.terminalInitOnce.Do(func() { f.init(entry) })
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
if f.isColored() {
|
||||
f.printColored(b, entry, keys, data, timestampFormat)
|
||||
} else {
|
||||
|
||||
for _, key := range fixedKeys {
|
||||
var value interface{}
|
||||
switch {
|
||||
case key == f.FieldMap.resolve(FieldKeyTime):
|
||||
value = entry.Time.Format(timestampFormat)
|
||||
case key == f.FieldMap.resolve(FieldKeyLevel):
|
||||
value = entry.Level.String()
|
||||
case key == f.FieldMap.resolve(FieldKeyMsg):
|
||||
value = entry.Message
|
||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||
value = entry.err
|
||||
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||
value = funcVal
|
||||
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||
value = fileVal
|
||||
default:
|
||||
value = data[key]
|
||||
for _, key := range fixedKeys {
|
||||
var value any
|
||||
switch {
|
||||
case key == f.FieldMap.resolve(FieldKeyTime):
|
||||
if f.TimestampFormat == "" {
|
||||
value = entry.Time.Format(defaultTimestampFormat)
|
||||
} else {
|
||||
value = entry.Time.Format(f.TimestampFormat)
|
||||
}
|
||||
f.appendKeyValue(b, key, value)
|
||||
case key == f.FieldMap.resolve(FieldKeyLevel):
|
||||
value = entry.Level.String()
|
||||
case key == f.FieldMap.resolve(FieldKeyMsg):
|
||||
value = entry.Message
|
||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||
value = entry.err
|
||||
case key == f.FieldMap.resolve(FieldKeyFunc) && hasCaller:
|
||||
value = funcVal
|
||||
case key == f.FieldMap.resolve(FieldKeyFile) && hasCaller:
|
||||
value = fileVal
|
||||
default:
|
||||
value = data[key]
|
||||
}
|
||||
f.appendKeyValue(b, key, value)
|
||||
}
|
||||
|
||||
b.WriteByte('\n')
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case DebugLevel, TraceLevel:
|
||||
levelColor = gray
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
levelColor = red
|
||||
case InfoLevel:
|
||||
levelColor = blue
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())
|
||||
if !f.DisableLevelTruncation && !f.PadLevelText {
|
||||
levelText = levelText[0:4]
|
||||
}
|
||||
if f.PadLevelText {
|
||||
// Generates the format string used in the next line, for example "%-6s" or "%-7s".
|
||||
// Based on the max level text length.
|
||||
formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s"
|
||||
// Formats the level text by appending spaces up to the max length, for example:
|
||||
// - "INFO "
|
||||
// - "WARNING"
|
||||
levelText = fmt.Sprintf(formatString, levelText)
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields) {
|
||||
// Remove a single newline if it already exists in the message to keep
|
||||
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||
|
||||
caller := ""
|
||||
if entry.HasCaller() {
|
||||
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
||||
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
|
||||
var callerText string
|
||||
if caller := entry.Caller; caller != nil {
|
||||
var funcVal, fileVal string
|
||||
if f.CallerPrettyfier != nil {
|
||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
||||
funcVal, fileVal = f.CallerPrettyfier(caller)
|
||||
} else {
|
||||
if caller.Function != "" {
|
||||
funcVal = caller.Function + "()"
|
||||
}
|
||||
fileVal = caller.File + ":" + strconv.FormatInt(int64(caller.Line), 10)
|
||||
}
|
||||
|
||||
if fileVal == "" {
|
||||
caller = funcVal
|
||||
callerText = funcVal
|
||||
} else if funcVal == "" {
|
||||
caller = fileVal
|
||||
callerText = fileVal
|
||||
} else {
|
||||
caller = fileVal + " " + funcVal
|
||||
callerText = fileVal + " " + funcVal
|
||||
}
|
||||
}
|
||||
|
||||
levelText := levelPrefix(entry.Level, f.DisableLevelTruncation, f.PadLevelText)
|
||||
switch {
|
||||
case f.DisableTimestamp:
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
||||
_, _ = fmt.Fprintf(b, "%s%s %-44s ", levelText, callerText, entry.Message)
|
||||
case !f.FullTimestamp:
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
|
||||
_, _ = fmt.Fprintf(b, "%s[%04d]%s %-44s ", levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), callerText, entry.Message)
|
||||
default:
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
_, _ = fmt.Fprintf(b, "%s[%s]%s %-44s ", levelText, entry.Time.Format(timestampFormat), callerText, entry.Message)
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
||||
f.appendValue(b, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TextFormatter) needsQuoting(text string) bool {
|
||||
if f.ForceQuote {
|
||||
return true
|
||||
}
|
||||
if f.QuoteEmptyFields && len(text) == 0 {
|
||||
return true
|
||||
}
|
||||
if f.DisableQuote {
|
||||
return false
|
||||
}
|
||||
for _, ch := range text {
|
||||
//nolint:staticcheck // QF1001: could apply De Morgan's law
|
||||
if !((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
|
||||
return true
|
||||
if !f.DisableSorting {
|
||||
if f.SortingFunc == nil {
|
||||
slices.Sort(keys)
|
||||
} else {
|
||||
f.SortingFunc(keys)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
// Keys use the same color as the level-prefix.
|
||||
for _, k := range keys {
|
||||
b.WriteByte(' ')
|
||||
b.WriteString(colorize(entry.Level, k))
|
||||
b.WriteByte('=')
|
||||
f.appendValue(b, data[k])
|
||||
}
|
||||
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||
// appendKeyValue writes key=value. Keys are written verbatim (unquoted/unescaped);
|
||||
// values are subject to quoting/escaping.
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value any) {
|
||||
if b.Len() > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
|
@ -326,15 +316,168 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf
|
|||
f.appendValue(b, value)
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
||||
stringVal, ok := value.(string)
|
||||
if !ok {
|
||||
stringVal = fmt.Sprint(value)
|
||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value any) {
|
||||
// Fast paths.
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
f.appendString(b, v)
|
||||
return
|
||||
case []byte:
|
||||
f.appendBytes(b, v)
|
||||
return
|
||||
case bool:
|
||||
var raw [8]byte
|
||||
f.appendBytes(b, strconv.AppendBool(raw[:0], v))
|
||||
return
|
||||
case error:
|
||||
f.appendError(b, v)
|
||||
return
|
||||
case fmt.Stringer:
|
||||
f.appendStringer(b, v)
|
||||
return
|
||||
}
|
||||
|
||||
if !f.needsQuoting(stringVal) {
|
||||
b.WriteString(stringVal)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%q", stringVal)
|
||||
// Handle common primitives.
|
||||
var raw [64]byte
|
||||
var num []byte
|
||||
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
num = strconv.AppendInt(raw[:0], int64(v), 10)
|
||||
case int8:
|
||||
num = strconv.AppendInt(raw[:0], int64(v), 10)
|
||||
case int16:
|
||||
num = strconv.AppendInt(raw[:0], int64(v), 10)
|
||||
case int32:
|
||||
num = strconv.AppendInt(raw[:0], int64(v), 10)
|
||||
case int64:
|
||||
num = strconv.AppendInt(raw[:0], v, 10)
|
||||
|
||||
case uint:
|
||||
num = strconv.AppendUint(raw[:0], uint64(v), 10)
|
||||
case uint8:
|
||||
num = strconv.AppendUint(raw[:0], uint64(v), 10)
|
||||
case uint16:
|
||||
num = strconv.AppendUint(raw[:0], uint64(v), 10)
|
||||
case uint32:
|
||||
num = strconv.AppendUint(raw[:0], uint64(v), 10)
|
||||
case uint64:
|
||||
num = strconv.AppendUint(raw[:0], v, 10)
|
||||
case uintptr:
|
||||
num = strconv.AppendUint(raw[:0], uint64(v), 10)
|
||||
|
||||
case float32:
|
||||
num = strconv.AppendFloat(raw[:0], float64(v), 'g', -1, 32)
|
||||
case float64:
|
||||
num = strconv.AppendFloat(raw[:0], v, 'g', -1, 64)
|
||||
|
||||
default:
|
||||
f.appendString(b, fmt.Sprint(value))
|
||||
return
|
||||
}
|
||||
|
||||
f.appendNumeric(b, num)
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendString(b *bytes.Buffer, s string) {
|
||||
quote := f.ForceQuote || (f.QuoteEmptyFields && len(s) == 0) || (!f.DisableQuote && needsQuoting(s))
|
||||
if !quote {
|
||||
b.WriteString(s)
|
||||
return
|
||||
}
|
||||
if len(s) == 0 {
|
||||
b.WriteString(`""`)
|
||||
return
|
||||
}
|
||||
|
||||
var tmp [128]byte
|
||||
b.Write(strconv.AppendQuote(tmp[:0], s))
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendBytes(b *bytes.Buffer, bs []byte) {
|
||||
quote := f.ForceQuote || (f.QuoteEmptyFields && len(bs) == 0) || (!f.DisableQuote && needsQuotingBytes(bs))
|
||||
if !quote {
|
||||
b.Write(bs)
|
||||
return
|
||||
}
|
||||
if len(bs) == 0 {
|
||||
b.WriteString(`""`)
|
||||
return
|
||||
}
|
||||
|
||||
var tmp [128]byte
|
||||
b.Write(strconv.AppendQuote(tmp[:0], string(bs)))
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendNumeric(b *bytes.Buffer, out []byte) {
|
||||
if f.ForceQuote {
|
||||
var tmp [128]byte
|
||||
b.Write(strconv.AppendQuote(tmp[:0], string(out)))
|
||||
return
|
||||
}
|
||||
b.Write(out)
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendError(b *bytes.Buffer, v error) {
|
||||
defer f.recoverValue(b, v, "Error")
|
||||
|
||||
f.appendString(b, v.Error())
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendStringer(b *bytes.Buffer, v fmt.Stringer) {
|
||||
defer f.recoverValue(b, v, "String")
|
||||
|
||||
f.appendString(b, v.String())
|
||||
}
|
||||
|
||||
func (f *TextFormatter) recoverValue(b *bytes.Buffer, v any, method string) {
|
||||
if r := recover(); r != nil {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() == reflect.Pointer && rv.IsNil() {
|
||||
f.appendString(b, "<nil>")
|
||||
} else {
|
||||
f.appendString(b, fmt.Sprintf("%%!v(PANIC=%s method: %v)", method, r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// needsQuoting returns true if the string contains any byte that
|
||||
// requires quoting. It returns false when every byte is "safe" according
|
||||
// to isSafeByte.
|
||||
func needsQuoting(s string) bool {
|
||||
// use an index loop (avoid rune decoding).
|
||||
for i := range len(s) {
|
||||
c := s[i]
|
||||
if !isSafeByte(c) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// needsQuotingBytes returns true if the byte slice contains any byte that
|
||||
// requires quoting. It returns false when every byte is "safe" according
|
||||
// to isSafeByte.
|
||||
func needsQuotingBytes(bs []byte) bool {
|
||||
for _, c := range bs {
|
||||
if !isSafeByte(c) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isSafeByte returns true if the byte is allowed unquoted (ASCII and in the allowlist).
|
||||
// It purposely uses byte arithmetic (no runes) for performance.
|
||||
func isSafeByte(ch byte) bool {
|
||||
ok := ch < 0x80 && ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
switch ch {
|
||||
case '-', '.', '_', '/', '@', '^', '+':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
6
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
|
|
@ -30,7 +30,7 @@ func (entry *Entry) Writer() *io.PipeWriter {
|
|||
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
var printFunc func(args ...interface{})
|
||||
printFunc := entry.Print
|
||||
|
||||
// Determine which log function to use based on the specified log level
|
||||
switch level {
|
||||
|
|
@ -48,8 +48,6 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
|||
printFunc = entry.Fatal
|
||||
case PanicLevel:
|
||||
printFunc = entry.Panic
|
||||
default:
|
||||
printFunc = entry.Print
|
||||
}
|
||||
|
||||
// Start a new goroutine to scan the input and write it to the logger using the specified print function.
|
||||
|
|
@ -63,7 +61,7 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
|||
}
|
||||
|
||||
// writerScanner scans the input from the reader and writes it to the logger
|
||||
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
||||
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...any)) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
// Set the buffer size to the maximum token size to avoid buffer overflows
|
||||
|
|
|
|||
28
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
28
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
|
|
@ -84,7 +84,7 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
|
|||
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
|
||||
// EqualErrorf asserts that a function returned a non-nil error (i.e. an error)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -124,7 +124,7 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
|
|||
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Errorf asserts that a function returned an error (i.e. not `nil`).
|
||||
// Errorf asserts that a function returned a non-nil error (ie. an error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// assert.Errorf(t, err, "error message %s", "formatted")
|
||||
|
|
@ -144,8 +144,8 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int
|
|||
return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that the error contains the specified substring.
|
||||
// ErrorContainsf asserts that a function returned a non-nil error (i.e. an
|
||||
// error) and that the error contains the specified substring.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted")
|
||||
|
|
@ -190,10 +190,10 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick
|
|||
// time.Sleep(8*time.Second)
|
||||
// externalValue = true
|
||||
// }()
|
||||
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
|
||||
// assert.EventuallyWithTf(t, func(c *assert.CollectT) {
|
||||
// // add assertions as needed; any assertion failure will fail the current tick
|
||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||
// }, 10*time.Second, 1*time.Second, "error message %s", "formatted")
|
||||
func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -552,7 +552,7 @@ func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool
|
|||
return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
||||
// NoErrorf asserts that a function returned a nil error (ie. no error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if assert.NoErrorf(t, err, "error message %s", "formatted") {
|
||||
|
|
@ -849,7 +849,19 @@ func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time,
|
|||
return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
// YAMLEqf asserts that the first documents in the two YAML strings are equivalent.
|
||||
//
|
||||
// expected := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a second document, it is not evaluated
|
||||
// `
|
||||
// actual := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a subsequent document, it is not evaluated
|
||||
// `
|
||||
// assert.YAMLEqf(t, expected, actual, "error message %s", "formatted")
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
|||
52
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
52
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
|
|
@ -146,7 +146,7 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
|
|||
return Equal(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// EqualError asserts that a function returned an error (i.e. not `nil`)
|
||||
// EqualError asserts that a function returned a non-nil error (i.e. an error)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -158,7 +158,7 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
|
|||
return EqualError(a.t, theError, errString, msgAndArgs...)
|
||||
}
|
||||
|
||||
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
|
||||
// EqualErrorf asserts that a function returned a non-nil error (i.e. an error)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -240,7 +240,7 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
|
|||
return Equalf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
||||
// Error asserts that a function returned a non-nil error (ie. an error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// a.Error(err)
|
||||
|
|
@ -269,8 +269,8 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ..
|
|||
return ErrorAsf(a.t, err, target, msg, args...)
|
||||
}
|
||||
|
||||
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that the error contains the specified substring.
|
||||
// ErrorContains asserts that a function returned a non-nil error (i.e. an
|
||||
// error) and that the error contains the specified substring.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// a.ErrorContains(err, expectedErrorSubString)
|
||||
|
|
@ -281,8 +281,8 @@ func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs .
|
|||
return ErrorContains(a.t, theError, contains, msgAndArgs...)
|
||||
}
|
||||
|
||||
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that the error contains the specified substring.
|
||||
// ErrorContainsf asserts that a function returned a non-nil error (i.e. an
|
||||
// error) and that the error contains the specified substring.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted")
|
||||
|
|
@ -311,7 +311,7 @@ func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...inter
|
|||
return ErrorIsf(a.t, err, target, msg, args...)
|
||||
}
|
||||
|
||||
// Errorf asserts that a function returned an error (i.e. not `nil`).
|
||||
// Errorf asserts that a function returned a non-nil error (ie. an error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// a.Errorf(err, "error message %s", "formatted")
|
||||
|
|
@ -372,10 +372,10 @@ func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor
|
|||
// time.Sleep(8*time.Second)
|
||||
// externalValue = true
|
||||
// }()
|
||||
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
|
||||
// a.EventuallyWithTf(func(c *assert.CollectT) {
|
||||
// // add assertions as needed; any assertion failure will fail the current tick
|
||||
// assert.True(c, externalValue, "expected 'externalValue' to be true")
|
||||
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
|
||||
// }, 10*time.Second, 1*time.Second, "error message %s", "formatted")
|
||||
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -1096,7 +1096,7 @@ func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{})
|
|||
return NoDirExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
// NoError asserts that a function returned a nil error (ie. no error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if a.NoError(err) {
|
||||
|
|
@ -1109,7 +1109,7 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
|||
return NoError(a.t, err, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
||||
// NoErrorf asserts that a function returned a nil error (ie. no error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if a.NoErrorf(err, "error message %s", "formatted") {
|
||||
|
|
@ -1690,7 +1690,19 @@ func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Ti
|
|||
return WithinRangef(a.t, actual, start, end, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
// YAMLEq asserts that the first documents in the two YAML strings are equivalent.
|
||||
//
|
||||
// expected := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a second document, it is not evaluated
|
||||
// `
|
||||
// actual := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a subsequent document, it is not evaluated
|
||||
// `
|
||||
// a.YAMLEq(expected, actual)
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -1698,7 +1710,19 @@ func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interf
|
|||
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
// YAMLEqf asserts that the first documents in the two YAML strings are equivalent.
|
||||
//
|
||||
// expected := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a second document, it is not evaluated
|
||||
// `
|
||||
// actual := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a subsequent document, it is not evaluated
|
||||
// `
|
||||
// a.YAMLEqf(expected, actual, "error message %s", "formatted")
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
|
|||
14
vendor/github.com/stretchr/testify/assert/assertion_order.go
generated
vendored
14
vendor/github.com/stretchr/testify/assert/assertion_order.go
generated
vendored
|
|
@ -9,7 +9,7 @@ import (
|
|||
func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
|
||||
objKind := reflect.TypeOf(object).Kind()
|
||||
if objKind != reflect.Slice && objKind != reflect.Array {
|
||||
return false
|
||||
return Fail(t, fmt.Sprintf("object %T is not an ordered collection", object), msgAndArgs...)
|
||||
}
|
||||
|
||||
objValue := reflect.ValueOf(object)
|
||||
|
|
@ -50,6 +50,9 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareR
|
|||
// assert.IsIncreasing(t, []float{1, 2})
|
||||
// assert.IsIncreasing(t, []string{"a", "b"})
|
||||
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +62,9 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
|
|||
// assert.IsNonIncreasing(t, []float{2, 1})
|
||||
// assert.IsNonIncreasing(t, []string{"b", "a"})
|
||||
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +74,9 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{})
|
|||
// assert.IsDecreasing(t, []float{2, 1})
|
||||
// assert.IsDecreasing(t, []string{"b", "a"})
|
||||
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -77,5 +86,8 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo
|
|||
// assert.IsNonDecreasing(t, []float{1, 2})
|
||||
// assert.IsNonDecreasing(t, []string{"a", "b"})
|
||||
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
|
||||
}
|
||||
|
|
|
|||
145
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
145
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
|
|
@ -17,11 +17,10 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/pmezard/go-difflib/difflib"
|
||||
|
||||
// Wrapper around gopkg.in/yaml.v3
|
||||
"github.com/stretchr/testify/assert/yaml"
|
||||
"github.com/stretchr/testify/internal/difflib"
|
||||
"github.com/stretchr/testify/internal/spew"
|
||||
)
|
||||
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
|
||||
|
|
@ -33,19 +32,19 @@ type TestingT interface {
|
|||
|
||||
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
|
||||
// for table driven tests.
|
||||
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
|
||||
type ComparisonAssertionFunc = func(TestingT, interface{}, interface{}, ...interface{}) bool
|
||||
|
||||
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
|
||||
// for table driven tests.
|
||||
type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
|
||||
type ValueAssertionFunc = func(TestingT, interface{}, ...interface{}) bool
|
||||
|
||||
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
|
||||
// for table driven tests.
|
||||
type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
|
||||
type BoolAssertionFunc = func(TestingT, bool, ...interface{}) bool
|
||||
|
||||
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
|
||||
// for table driven tests.
|
||||
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
|
||||
type ErrorAssertionFunc = func(TestingT, error, ...interface{}) bool
|
||||
|
||||
// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful
|
||||
// for table driven tests.
|
||||
|
|
@ -325,13 +324,15 @@ func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
|
|||
func indentMessageLines(message string, longestLabelLen int) string {
|
||||
outBuf := new(bytes.Buffer)
|
||||
|
||||
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
|
||||
// no need to align first line because it starts at the correct location (after the label)
|
||||
if i != 0 {
|
||||
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
|
||||
outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
|
||||
scanner := bufio.NewScanner(strings.NewReader(message))
|
||||
for firstLine := true; scanner.Scan(); firstLine = false {
|
||||
if !firstLine {
|
||||
fmt.Fprint(outBuf, "\n\t"+strings.Repeat(" ", longestLabelLen+1)+"\t")
|
||||
}
|
||||
outBuf.WriteString(scanner.Text())
|
||||
fmt.Fprint(outBuf, scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return fmt.Sprintf("cannot display message: %s", err)
|
||||
}
|
||||
|
||||
return outBuf.String()
|
||||
|
|
@ -544,9 +545,8 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
|||
if !same {
|
||||
// both are pointers but not the same type & pointing to the same address
|
||||
return Fail(t, fmt.Sprintf("Not same: \n"+
|
||||
"expected: %p %#[1]v\n"+
|
||||
"actual : %p %#[2]v",
|
||||
expected, actual), msgAndArgs...)
|
||||
"expected: %[2]s (%[1]T)(%[1]p)\n"+
|
||||
"actual : %[4]s (%[3]T)(%[3]p)", expected, truncatingFormat("%#v", expected), actual, truncatingFormat("%#v", actual)), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -571,8 +571,8 @@ func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
|
|||
|
||||
if same {
|
||||
return Fail(t, fmt.Sprintf(
|
||||
"Expected and actual point to the same object: %p %#[1]v",
|
||||
expected), msgAndArgs...)
|
||||
"Expected and actual point to the same object: %p %s",
|
||||
expected, truncatingFormat("%#v", expected)), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -604,25 +604,26 @@ func samePointers(first, second interface{}) (same bool, ok bool) {
|
|||
// to a type conversion in the Go grammar.
|
||||
func formatUnequalValues(expected, actual interface{}) (e string, a string) {
|
||||
if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
|
||||
return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
|
||||
fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
|
||||
return fmt.Sprintf("%T(%s)", expected, truncatingFormat("%#v", expected)),
|
||||
fmt.Sprintf("%T(%s)", actual, truncatingFormat("%#v", actual))
|
||||
}
|
||||
switch expected.(type) {
|
||||
case time.Duration:
|
||||
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
|
||||
}
|
||||
return truncatingFormat(expected), truncatingFormat(actual)
|
||||
return truncatingFormat("%#v", expected), truncatingFormat("%#v", actual)
|
||||
}
|
||||
|
||||
// truncatingFormat formats the data and truncates it if it's too long.
|
||||
//
|
||||
// This helps keep formatted error messages lines from exceeding the
|
||||
// bufio.MaxScanTokenSize max line length that the go testing framework imposes.
|
||||
func truncatingFormat(data interface{}) string {
|
||||
value := fmt.Sprintf("%#v", data)
|
||||
max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
|
||||
if len(value) > max {
|
||||
value = value[0:max] + "<... truncated>"
|
||||
func truncatingFormat(format string, data interface{}) string {
|
||||
value := fmt.Sprintf(format, data)
|
||||
// Give us space for two truncated objects and the surrounding sentence.
|
||||
maxMessageSize := bufio.MaxScanTokenSize/2 - 100
|
||||
if len(value) > maxMessageSize {
|
||||
value = value[0:maxMessageSize] + "<... truncated>"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
@ -743,7 +744,7 @@ func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
|||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Expected nil, but got: %s", truncatingFormat("%#v", object)), msgAndArgs...)
|
||||
}
|
||||
|
||||
// isEmpty gets whether the specified object is considered empty or not.
|
||||
|
|
@ -793,7 +794,7 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
|||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
|
||||
Fail(t, fmt.Sprintf("Should be empty, but was %s", truncatingFormat("%v", object)), msgAndArgs...)
|
||||
}
|
||||
|
||||
return pass
|
||||
|
|
@ -836,11 +837,11 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
|
|||
}
|
||||
l, ok := getLen(object)
|
||||
if !ok {
|
||||
return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", truncatingFormat("%v", object)), msgAndArgs...)
|
||||
}
|
||||
|
||||
if l != length {
|
||||
return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%q should have %d item(s), but has %d", truncatingFormat("%v", object), length, l), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -889,7 +890,7 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{
|
|||
}
|
||||
|
||||
if ObjectsAreEqual(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -904,7 +905,7 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte
|
|||
}
|
||||
|
||||
if ObjectsAreEqualValues(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Should not be: %s\n", truncatingFormat("%#v", actual)), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -964,10 +965,10 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
|
|||
|
||||
ok, found := containsElement(s, contains)
|
||||
if !ok {
|
||||
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...)
|
||||
}
|
||||
if !found {
|
||||
return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -986,10 +987,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
|
|||
|
||||
ok, found := containsElement(s, contains)
|
||||
if !ok {
|
||||
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s could not be applied builtin len()", truncatingFormat("%#v", s)), msgAndArgs...)
|
||||
}
|
||||
if found {
|
||||
return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s should not contain %#v", truncatingFormat("%#v", s), contains), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -1031,10 +1032,10 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
|
|||
av := actualMap.MapIndex(k)
|
||||
|
||||
if !av.IsValid() {
|
||||
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
|
||||
}
|
||||
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
|
||||
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s does not contain %s", truncatingFormat("%#v", list), truncatingFormat("%#v", subset)), msgAndArgs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1056,7 +1057,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
|
|||
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
|
||||
}
|
||||
if !found {
|
||||
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s does not contain %#v", truncatingFormat("%#v", list), element), msgAndArgs...)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1082,12 +1083,12 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
|
|||
|
||||
listKind := reflect.TypeOf(list).Kind()
|
||||
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
|
||||
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", list, listKind), msgAndArgs...)
|
||||
}
|
||||
|
||||
subsetKind := reflect.TypeOf(subset).Kind()
|
||||
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
|
||||
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%#v has an unsupported type %s", subset, subsetKind), msgAndArgs...)
|
||||
}
|
||||
|
||||
if subsetKind == reflect.Map && listKind == reflect.Map {
|
||||
|
|
@ -1106,7 +1107,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
|
|||
}
|
||||
}
|
||||
|
||||
return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...)
|
||||
}
|
||||
|
||||
subsetList := reflect.ValueOf(subset)
|
||||
|
|
@ -1121,14 +1122,14 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
|
|||
element := subsetList.Index(i).Interface()
|
||||
ok, found := containsElement(list, element)
|
||||
if !ok {
|
||||
return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
|
||||
}
|
||||
if !found {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("%s is a subset of %s", truncatingFormat("%#v", subset), truncatingFormat("%#v", list)), msgAndArgs...)
|
||||
}
|
||||
|
||||
// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
|
||||
|
|
@ -1343,9 +1344,15 @@ func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs .
|
|||
if !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
panicErr, ok := panicValue.(error)
|
||||
if !ok || panicErr.Error() != errString {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
|
||||
panicErr, isError := panicValue.(error)
|
||||
if !isError || panicErr.Error() != errString {
|
||||
msg := fmt.Sprintf("func %#v should panic with error message:\t%#v\n", f, errString)
|
||||
if isError {
|
||||
msg += fmt.Sprintf("\tError message:\t%#v\n", panicErr.Error())
|
||||
}
|
||||
msg += fmt.Sprintf("\tPanic value:\t%#v\n", panicValue)
|
||||
msg += fmt.Sprintf("\tPanic stack:\t%s\n", panickedStack)
|
||||
return Fail(t, msg, msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -1624,7 +1631,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
|
|||
Errors
|
||||
*/
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
// NoError asserts that a function returned a nil error (ie. no error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// if assert.NoError(t, err) {
|
||||
|
|
@ -1635,13 +1642,13 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
|||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Received unexpected error:\n%s", truncatingFormat("%+v", err)), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
||||
// Error asserts that a function returned a non-nil error (ie. an error).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// assert.Error(t, err)
|
||||
|
|
@ -1656,7 +1663,7 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// EqualError asserts that a function returned an error (i.e. not `nil`)
|
||||
// EqualError asserts that a function returned a non-nil error (i.e. an error)
|
||||
// and that it is equal to the provided error.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -1674,13 +1681,13 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte
|
|||
if expected != actual {
|
||||
return Fail(t, fmt.Sprintf("Error message not equal:\n"+
|
||||
"expected: %q\n"+
|
||||
"actual : %q", expected, actual), msgAndArgs...)
|
||||
"actual : %s", expected, truncatingFormat("%q", actual)), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
|
||||
// and that the error contains the specified substring.
|
||||
// ErrorContains asserts that a function returned a non-nil error (i.e. an
|
||||
// error) and that the error contains the specified substring.
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
// assert.ErrorContains(t, err, expectedErrorSubString)
|
||||
|
|
@ -1694,7 +1701,7 @@ func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...in
|
|||
|
||||
actual := theError.Error()
|
||||
if !strings.Contains(actual, contains) {
|
||||
return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Error %s does not contain %#v", truncatingFormat("%#v", actual), contains), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -1760,7 +1767,7 @@ func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
|||
h.Helper()
|
||||
}
|
||||
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
|
||||
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("Should be zero, but was %s", truncatingFormat("%v", i)), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1874,7 +1881,19 @@ func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{
|
|||
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
// YAMLEq asserts that the first documents in the two YAML strings are equivalent.
|
||||
//
|
||||
// expected := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a second document, it is not evaluated
|
||||
// `
|
||||
// actual := `---
|
||||
// key: value
|
||||
// ---
|
||||
// key: this is a subsequent document, it is not evaluated
|
||||
// `
|
||||
// assert.YAMLEq(t, expected, actual)
|
||||
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -2188,8 +2207,8 @@ func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
|||
chain := buildErrorChainString(err, false)
|
||||
|
||||
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
|
||||
"expected: %q\n"+
|
||||
"in chain: %s", expectedText, chain,
|
||||
"expected: %s\n"+
|
||||
"in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain),
|
||||
), msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -2211,8 +2230,8 @@ func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
|
|||
chain := buildErrorChainString(err, false)
|
||||
|
||||
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||
"found: %q\n"+
|
||||
"in chain: %s", expectedText, chain,
|
||||
"found: %s\n"+
|
||||
"in chain: %s", truncatingFormat("%q", expectedText), truncatingFormat("%s", chain),
|
||||
), msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -2236,7 +2255,7 @@ func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{
|
|||
|
||||
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
|
||||
"expected: %s\n"+
|
||||
"in chain: %s", expectedType, chain,
|
||||
"in chain: %s", expectedType, truncatingFormat("%s", chain),
|
||||
), msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -2254,7 +2273,7 @@ func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interfa
|
|||
|
||||
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
|
||||
"found: %s\n"+
|
||||
"in chain: %s", reflect.TypeOf(target).Elem().String(), chain,
|
||||
"in chain: %s", reflect.TypeOf(target).Elem().String(), truncatingFormat("%s", chain),
|
||||
), msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
|
|||
4
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
4
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
|
|
@ -40,8 +40,8 @@
|
|||
//
|
||||
// # Assertions
|
||||
//
|
||||
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
|
||||
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
|
||||
// Assertions allow you to easily write test code, and are global funcs in the assert package.
|
||||
// All assertion functions take, as the first argument, the [*testing.T] object provided by the
|
||||
// testing framework. This allows the assertion funcs to write the failings and other details to
|
||||
// the correct place.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -8,11 +8,14 @@
|
|||
//
|
||||
// - unified_diff
|
||||
//
|
||||
// - context_diff
|
||||
//
|
||||
// Getting unified diffs was the main goal of the port. Keep in mind this code
|
||||
// is mostly suitable to output text differences in a human friendly way, there
|
||||
// are no guarantees generated diffs are consumable by patch(1).
|
||||
//
|
||||
// This package was adopted from [github.com/pmezard/go-difflib] which
|
||||
// is no longer maintained.
|
||||
//
|
||||
// [github.com/pmezard/go-difflib]: https://github.com/pmezard/go-difflib
|
||||
package difflib
|
||||
|
||||
import (
|
||||
|
|
@ -37,13 +40,6 @@ func max(a, b int) int {
|
|||
return b
|
||||
}
|
||||
|
||||
func calculateRatio(matches, length int) float64 {
|
||||
if length > 0 {
|
||||
return 2.0 * float64(matches) / float64(length)
|
||||
}
|
||||
return 1.0
|
||||
}
|
||||
|
||||
type Match struct {
|
||||
A int
|
||||
B int
|
||||
|
|
@ -103,14 +99,6 @@ func NewMatcher(a, b []string) *SequenceMatcher {
|
|||
return &m
|
||||
}
|
||||
|
||||
func NewMatcherWithJunk(a, b []string, autoJunk bool,
|
||||
isJunk func(string) bool) *SequenceMatcher {
|
||||
|
||||
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
|
||||
m.SetSeqs(a, b)
|
||||
return &m
|
||||
}
|
||||
|
||||
// Set two sequences to be compared.
|
||||
func (m *SequenceMatcher) SetSeqs(a, b []string) {
|
||||
m.SetSeq1(a)
|
||||
|
|
@ -199,12 +187,15 @@ func (m *SequenceMatcher) isBJunk(s string) bool {
|
|||
// If IsJunk is not defined:
|
||||
//
|
||||
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
|
||||
// alo <= i <= i+k <= ahi
|
||||
// blo <= j <= j+k <= bhi
|
||||
//
|
||||
// alo <= i <= i+k <= ahi
|
||||
// blo <= j <= j+k <= bhi
|
||||
//
|
||||
// and for all (i',j',k') meeting those conditions,
|
||||
// k >= k'
|
||||
// i <= i'
|
||||
// and if i == i', j <= j'
|
||||
//
|
||||
// k >= k'
|
||||
// i <= i'
|
||||
// and if i == i', j <= j'
|
||||
//
|
||||
// In other words, of all maximal matching blocks, return one that
|
||||
// starts earliest in a, and of all those maximal matching blocks that
|
||||
|
|
@ -451,66 +442,6 @@ func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
|
|||
return groups
|
||||
}
|
||||
|
||||
// Return a measure of the sequences' similarity (float in [0,1]).
|
||||
//
|
||||
// Where T is the total number of elements in both sequences, and
|
||||
// M is the number of matches, this is 2.0*M / T.
|
||||
// Note that this is 1 if the sequences are identical, and 0 if
|
||||
// they have nothing in common.
|
||||
//
|
||||
// .Ratio() is expensive to compute if you haven't already computed
|
||||
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
|
||||
// want to try .QuickRatio() or .RealQuickRation() first to get an
|
||||
// upper bound.
|
||||
func (m *SequenceMatcher) Ratio() float64 {
|
||||
matches := 0
|
||||
for _, m := range m.GetMatchingBlocks() {
|
||||
matches += m.Size
|
||||
}
|
||||
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||
}
|
||||
|
||||
// Return an upper bound on ratio() relatively quickly.
|
||||
//
|
||||
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||
// is faster to compute.
|
||||
func (m *SequenceMatcher) QuickRatio() float64 {
|
||||
// viewing a and b as multisets, set matches to the cardinality
|
||||
// of their intersection; this counts the number of matches
|
||||
// without regard to order, so is clearly an upper bound
|
||||
if m.fullBCount == nil {
|
||||
m.fullBCount = map[string]int{}
|
||||
for _, s := range m.b {
|
||||
m.fullBCount[s] = m.fullBCount[s] + 1
|
||||
}
|
||||
}
|
||||
|
||||
// avail[x] is the number of times x appears in 'b' less the
|
||||
// number of times we've seen it in 'a' so far ... kinda
|
||||
avail := map[string]int{}
|
||||
matches := 0
|
||||
for _, s := range m.a {
|
||||
n, ok := avail[s]
|
||||
if !ok {
|
||||
n = m.fullBCount[s]
|
||||
}
|
||||
avail[s] = n - 1
|
||||
if n > 0 {
|
||||
matches += 1
|
||||
}
|
||||
}
|
||||
return calculateRatio(matches, len(m.a)+len(m.b))
|
||||
}
|
||||
|
||||
// Return an upper bound on ratio() very quickly.
|
||||
//
|
||||
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
||||
// is faster to compute than either .Ratio() or .QuickRatio().
|
||||
func (m *SequenceMatcher) RealQuickRatio() float64 {
|
||||
la, lb := len(m.a), len(m.b)
|
||||
return calculateRatio(min(la, lb), la+lb)
|
||||
}
|
||||
|
||||
// Convert range to the "ed" format
|
||||
func formatRangeUnified(start, stop int) string {
|
||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
||||
|
|
@ -652,117 +583,6 @@ func formatRangeContext(start, stop int) string {
|
|||
return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
|
||||
}
|
||||
|
||||
type ContextDiff UnifiedDiff
|
||||
|
||||
// Compare two sequences of lines; generate the delta as a context diff.
|
||||
//
|
||||
// Context diffs are a compact way of showing line changes and a few
|
||||
// lines of context. The number of context lines is set by diff.Context
|
||||
// which defaults to three.
|
||||
//
|
||||
// By default, the diff control lines (those with *** or ---) are
|
||||
// created with a trailing newline.
|
||||
//
|
||||
// For inputs that do not have trailing newlines, set the diff.Eol
|
||||
// argument to "" so that the output will be uniformly newline free.
|
||||
//
|
||||
// The context diff format normally has a header for filenames and
|
||||
// modification times. Any or all of these may be specified using
|
||||
// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
|
||||
// The modification times are normally expressed in the ISO 8601 format.
|
||||
// If not specified, the strings default to blanks.
|
||||
func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
||||
buf := bufio.NewWriter(writer)
|
||||
defer buf.Flush()
|
||||
var diffErr error
|
||||
wf := func(format string, args ...interface{}) {
|
||||
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
||||
if diffErr == nil && err != nil {
|
||||
diffErr = err
|
||||
}
|
||||
}
|
||||
ws := func(s string) {
|
||||
_, err := buf.WriteString(s)
|
||||
if diffErr == nil && err != nil {
|
||||
diffErr = err
|
||||
}
|
||||
}
|
||||
|
||||
if len(diff.Eol) == 0 {
|
||||
diff.Eol = "\n"
|
||||
}
|
||||
|
||||
prefix := map[byte]string{
|
||||
'i': "+ ",
|
||||
'd': "- ",
|
||||
'r': "! ",
|
||||
'e': " ",
|
||||
}
|
||||
|
||||
started := false
|
||||
m := NewMatcher(diff.A, diff.B)
|
||||
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
||||
if !started {
|
||||
started = true
|
||||
fromDate := ""
|
||||
if len(diff.FromDate) > 0 {
|
||||
fromDate = "\t" + diff.FromDate
|
||||
}
|
||||
toDate := ""
|
||||
if len(diff.ToDate) > 0 {
|
||||
toDate = "\t" + diff.ToDate
|
||||
}
|
||||
if diff.FromFile != "" || diff.ToFile != "" {
|
||||
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
||||
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
||||
}
|
||||
}
|
||||
|
||||
first, last := g[0], g[len(g)-1]
|
||||
ws("***************" + diff.Eol)
|
||||
|
||||
range1 := formatRangeContext(first.I1, last.I2)
|
||||
wf("*** %s ****%s", range1, diff.Eol)
|
||||
for _, c := range g {
|
||||
if c.Tag == 'r' || c.Tag == 'd' {
|
||||
for _, cc := range g {
|
||||
if cc.Tag == 'i' {
|
||||
continue
|
||||
}
|
||||
for _, line := range diff.A[cc.I1:cc.I2] {
|
||||
ws(prefix[cc.Tag] + line)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
range2 := formatRangeContext(first.J1, last.J2)
|
||||
wf("--- %s ----%s", range2, diff.Eol)
|
||||
for _, c := range g {
|
||||
if c.Tag == 'r' || c.Tag == 'i' {
|
||||
for _, cc := range g {
|
||||
if cc.Tag == 'd' {
|
||||
continue
|
||||
}
|
||||
for _, line := range diff.B[cc.J1:cc.J2] {
|
||||
ws(prefix[cc.Tag] + line)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return diffErr
|
||||
}
|
||||
|
||||
// Like WriteContextDiff but returns the diff a string.
|
||||
func GetContextDiffString(diff ContextDiff) (string, error) {
|
||||
w := &bytes.Buffer{}
|
||||
err := WriteContextDiff(w, diff)
|
||||
return string(w.Bytes()), err
|
||||
}
|
||||
|
||||
// Split a string on "\n" while preserving them. The output can be used
|
||||
// as input for UnifiedDiff and ContextDiff structures.
|
||||
func SplitLines(s string) []string {
|
||||
12
vendor/github.com/stretchr/testify/internal/spew/README.md
generated
vendored
Normal file
12
vendor/github.com/stretchr/testify/internal/spew/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
go-spew
|
||||
=======
|
||||
|
||||
[](http://copyfree.org)
|
||||
|
||||
Go-spew implements a deep pretty printer for Go data structures to aid in
|
||||
debugging. A comprehensive suite of tests with 100% test coverage is provided
|
||||
to ensure proper functionality.
|
||||
|
||||
## License
|
||||
|
||||
Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
// tag is deprecated and thus should not be used.
|
||||
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||
//go:build !js && !appengine && !safe && !disableunsafe && go1.4
|
||||
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||
|
||||
package spew
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
//go:build js || appengine || safe || disableunsafe || !go1.4
|
||||
// +build js appengine safe disableunsafe !go1.4
|
||||
|
||||
package spew
|
||||
|
|
@ -254,15 +254,15 @@ pointer addresses used to indirect to the final value. It provides the
|
|||
following features over the built-in printing facilities provided by the fmt
|
||||
package:
|
||||
|
||||
* Pointers are dereferenced and followed
|
||||
* Circular data structures are detected and handled properly
|
||||
* Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
* Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output
|
||||
- Pointers are dereferenced and followed
|
||||
- Circular data structures are detected and handled properly
|
||||
- Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
- Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
- Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output
|
||||
|
||||
The configuration options are controlled by modifying the public members
|
||||
of c. See ConfigState for options documentation.
|
||||
|
|
@ -295,12 +295,12 @@ func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{})
|
|||
|
||||
// NewDefaultConfig returns a ConfigState with the following default settings.
|
||||
//
|
||||
// Indent: " "
|
||||
// MaxDepth: 0
|
||||
// DisableMethods: false
|
||||
// DisablePointerMethods: false
|
||||
// ContinueOnMethod: false
|
||||
// SortKeys: false
|
||||
// Indent: " "
|
||||
// MaxDepth: 0
|
||||
// DisableMethods: false
|
||||
// DisablePointerMethods: false
|
||||
// ContinueOnMethod: false
|
||||
// SortKeys: false
|
||||
func NewDefaultConfig() *ConfigState {
|
||||
return &ConfigState{Indent: " "}
|
||||
}
|
||||
|
|
@ -21,35 +21,36 @@ debugging.
|
|||
A quick overview of the additional features spew provides over the built-in
|
||||
printing facilities for Go data types are as follows:
|
||||
|
||||
* Pointers are dereferenced and followed
|
||||
* Circular data structures are detected and handled properly
|
||||
* Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
* Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output (only when using
|
||||
Dump style)
|
||||
- Pointers are dereferenced and followed
|
||||
- Circular data structures are detected and handled properly
|
||||
- Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
- Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
- Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output (only when using
|
||||
Dump style)
|
||||
|
||||
There are two different approaches spew allows for dumping Go data structures:
|
||||
|
||||
* Dump style which prints with newlines, customizable indentation,
|
||||
and additional debug information such as types and all pointer addresses
|
||||
used to indirect to the final value
|
||||
* A custom Formatter interface that integrates cleanly with the standard fmt
|
||||
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
||||
similar to the default %v while providing the additional functionality
|
||||
outlined above and passing unsupported format verbs such as %x and %q
|
||||
along to fmt
|
||||
- Dump style which prints with newlines, customizable indentation,
|
||||
and additional debug information such as types and all pointer addresses
|
||||
used to indirect to the final value
|
||||
- A custom Formatter interface that integrates cleanly with the standard fmt
|
||||
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
||||
similar to the default %v while providing the additional functionality
|
||||
outlined above and passing unsupported format verbs such as %x and %q
|
||||
along to fmt
|
||||
|
||||
Quick Start
|
||||
# Quick Start
|
||||
|
||||
This section demonstrates how to quickly get started with spew. See the
|
||||
sections below for further details on formatting and configuration options.
|
||||
|
||||
To dump a variable with full newlines, indentation, type, and pointer
|
||||
information use Dump, Fdump, or Sdump:
|
||||
|
||||
spew.Dump(myVar1, myVar2, ...)
|
||||
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
||||
str := spew.Sdump(myVar1, myVar2, ...)
|
||||
|
|
@ -58,12 +59,13 @@ Alternatively, if you would prefer to use format strings with a compacted inline
|
|||
printing style, use the convenience wrappers Printf, Fprintf, etc with
|
||||
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
|
||||
%#+v (adds types and pointer addresses):
|
||||
|
||||
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
||||
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
||||
|
||||
Configuration Options
|
||||
# Configuration Options
|
||||
|
||||
Configuration of spew is handled by fields in the ConfigState type. For
|
||||
convenience, all of the top-level functions use a global state available
|
||||
|
|
@ -74,51 +76,52 @@ equivalent to the top-level functions. This allows concurrent configuration
|
|||
options. See the ConfigState documentation for more details.
|
||||
|
||||
The following configuration options are available:
|
||||
* Indent
|
||||
String to use for each indentation level for Dump functions.
|
||||
It is a single space by default. A popular alternative is "\t".
|
||||
|
||||
* MaxDepth
|
||||
Maximum number of levels to descend into nested data structures.
|
||||
There is no limit by default.
|
||||
- Indent
|
||||
String to use for each indentation level for Dump functions.
|
||||
It is a single space by default. A popular alternative is "\t".
|
||||
|
||||
* DisableMethods
|
||||
Disables invocation of error and Stringer interface methods.
|
||||
Method invocation is enabled by default.
|
||||
- MaxDepth
|
||||
Maximum number of levels to descend into nested data structures.
|
||||
There is no limit by default.
|
||||
|
||||
* DisablePointerMethods
|
||||
Disables invocation of error and Stringer interface methods on types
|
||||
which only accept pointer receivers from non-pointer variables.
|
||||
Pointer method invocation is enabled by default.
|
||||
- DisableMethods
|
||||
Disables invocation of error and Stringer interface methods.
|
||||
Method invocation is enabled by default.
|
||||
|
||||
* DisablePointerAddresses
|
||||
DisablePointerAddresses specifies whether to disable the printing of
|
||||
pointer addresses. This is useful when diffing data structures in tests.
|
||||
- DisablePointerMethods
|
||||
Disables invocation of error and Stringer interface methods on types
|
||||
which only accept pointer receivers from non-pointer variables.
|
||||
Pointer method invocation is enabled by default.
|
||||
|
||||
* DisableCapacities
|
||||
DisableCapacities specifies whether to disable the printing of
|
||||
capacities for arrays, slices, maps and channels. This is useful when
|
||||
diffing data structures in tests.
|
||||
- DisablePointerAddresses
|
||||
DisablePointerAddresses specifies whether to disable the printing of
|
||||
pointer addresses. This is useful when diffing data structures in tests.
|
||||
|
||||
* ContinueOnMethod
|
||||
Enables recursion into types after invoking error and Stringer interface
|
||||
methods. Recursion after method invocation is disabled by default.
|
||||
- DisableCapacities
|
||||
DisableCapacities specifies whether to disable the printing of
|
||||
capacities for arrays, slices, maps and channels. This is useful when
|
||||
diffing data structures in tests.
|
||||
|
||||
* SortKeys
|
||||
Specifies map keys should be sorted before being printed. Use
|
||||
this to have a more deterministic, diffable output. Note that
|
||||
only native types (bool, int, uint, floats, uintptr and string)
|
||||
and types which implement error or Stringer interfaces are
|
||||
supported with other types sorted according to the
|
||||
reflect.Value.String() output which guarantees display
|
||||
stability. Natural map order is used by default.
|
||||
- ContinueOnMethod
|
||||
Enables recursion into types after invoking error and Stringer interface
|
||||
methods. Recursion after method invocation is disabled by default.
|
||||
|
||||
* SpewKeys
|
||||
Specifies that, as a last resort attempt, map keys should be
|
||||
spewed to strings and sorted by those strings. This is only
|
||||
considered if SortKeys is true.
|
||||
- SortKeys
|
||||
Specifies map keys should be sorted before being printed. Use
|
||||
this to have a more deterministic, diffable output. Note that
|
||||
only native types (bool, int, uint, floats, uintptr and string)
|
||||
and types which implement error or Stringer interfaces are
|
||||
supported with other types sorted according to the
|
||||
reflect.Value.String() output which guarantees display
|
||||
stability. Natural map order is used by default.
|
||||
|
||||
Dump Usage
|
||||
- SpewKeys
|
||||
Specifies that, as a last resort attempt, map keys should be
|
||||
spewed to strings and sorted by those strings. This is only
|
||||
considered if SortKeys is true.
|
||||
|
||||
# Dump Usage
|
||||
|
||||
Simply call spew.Dump with a list of variables you want to dump:
|
||||
|
||||
|
|
@ -133,7 +136,7 @@ A third option is to call spew.Sdump to get the formatted output as a string:
|
|||
|
||||
str := spew.Sdump(myVar1, myVar2, ...)
|
||||
|
||||
Sample Dump Output
|
||||
# Sample Dump Output
|
||||
|
||||
See the Dump example for details on the setup of the types and variables being
|
||||
shown here.
|
||||
|
|
@ -150,13 +153,14 @@ shown here.
|
|||
|
||||
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
|
||||
command as shown.
|
||||
|
||||
([]uint8) (len=32 cap=32) {
|
||||
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
||||
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
||||
00000020 31 32 |12|
|
||||
}
|
||||
|
||||
Custom Formatter
|
||||
# Custom Formatter
|
||||
|
||||
Spew provides a custom formatter that implements the fmt.Formatter interface
|
||||
so that it integrates cleanly with standard fmt package printing functions. The
|
||||
|
|
@ -170,7 +174,7 @@ standard fmt package for formatting. In addition, the custom formatter ignores
|
|||
the width and precision arguments (however they will still work on the format
|
||||
specifiers not handled by the custom formatter).
|
||||
|
||||
Custom Formatter Usage
|
||||
# Custom Formatter Usage
|
||||
|
||||
The simplest way to make use of the spew custom formatter is to call one of the
|
||||
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
|
||||
|
|
@ -184,15 +188,17 @@ functions have syntax you are most likely already familiar with:
|
|||
|
||||
See the Index for the full list convenience functions.
|
||||
|
||||
Sample Formatter Output
|
||||
# Sample Formatter Output
|
||||
|
||||
Double pointer to a uint8:
|
||||
|
||||
%v: <**>5
|
||||
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
||||
%#v: (**uint8)5
|
||||
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
||||
|
||||
Pointer to circular struct with a uint8 field and a pointer to itself:
|
||||
|
||||
%v: <*>{1 <*><shown>}
|
||||
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
||||
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
||||
|
|
@ -201,7 +207,7 @@ Pointer to circular struct with a uint8 field and a pointer to itself:
|
|||
See the Printf example for details on the setup of variables being shown
|
||||
here.
|
||||
|
||||
Errors
|
||||
# Errors
|
||||
|
||||
Since it is possible for custom Stringer/error interfaces to panic, spew
|
||||
detects them and handles them internally by printing the panic information
|
||||
|
|
@ -488,15 +488,15 @@ pointer addresses used to indirect to the final value. It provides the
|
|||
following features over the built-in printing facilities provided by the fmt
|
||||
package:
|
||||
|
||||
* Pointers are dereferenced and followed
|
||||
* Circular data structures are detected and handled properly
|
||||
* Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
* Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output
|
||||
- Pointers are dereferenced and followed
|
||||
- Circular data structures are detected and handled properly
|
||||
- Custom Stringer/error interfaces are optionally invoked, including
|
||||
on unexported types
|
||||
- Custom types which only implement the Stringer/error interfaces via
|
||||
a pointer receiver are optionally invoked when passing non-pointer
|
||||
variables
|
||||
- Byte arrays and slices are dumped like the hexdump -C command which
|
||||
includes offsets, byte values in hex, and ASCII output
|
||||
|
||||
The configuration options are controlled by an exported package global,
|
||||
spew.Config. See ConfigState for options documentation.
|
||||
14
vendor/modules.txt
vendored
14
vendor/modules.txt
vendored
|
|
@ -39,9 +39,6 @@ github.com/cloudfoundry/jibber_jabber
|
|||
# github.com/creack/pty v1.1.24
|
||||
## explicit; go 1.18
|
||||
github.com/creack/pty
|
||||
# github.com/davecgh/go-spew v1.1.1
|
||||
## explicit
|
||||
github.com/davecgh/go-spew/spew
|
||||
# github.com/fatih/color v1.9.0
|
||||
## explicit; go 1.13
|
||||
github.com/fatih/color
|
||||
|
|
@ -118,9 +115,6 @@ github.com/mitchellh/go-ps
|
|||
# github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe
|
||||
## explicit; go 1.17
|
||||
github.com/petermattis/goid
|
||||
# github.com/pmezard/go-difflib v1.0.0
|
||||
## explicit
|
||||
github.com/pmezard/go-difflib/difflib
|
||||
# github.com/rivo/uniseg v0.4.7
|
||||
## explicit; go 1.18
|
||||
github.com/rivo/uniseg
|
||||
|
|
@ -140,8 +134,8 @@ github.com/sanity-io/litter
|
|||
# github.com/sasha-s/go-deadlock v0.3.9
|
||||
## explicit
|
||||
github.com/sasha-s/go-deadlock
|
||||
# github.com/sirupsen/logrus v1.9.4
|
||||
## explicit; go 1.17
|
||||
# github.com/sirupsen/logrus v1.10.1
|
||||
## explicit; go 1.23
|
||||
github.com/sirupsen/logrus
|
||||
# github.com/spf13/afero v1.15.0
|
||||
## explicit; go 1.23.0
|
||||
|
|
@ -154,10 +148,12 @@ github.com/spkg/bom
|
|||
# github.com/stefanhaller/git-todo-parser v0.0.7-0.20250905083220-c50528f08304
|
||||
## explicit; go 1.13
|
||||
github.com/stefanhaller/git-todo-parser/todo
|
||||
# github.com/stretchr/testify v1.11.1
|
||||
# github.com/stretchr/testify v1.12.0
|
||||
## explicit; go 1.17
|
||||
github.com/stretchr/testify/assert
|
||||
github.com/stretchr/testify/assert/yaml
|
||||
github.com/stretchr/testify/internal/difflib
|
||||
github.com/stretchr/testify/internal/spew
|
||||
# github.com/wk8/go-ordered-map/v2 v2.1.8
|
||||
## explicit; go 1.18
|
||||
github.com/wk8/go-ordered-map/v2
|
||||
|
|
|
|||
Loading…
Reference in a new issue