mirror of
https://github.com/mudler/luet.git
synced 2025-09-05 09:10:43 +00:00
🎨 Introduce contextualized logging
This commit is multi-fold as it also refactors internally context and logger as interfaces so it is easier to plug luet as a library externally. Introduces a garbage collector (related to #227) but doesn't handle yet parallelism. Closes #265
This commit is contained in:
21
vendor/github.com/ipfs/go-log/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/ipfs/go-log/v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
137
vendor/github.com/ipfs/go-log/v2/README.md
generated
vendored
Normal file
137
vendor/github.com/ipfs/go-log/v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
# go-log
|
||||
|
||||
[](https://protocol.ai)
|
||||
[](https://ipfs.io/)
|
||||
[](https://pkg.go.dev/github.com/ipfs/go-log/v2)
|
||||
|
||||
> The logging library used by go-ipfs
|
||||
|
||||
go-log wraps [zap](https://github.com/uber-go/zap) to provide a logging facade. go-log manages logging
|
||||
instances and allows for their levels to be controlled individually.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
go get github.com/ipfs/go-log
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once the package is imported under the name `logging`, an instance of `EventLogger` can be created like so:
|
||||
|
||||
```go
|
||||
var log = logging.Logger("subsystem name")
|
||||
```
|
||||
|
||||
It can then be used to emit log messages in plain printf-style messages at seven standard levels:
|
||||
|
||||
Levels may be set for all loggers:
|
||||
|
||||
```go
|
||||
lvl, err := logging.LevelFromString("error")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logging.SetAllLoggers(lvl)
|
||||
```
|
||||
|
||||
or individually:
|
||||
|
||||
```go
|
||||
err := logging.SetLogLevel("net:pubsub", "info")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
or by regular expression:
|
||||
|
||||
```go
|
||||
err := logging.SetLogLevelRegex("net:.*", "info")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
This package can be configured through various environment variables.
|
||||
|
||||
#### `GOLOG_LOG_LEVEL`
|
||||
|
||||
Specifies the log-level, both globally and on a per-subsystem basis.
|
||||
|
||||
For example, the following will set the global minimum log level to `error`, but reduce the minimum
|
||||
log level for `subsystem1` to `info` and reduce the minimum log level for `subsystem2` to debug.
|
||||
|
||||
```bash
|
||||
export GOLOG_LOG_LEVEL="error,subsystem1=info,subsystem2=debug"
|
||||
```
|
||||
|
||||
`IPFS_LOGGING` is a deprecated alias for this environment variable.
|
||||
|
||||
#### `GOLOG_FILE`
|
||||
|
||||
Specifies that logs should be written to the specified file. If this option is _not_ specified, logs are written to standard error.
|
||||
|
||||
```bash
|
||||
export GOLOG_FILE="/path/to/my/file.log"
|
||||
```
|
||||
|
||||
#### `GOLOG_OUTPUT`
|
||||
|
||||
Specifies where logging output should be written. Can take one or more of the following values, combined with `+`:
|
||||
|
||||
- `stdout` -- write logs to standard out.
|
||||
- `stderr` -- write logs to standard error.
|
||||
- `file` -- write logs to the file specified by `GOLOG_FILE`
|
||||
|
||||
For example, if you want to log to both a file and standard error:
|
||||
|
||||
```bash
|
||||
export GOLOG_FILE="/path/to/my/file.log"
|
||||
export GOLOG_OUTPUT="stderr+file"
|
||||
```
|
||||
|
||||
Setting _only_ `GOLOG_FILE` will prevent logs from being written to standard error.
|
||||
|
||||
#### `GOLOG_LOG_FMT`
|
||||
|
||||
Specifies the log message format. It supports the following values:
|
||||
|
||||
- `color` -- human readable, colorized (ANSI) output
|
||||
- `nocolor` -- human readable, plain-text output.
|
||||
- `json` -- structured JSON.
|
||||
|
||||
For example, to log structured JSON (for easier parsing):
|
||||
|
||||
```bash
|
||||
export GOLOG_LOG_FMT="json"
|
||||
```
|
||||
|
||||
The logging format defaults to `color` when the output is a terminal, and `nocolor` otherwise.
|
||||
|
||||
`IPFS_LOGGING_FMT` is a deprecated alias for this environment variable.
|
||||
|
||||
#### `GOLOG_LOG_LABELS`
|
||||
|
||||
Specifies a set of labels that should be added to all log messages as comma-separated key-value
|
||||
pairs. For example, the following add `{"app": "example_app", "dc": "sjc-1"}` to every log entry.
|
||||
|
||||
```bash
|
||||
export GOLOG_LOG_LABELS="app=example_app,dc=sjc-1"
|
||||
```
|
||||
|
||||
## Contribute
|
||||
|
||||
Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-log/issues)!
|
||||
|
||||
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
||||
|
||||
### Want to hack on IPFS?
|
||||
|
||||
[](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
121
vendor/github.com/ipfs/go-log/v2/core.go
generated
vendored
Normal file
121
vendor/github.com/ipfs/go-log/v2/core.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var _ zapcore.Core = (*lockedMultiCore)(nil)
|
||||
|
||||
type lockedMultiCore struct {
|
||||
mu sync.RWMutex // guards mutations to cores slice
|
||||
cores []zapcore.Core
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) With(fields []zapcore.Field) zapcore.Core {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
sub := &lockedMultiCore{
|
||||
cores: make([]zapcore.Core, len(l.cores)),
|
||||
}
|
||||
for i := range l.cores {
|
||||
sub.cores[i] = l.cores[i].With(fields)
|
||||
}
|
||||
return sub
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) Enabled(lvl zapcore.Level) bool {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
for i := range l.cores {
|
||||
if l.cores[i].Enabled(lvl) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
for i := range l.cores {
|
||||
ce = l.cores[i].Check(ent, ce)
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) Write(ent zapcore.Entry, fields []zapcore.Field) error {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
var err error
|
||||
for i := range l.cores {
|
||||
err = multierr.Append(err, l.cores[i].Write(ent, fields))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) Sync() error {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
var err error
|
||||
for i := range l.cores {
|
||||
err = multierr.Append(err, l.cores[i].Sync())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) AddCore(core zapcore.Core) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
l.cores = append(l.cores, core)
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) DeleteCore(core zapcore.Core) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
w := 0
|
||||
for i := 0; i < len(l.cores); i++ {
|
||||
if reflect.DeepEqual(l.cores[i], core) {
|
||||
continue
|
||||
}
|
||||
l.cores[w] = l.cores[i]
|
||||
w++
|
||||
}
|
||||
l.cores = l.cores[:w]
|
||||
}
|
||||
|
||||
func (l *lockedMultiCore) ReplaceCore(original, replacement zapcore.Core) {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
for i := 0; i < len(l.cores); i++ {
|
||||
if reflect.DeepEqual(l.cores[i], original) {
|
||||
l.cores[i] = replacement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newCore(format LogFormat, ws zapcore.WriteSyncer, level LogLevel) zapcore.Core {
|
||||
encCfg := zap.NewProductionEncoderConfig()
|
||||
encCfg.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
|
||||
var encoder zapcore.Encoder
|
||||
switch format {
|
||||
case PlaintextOutput:
|
||||
encCfg.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||
encoder = zapcore.NewConsoleEncoder(encCfg)
|
||||
case JSONOutput:
|
||||
encoder = zapcore.NewJSONEncoder(encCfg)
|
||||
default:
|
||||
encCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
encoder = zapcore.NewConsoleEncoder(encCfg)
|
||||
}
|
||||
|
||||
return zapcore.NewCore(encoder, ws, zap.NewAtomicLevelAt(zapcore.Level(level)))
|
||||
}
|
9
vendor/github.com/ipfs/go-log/v2/go.mod
generated
vendored
Normal file
9
vendor/github.com/ipfs/go-log/v2/go.mod
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module github.com/ipfs/go-log/v2
|
||||
|
||||
require (
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
go.uber.org/multierr v1.6.0
|
||||
go.uber.org/zap v1.16.0
|
||||
)
|
||||
|
||||
go 1.16
|
57
vendor/github.com/ipfs/go-log/v2/go.sum
generated
vendored
Normal file
57
vendor/github.com/ipfs/go-log/v2/go.sum
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
30
vendor/github.com/ipfs/go-log/v2/levels.go
generated
vendored
Normal file
30
vendor/github.com/ipfs/go-log/v2/levels.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package log
|
||||
|
||||
import "go.uber.org/zap/zapcore"
|
||||
|
||||
// LogLevel represents a log severity level. Use the package variables as an
|
||||
// enum.
|
||||
type LogLevel zapcore.Level
|
||||
|
||||
var (
|
||||
LevelDebug = LogLevel(zapcore.DebugLevel)
|
||||
LevelInfo = LogLevel(zapcore.InfoLevel)
|
||||
LevelWarn = LogLevel(zapcore.WarnLevel)
|
||||
LevelError = LogLevel(zapcore.ErrorLevel)
|
||||
LevelDPanic = LogLevel(zapcore.DPanicLevel)
|
||||
LevelPanic = LogLevel(zapcore.PanicLevel)
|
||||
LevelFatal = LogLevel(zapcore.FatalLevel)
|
||||
)
|
||||
|
||||
// LevelFromString parses a string-based level and returns the corresponding
|
||||
// LogLevel.
|
||||
//
|
||||
// Supported strings are: DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL, and
|
||||
// their lower-case forms.
|
||||
//
|
||||
// The returned LogLevel must be discarded if error is not nil.
|
||||
func LevelFromString(level string) (LogLevel, error) {
|
||||
lvl := zapcore.InfoLevel // zero value
|
||||
err := lvl.Set(level)
|
||||
return LogLevel(lvl), err
|
||||
}
|
84
vendor/github.com/ipfs/go-log/v2/log.go
generated
vendored
Normal file
84
vendor/github.com/ipfs/go-log/v2/log.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Package log is the logging library used by IPFS & libp2p
|
||||
// (https://github.com/ipfs/go-ipfs).
|
||||
package log
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// StandardLogger provides API compatibility with standard printf loggers
|
||||
// eg. go-logging
|
||||
type StandardLogger interface {
|
||||
Debug(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Panic(args ...interface{})
|
||||
Panicf(format string, args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// EventLogger extends the StandardLogger interface to allow for log items
|
||||
// containing structured metadata
|
||||
type EventLogger interface {
|
||||
StandardLogger
|
||||
}
|
||||
|
||||
// Logger retrieves an event logger by name
|
||||
func Logger(system string) *ZapEventLogger {
|
||||
if len(system) == 0 {
|
||||
setuplog := getLogger("setup-logger")
|
||||
setuplog.Error("Missing name parameter")
|
||||
system = "undefined"
|
||||
}
|
||||
|
||||
logger := getLogger(system)
|
||||
skipLogger := logger.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar()
|
||||
|
||||
return &ZapEventLogger{
|
||||
system: system,
|
||||
SugaredLogger: *logger,
|
||||
skipLogger: *skipLogger,
|
||||
}
|
||||
}
|
||||
|
||||
// ZapEventLogger implements the EventLogger and wraps a go-logging Logger
|
||||
type ZapEventLogger struct {
|
||||
zap.SugaredLogger
|
||||
// used to fix the caller location when calling Warning and Warningf.
|
||||
skipLogger zap.SugaredLogger
|
||||
system string
|
||||
}
|
||||
|
||||
// Warning is for compatibility
|
||||
// Deprecated: use Warn(args ...interface{}) instead
|
||||
func (logger *ZapEventLogger) Warning(args ...interface{}) {
|
||||
logger.skipLogger.Warn(args...)
|
||||
}
|
||||
|
||||
// Warningf is for compatibility
|
||||
// Deprecated: use Warnf(format string, args ...interface{}) instead
|
||||
func (logger *ZapEventLogger) Warningf(format string, args ...interface{}) {
|
||||
logger.skipLogger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// FormatRFC3339 returns the given time in UTC with RFC3999Nano format.
|
||||
func FormatRFC3339(t time.Time) string {
|
||||
return t.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
func WithStacktrace(l *ZapEventLogger, level LogLevel) *ZapEventLogger {
|
||||
copyLogger := *l
|
||||
copyLogger.SugaredLogger = *copyLogger.SugaredLogger.Desugar().
|
||||
WithOptions(zap.AddStacktrace(zapcore.Level(level))).Sugar()
|
||||
copyLogger.skipLogger = *copyLogger.SugaredLogger.Desugar().WithOptions(zap.AddCallerSkip(1)).Sugar()
|
||||
return ©Logger
|
||||
}
|
12
vendor/github.com/ipfs/go-log/v2/path_other.go
generated
vendored
Normal file
12
vendor/github.com/ipfs/go-log/v2/path_other.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func normalizePath(p string) (string, error) {
|
||||
return filepath.Abs(p)
|
||||
}
|
36
vendor/github.com/ipfs/go-log/v2/path_windows.go
generated
vendored
Normal file
36
vendor/github.com/ipfs/go-log/v2/path_windows.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func normalizePath(p string) (string, error) {
|
||||
if p == "" {
|
||||
return "", fmt.Errorf("path empty")
|
||||
}
|
||||
p, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Is this _really_ an absolute path?
|
||||
if !strings.HasPrefix(p, "\\\\") {
|
||||
// It's a drive: path!
|
||||
// Return a UNC path.
|
||||
p = "\\\\%3F\\" + p
|
||||
}
|
||||
|
||||
// This will return file:////?/c:/foobar
|
||||
//
|
||||
// Why? Because:
|
||||
// 1. Go will choke on file://c:/ because the "domain" includes a :.
|
||||
// 2. Windows will choke on file:///c:/ because the path will be
|
||||
// /c:/... which is _relative_ to the current drive.
|
||||
//
|
||||
// This path (a) has no "domain" and (b) starts with a slash. Yay!
|
||||
return "file://" + filepath.ToSlash(p), nil
|
||||
}
|
90
vendor/github.com/ipfs/go-log/v2/pipe.go
generated
vendored
Normal file
90
vendor/github.com/ipfs/go-log/v2/pipe.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"go.uber.org/multierr"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// A PipeReader is a reader that reads from the logger. It is synchronous
|
||||
// so blocking on read will affect logging performance.
|
||||
type PipeReader struct {
|
||||
r *io.PipeReader
|
||||
closer io.Closer
|
||||
core zapcore.Core
|
||||
}
|
||||
|
||||
// Read implements the standard Read interface
|
||||
func (p *PipeReader) Read(data []byte) (int, error) {
|
||||
return p.r.Read(data)
|
||||
}
|
||||
|
||||
// Close unregisters the reader from the logger.
|
||||
func (p *PipeReader) Close() error {
|
||||
if p.core != nil {
|
||||
loggerCore.DeleteCore(p.core)
|
||||
}
|
||||
return multierr.Append(p.core.Sync(), p.closer.Close())
|
||||
}
|
||||
|
||||
// NewPipeReader creates a new in-memory reader that reads from all loggers
|
||||
// The caller must call Close on the returned reader when done.
|
||||
//
|
||||
// By default, it:
|
||||
//
|
||||
// 1. Logs JSON. This can be changed by passing the PipeFormat option.
|
||||
// 2. Logs everything that would otherwise be logged to the "primary" log
|
||||
// output. That is, everything enabled by SetLogLevel. The minimum log level
|
||||
// can be increased by passing the PipeLevel option.
|
||||
func NewPipeReader(opts ...PipeReaderOption) *PipeReader {
|
||||
opt := pipeReaderOptions{
|
||||
format: JSONOutput,
|
||||
level: LevelDebug,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o.setOption(&opt)
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
|
||||
p := &PipeReader{
|
||||
r: r,
|
||||
closer: w,
|
||||
core: newCore(opt.format, zapcore.AddSync(w), opt.level),
|
||||
}
|
||||
|
||||
loggerCore.AddCore(p.core)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
type pipeReaderOptions struct {
|
||||
format LogFormat
|
||||
level LogLevel
|
||||
}
|
||||
|
||||
type PipeReaderOption interface {
|
||||
setOption(*pipeReaderOptions)
|
||||
}
|
||||
|
||||
type pipeReaderOptionFunc func(*pipeReaderOptions)
|
||||
|
||||
func (p pipeReaderOptionFunc) setOption(o *pipeReaderOptions) {
|
||||
p(o)
|
||||
}
|
||||
|
||||
// PipeFormat sets the output format of the pipe reader
|
||||
func PipeFormat(format LogFormat) PipeReaderOption {
|
||||
return pipeReaderOptionFunc(func(o *pipeReaderOptions) {
|
||||
o.format = format
|
||||
})
|
||||
}
|
||||
|
||||
// PipeLevel sets the log level of logs sent to the pipe reader.
|
||||
func PipeLevel(level LogLevel) PipeReaderOption {
|
||||
return pipeReaderOptionFunc(func(o *pipeReaderOptions) {
|
||||
o.level = level
|
||||
})
|
||||
}
|
390
vendor/github.com/ipfs/go-log/v2/setup.go
generated
vendored
Normal file
390
vendor/github.com/ipfs/go-log/v2/setup.go
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetupLogging(configFromEnv())
|
||||
}
|
||||
|
||||
// Logging environment variables
|
||||
const (
|
||||
// IPFS_* prefixed env vars kept for backwards compatibility
|
||||
// for this release. They will not be available in the next
|
||||
// release.
|
||||
//
|
||||
// GOLOG_* env vars take precedences over IPFS_* env vars.
|
||||
envIPFSLogging = "IPFS_LOGGING"
|
||||
envIPFSLoggingFmt = "IPFS_LOGGING_FMT"
|
||||
|
||||
envLogging = "GOLOG_LOG_LEVEL"
|
||||
envLoggingFmt = "GOLOG_LOG_FMT"
|
||||
|
||||
envLoggingFile = "GOLOG_FILE" // /path/to/file
|
||||
envLoggingURL = "GOLOG_URL" // url that will be processed by sink in the zap
|
||||
|
||||
envLoggingOutput = "GOLOG_OUTPUT" // possible values: stdout|stderr|file combine multiple values with '+'
|
||||
envLoggingLabels = "GOLOG_LOG_LABELS" // comma-separated key-value pairs, i.e. "app=example_app,dc=sjc-1"
|
||||
)
|
||||
|
||||
type LogFormat int
|
||||
|
||||
const (
|
||||
ColorizedOutput LogFormat = iota
|
||||
PlaintextOutput
|
||||
JSONOutput
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Format overrides the format of the log output. Defaults to ColorizedOutput
|
||||
Format LogFormat
|
||||
|
||||
// Level is the default minimum enabled logging level.
|
||||
Level LogLevel
|
||||
|
||||
// SubsystemLevels are the default levels per-subsystem. When unspecified, defaults to Level.
|
||||
SubsystemLevels map[string]LogLevel
|
||||
|
||||
// Stderr indicates whether logs should be written to stderr.
|
||||
Stderr bool
|
||||
|
||||
// Stdout indicates whether logs should be written to stdout.
|
||||
Stdout bool
|
||||
|
||||
// File is a path to a file that logs will be written to.
|
||||
File string
|
||||
|
||||
// URL with schema supported by zap. Use zap.RegisterSink
|
||||
URL string
|
||||
|
||||
// Labels is a set of key-values to apply to all loggers
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger
|
||||
var ErrNoSuchLogger = errors.New("error: No such logger")
|
||||
|
||||
var loggerMutex sync.RWMutex // guards access to global logger state
|
||||
|
||||
// loggers is the set of loggers in the system
|
||||
var loggers = make(map[string]*zap.SugaredLogger)
|
||||
var levels = make(map[string]zap.AtomicLevel)
|
||||
|
||||
// primaryFormat is the format of the primary core used for logging
|
||||
var primaryFormat LogFormat = ColorizedOutput
|
||||
|
||||
// defaultLevel is the default log level
|
||||
var defaultLevel LogLevel = LevelError
|
||||
|
||||
// primaryCore is the primary logging core
|
||||
var primaryCore zapcore.Core
|
||||
|
||||
// loggerCore is the base for all loggers created by this package
|
||||
var loggerCore = &lockedMultiCore{}
|
||||
|
||||
// SetupLogging will initialize the logger backend and set the flags.
|
||||
// TODO calling this in `init` pushes all configuration to env variables
|
||||
// - move it out of `init`? then we need to change all the code (js-ipfs, go-ipfs) to call this explicitly
|
||||
// - have it look for a config file? need to define what that is
|
||||
func SetupLogging(cfg Config) {
|
||||
loggerMutex.Lock()
|
||||
defer loggerMutex.Unlock()
|
||||
|
||||
primaryFormat = cfg.Format
|
||||
defaultLevel = cfg.Level
|
||||
|
||||
outputPaths := []string{}
|
||||
|
||||
if cfg.Stderr {
|
||||
outputPaths = append(outputPaths, "stderr")
|
||||
}
|
||||
if cfg.Stdout {
|
||||
outputPaths = append(outputPaths, "stdout")
|
||||
}
|
||||
|
||||
// check if we log to a file
|
||||
if len(cfg.File) > 0 {
|
||||
if path, err := normalizePath(cfg.File); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to resolve log path '%q', logging to %s\n", cfg.File, outputPaths)
|
||||
} else {
|
||||
outputPaths = append(outputPaths, path)
|
||||
}
|
||||
}
|
||||
if len(cfg.URL) > 0 {
|
||||
outputPaths = append(outputPaths, cfg.URL)
|
||||
}
|
||||
|
||||
ws, _, err := zap.Open(outputPaths...)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to open logging output: %v", err))
|
||||
}
|
||||
|
||||
newPrimaryCore := newCore(primaryFormat, ws, LevelDebug) // the main core needs to log everything.
|
||||
|
||||
for k, v := range cfg.Labels {
|
||||
newPrimaryCore = newPrimaryCore.With([]zap.Field{zap.String(k, v)})
|
||||
}
|
||||
|
||||
setPrimaryCore(newPrimaryCore)
|
||||
setAllLoggers(defaultLevel)
|
||||
|
||||
for name, level := range cfg.SubsystemLevels {
|
||||
if leveler, ok := levels[name]; ok {
|
||||
leveler.SetLevel(zapcore.Level(level))
|
||||
} else {
|
||||
levels[name] = zap.NewAtomicLevelAt(zapcore.Level(level))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetPrimaryCore changes the primary logging core. If the SetupLogging was
|
||||
// called then the previously configured core will be replaced.
|
||||
func SetPrimaryCore(core zapcore.Core) {
|
||||
loggerMutex.Lock()
|
||||
defer loggerMutex.Unlock()
|
||||
|
||||
setPrimaryCore(core)
|
||||
}
|
||||
|
||||
func setPrimaryCore(core zapcore.Core) {
|
||||
if primaryCore != nil {
|
||||
loggerCore.ReplaceCore(primaryCore, core)
|
||||
} else {
|
||||
loggerCore.AddCore(core)
|
||||
}
|
||||
primaryCore = core
|
||||
}
|
||||
|
||||
// SetDebugLogging calls SetAllLoggers with logging.DEBUG
|
||||
func SetDebugLogging() {
|
||||
SetAllLoggers(LevelDebug)
|
||||
}
|
||||
|
||||
// SetAllLoggers changes the logging level of all loggers to lvl
|
||||
func SetAllLoggers(lvl LogLevel) {
|
||||
loggerMutex.RLock()
|
||||
defer loggerMutex.RUnlock()
|
||||
|
||||
setAllLoggers(lvl)
|
||||
}
|
||||
|
||||
func setAllLoggers(lvl LogLevel) {
|
||||
for _, l := range levels {
|
||||
l.SetLevel(zapcore.Level(lvl))
|
||||
}
|
||||
}
|
||||
|
||||
// SetLogLevel changes the log level of a specific subsystem
|
||||
// name=="*" changes all subsystems
|
||||
func SetLogLevel(name, level string) error {
|
||||
lvl, err := LevelFromString(level)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wildcard, change all
|
||||
if name == "*" {
|
||||
SetAllLoggers(lvl)
|
||||
return nil
|
||||
}
|
||||
|
||||
loggerMutex.RLock()
|
||||
defer loggerMutex.RUnlock()
|
||||
|
||||
// Check if we have a logger by that name
|
||||
if _, ok := levels[name]; !ok {
|
||||
return ErrNoSuchLogger
|
||||
}
|
||||
|
||||
levels[name].SetLevel(zapcore.Level(lvl))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLogLevelRegex sets all loggers to level `l` that match expression `e`.
|
||||
// An error is returned if `e` fails to compile.
|
||||
func SetLogLevelRegex(e, l string) error {
|
||||
lvl, err := LevelFromString(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rem, err := regexp.Compile(e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loggerMutex.Lock()
|
||||
defer loggerMutex.Unlock()
|
||||
for name := range loggers {
|
||||
if rem.MatchString(name) {
|
||||
levels[name].SetLevel(zapcore.Level(lvl))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSubsystems returns a slice containing the
|
||||
// names of the current loggers
|
||||
func GetSubsystems() []string {
|
||||
loggerMutex.RLock()
|
||||
defer loggerMutex.RUnlock()
|
||||
subs := make([]string, 0, len(loggers))
|
||||
|
||||
for k := range loggers {
|
||||
subs = append(subs, k)
|
||||
}
|
||||
return subs
|
||||
}
|
||||
|
||||
func getLogger(name string) *zap.SugaredLogger {
|
||||
loggerMutex.Lock()
|
||||
defer loggerMutex.Unlock()
|
||||
log, ok := loggers[name]
|
||||
if !ok {
|
||||
level, ok := levels[name]
|
||||
if !ok {
|
||||
level = zap.NewAtomicLevelAt(zapcore.Level(defaultLevel))
|
||||
levels[name] = level
|
||||
}
|
||||
log = zap.New(loggerCore).
|
||||
WithOptions(
|
||||
zap.IncreaseLevel(level),
|
||||
zap.AddCaller(),
|
||||
).
|
||||
Named(name).
|
||||
Sugar()
|
||||
|
||||
loggers[name] = log
|
||||
}
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
// configFromEnv returns a Config with defaults populated using environment variables.
|
||||
func configFromEnv() Config {
|
||||
cfg := Config{
|
||||
Format: ColorizedOutput,
|
||||
Stderr: true,
|
||||
Level: LevelError,
|
||||
SubsystemLevels: map[string]LogLevel{},
|
||||
Labels: map[string]string{},
|
||||
}
|
||||
|
||||
format := os.Getenv(envLoggingFmt)
|
||||
if format == "" {
|
||||
format = os.Getenv(envIPFSLoggingFmt)
|
||||
}
|
||||
|
||||
var noExplicitFormat bool
|
||||
|
||||
switch format {
|
||||
case "color":
|
||||
cfg.Format = ColorizedOutput
|
||||
case "nocolor":
|
||||
cfg.Format = PlaintextOutput
|
||||
case "json":
|
||||
cfg.Format = JSONOutput
|
||||
default:
|
||||
if format != "" {
|
||||
fmt.Fprintf(os.Stderr, "ignoring unrecognized log format '%s'\n", format)
|
||||
}
|
||||
noExplicitFormat = true
|
||||
}
|
||||
|
||||
lvl := os.Getenv(envLogging)
|
||||
if lvl == "" {
|
||||
lvl = os.Getenv(envIPFSLogging)
|
||||
}
|
||||
if lvl != "" {
|
||||
for _, kvs := range strings.Split(lvl, ",") {
|
||||
kv := strings.SplitN(kvs, "=", 2)
|
||||
lvl, err := LevelFromString(kv[len(kv)-1])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error setting log level %q: %s\n", kvs, err)
|
||||
continue
|
||||
}
|
||||
switch len(kv) {
|
||||
case 1:
|
||||
cfg.Level = lvl
|
||||
case 2:
|
||||
cfg.SubsystemLevels[kv[0]] = lvl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg.File = os.Getenv(envLoggingFile)
|
||||
// Disable stderr logging when a file is specified
|
||||
// https://github.com/ipfs/go-log/issues/83
|
||||
if cfg.File != "" {
|
||||
cfg.Stderr = false
|
||||
}
|
||||
|
||||
cfg.URL = os.Getenv(envLoggingURL)
|
||||
output := os.Getenv(envLoggingOutput)
|
||||
outputOptions := strings.Split(output, "+")
|
||||
for _, opt := range outputOptions {
|
||||
switch opt {
|
||||
case "stdout":
|
||||
cfg.Stdout = true
|
||||
case "stderr":
|
||||
cfg.Stderr = true
|
||||
case "file":
|
||||
if cfg.File == "" {
|
||||
fmt.Fprint(os.Stderr, "please specify a GOLOG_FILE value to write to")
|
||||
}
|
||||
case "url":
|
||||
if cfg.URL == "" {
|
||||
fmt.Fprint(os.Stderr, "please specify a GOLOG_URL value to write to")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that neither of the requested Std* nor the file are TTYs
|
||||
// At this stage (configFromEnv) we do not have a uniform list to examine yet
|
||||
if noExplicitFormat &&
|
||||
!(cfg.Stdout && isTerm(os.Stdout)) &&
|
||||
!(cfg.Stderr && isTerm(os.Stderr)) &&
|
||||
// check this last: expensive
|
||||
!(cfg.File != "" && pathIsTerm(cfg.File)) {
|
||||
cfg.Format = PlaintextOutput
|
||||
}
|
||||
|
||||
labels := os.Getenv(envLoggingLabels)
|
||||
if labels != "" {
|
||||
labelKVs := strings.Split(labels, ",")
|
||||
for _, label := range labelKVs {
|
||||
kv := strings.Split(label, "=")
|
||||
if len(kv) != 2 {
|
||||
fmt.Fprint(os.Stderr, "invalid label k=v: ", label)
|
||||
continue
|
||||
}
|
||||
cfg.Labels[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func isTerm(f *os.File) bool {
|
||||
return isatty.IsTerminal(f.Fd()) || isatty.IsCygwinTerminal(f.Fd())
|
||||
}
|
||||
|
||||
func pathIsTerm(p string) bool {
|
||||
// !!!no!!! O_CREAT, if we fail - we fail
|
||||
f, err := os.OpenFile(p, os.O_WRONLY, 0)
|
||||
if f != nil {
|
||||
defer f.Close() // nolint:errcheck
|
||||
}
|
||||
return err == nil && isTerm(f)
|
||||
}
|
3
vendor/github.com/ipfs/go-log/v2/version.json
generated
vendored
Normal file
3
vendor/github.com/ipfs/go-log/v2/version.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"version": "v2.4.0"
|
||||
}
|
Reference in New Issue
Block a user