-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
(cherry picked from commit 6276b01) # Conflicts: # log/CHANGELOG.md # log/logger.go # tools/cosmovisor/cmd/cosmovisor/version_test.go
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ jobs: | |
id: git_diff | ||
with: | ||
PATTERNS: | | ||
**/*.mk | ||
Makefile | ||
**/Makefile | ||
.golangci.yml | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<!-- | ||
Guiding Principles: | ||
Changelogs are for humans, not machines. | ||
There should be an entry for every single version. | ||
The same types of changes should be grouped. | ||
Versions and sections should be linkable. | ||
The latest version comes first. | ||
The release date of each version is displayed. | ||
Mention whether you follow Semantic Versioning. | ||
Usage: | ||
Change log entries are to be added to the Unreleased section from newest to oldest. | ||
Each entry must include the Github issue reference in the following format: | ||
* [#<issue-number>] Changelog message. | ||
--> | ||
|
||
# Changelog | ||
|
||
## [Unreleased] | ||
|
||
## [v1.4.1](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.4.1) - 2024-08-16 | ||
|
||
* [#21326](https://github.com/cosmos/cosmos-sdk/pull/21326) Avoid context key collision. | ||
|
||
## [v1.4.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.4.0) - 2024-08-07 | ||
|
||
* [#21045](https://github.com/cosmos/cosmos-sdk/pull/21045) Add `WithContext` method implementations to make all returned loggers compatible with `cosmossdk.io/core/log.Logger` (v1) without a direct dependency. | ||
|
||
## [v1.3.1](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.3.1) - 2024-02-05 | ||
|
||
* [#19346](https://github.com/cosmos/cosmos-sdk/pull/19346) Upgrade zerolog to v1.32.0. | ||
* [#19346](https://github.com/cosmos/cosmos-sdk/pull/19346) `#15956` now works thanks to the upgrade of `zerolog`. | ||
|
||
## [v1.3.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.3.0) - 2024-01-10 | ||
|
||
* [#18916](https://github.com/cosmos/cosmos-sdk/pull/18916) Introduce an option for setting hooks. | ||
* [#18429](https://github.com/cosmos/cosmos-sdk/pull/18429) Support customization of log json marshal. | ||
* [#18898](https://github.com/cosmos/cosmos-sdk/pull/18898) Add `WARN` level. | ||
|
||
## [v1.2.1](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.2.1) - 2023-08-25 | ||
|
||
* [#17532](https://github.com/cosmos/cosmos-sdk/pull/17532) Proper marshalling of `fmt.Stringer` (follow-up of [#17205](https://github.com/cosmos/cosmos-sdk/pull/17205)). | ||
|
||
## [v1.2.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.2.0) - 2023-07-31 | ||
|
||
* [#17194](https://github.com/cosmos/cosmos-sdk/pull/17194) Avoid repeating parse log level in `ParseLogLevel`. | ||
* [#17205](https://github.com/cosmos/cosmos-sdk/pull/17205) Fix types that do not implement the `json.Marshaler` interface. | ||
* [#15956](https://github.com/cosmos/cosmos-sdk/pull/15956) Introduce an option for enabling error stack trace. | ||
|
||
## [v1.1.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.1.0) - 2023-04-27 | ||
|
||
* [#15956](https://github.com/cosmos/cosmos-sdk/pull/15956) Introduce options to configure logger (enable/disable colored output, customize log timestamps). | ||
|
||
## [v1.0.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.0.0) - 2023-03-30 | ||
|
||
* [#15601](https://github.com/cosmos/cosmos-sdk/pull/15601) Introduce logger options. These options allow to configure the logger with filters, different level and output format. | ||
|
||
## [v0.1.0](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v0.1.0) - 2023-03-13 | ||
|
||
* Introducing a standalone SDK logger package (`comossdk.io/log`). | ||
It replaces CometBFT logger and provides a common interface for all SDK components. | ||
The default logger (`NewLogger`) is using [zerolog](https://github.com/rs/zerolog), | ||
but it can be easily replaced with any implementation that implements the `log.Logger` interface. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package log | ||
|
||
import ( | ||
"encoding" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/rs/zerolog" | ||
"github.com/rs/zerolog/pkgerrors" | ||
) | ||
|
||
func init() { | ||
zerolog.InterfaceMarshalFunc = func(i any) ([]byte, error) { | ||
switch v := i.(type) { | ||
case json.Marshaler: | ||
return json.Marshal(i) | ||
case encoding.TextMarshaler: | ||
return json.Marshal(i) | ||
case fmt.Stringer: | ||
return json.Marshal(v.String()) | ||
default: | ||
return json.Marshal(i) | ||
} | ||
} | ||
} | ||
|
||
// ModuleKey defines a module logging key. | ||
const ModuleKey = "module" | ||
|
||
// ContextKey is used to store the logger in the context. | ||
var ContextKey contextKey | ||
|
||
type contextKey struct{} | ||
|
||
// Logger is the Cosmos SDK logger interface. | ||
// It extends cosmossdk.io/core/log.Logger to return a child logger. | ||
// Use cosmossdk.io/core/log.Logger instead in modules. | ||
type Logger interface { | ||
// Info takes a message and a set of key/value pairs and logs with level INFO. | ||
// The key of the tuple must be a string. | ||
Info(msg string, keyVals ...any) | ||
|
||
// Warn takes a message and a set of key/value pairs and logs with level WARN. | ||
// The key of the tuple must be a string. | ||
Warn(msg string, keyVals ...any) | ||
|
||
// Error takes a message and a set of key/value pairs and logs with level ERR. | ||
// The key of the tuple must be a string. | ||
Error(msg string, keyVals ...any) | ||
|
||
// Debug takes a message and a set of key/value pairs and logs with level DEBUG. | ||
// The key of the tuple must be a string. | ||
Debug(msg string, keyVals ...any) | ||
|
||
// With returns a new wrapped logger with additional context provided by a set. | ||
With(keyVals ...any) Logger | ||
|
||
// Impl returns the underlying logger implementation. | ||
// It is used to access the full functionalities of the underlying logger. | ||
// Advanced users can type cast the returned value to the actual logger. | ||
Impl() any | ||
} | ||
|
||
// WithJSONMarshal configures zerolog global json encoding. | ||
func WithJSONMarshal(marshaler func(v any) ([]byte, error)) { | ||
zerolog.InterfaceMarshalFunc = func(i any) ([]byte, error) { | ||
switch v := i.(type) { | ||
case json.Marshaler: | ||
return marshaler(i) | ||
case encoding.TextMarshaler: | ||
return marshaler(i) | ||
case fmt.Stringer: | ||
return marshaler(v.String()) | ||
default: | ||
return marshaler(i) | ||
} | ||
} | ||
} | ||
|
||
type zeroLogWrapper struct { | ||
*zerolog.Logger | ||
} | ||
|
||
// NewLogger returns a new logger that writes to the given destination. | ||
// | ||
// Typical usage from a main function is: | ||
// | ||
// logger := log.NewLogger(os.Stderr) | ||
// | ||
// Stderr is the typical destination for logs, | ||
// so that any output from your application can still be piped to other processes. | ||
// The returned value can be safely cast to cosmossdk.io/core/log.Logger. | ||
func NewLogger(dst io.Writer, options ...Option) Logger { | ||
Check failure on line 95 in log/logger.go GitHub Actions / dependency-review
Check failure on line 95 in log/logger.go GitHub Actions / tests (01)
|
||
logCfg := defaultConfig | ||
Check failure on line 96 in log/logger.go GitHub Actions / dependency-review
Check failure on line 96 in log/logger.go GitHub Actions / tests (01)
|
||
for _, opt := range options { | ||
opt(&logCfg) | ||
} | ||
|
||
output := dst | ||
if !logCfg.OutputJSON { | ||
output = zerolog.ConsoleWriter{ | ||
Out: dst, | ||
NoColor: !logCfg.Color, | ||
TimeFormat: logCfg.TimeFormat, | ||
} | ||
} | ||
|
||
if logCfg.Filter != nil { | ||
output = NewFilterWriter(output, logCfg.Filter) | ||
Check failure on line 111 in log/logger.go GitHub Actions / dependency-review
Check failure on line 111 in log/logger.go GitHub Actions / tests (01)
|
||
} | ||
|
||
logger := zerolog.New(output) | ||
if logCfg.StackTrace { | ||
zerolog.ErrorStackMarshaler = func(err error) interface{} { | ||
return pkgerrors.MarshalStack(errors.WithStack(err)) | ||
} | ||
|
||
logger = logger.With().Stack().Logger() | ||
} | ||
|
||
if logCfg.TimeFormat != "" { | ||
logger = logger.With().Timestamp().Logger() | ||
} | ||
|
||
if logCfg.Level != zerolog.NoLevel { | ||
logger = logger.Level(logCfg.Level) | ||
} | ||
|
||
logger = logger.Hook(logCfg.Hooks...) | ||
|
||
return zeroLogWrapper{&logger} | ||
} | ||
|
||
// NewCustomLogger returns a new logger with the given zerolog logger. | ||
func NewCustomLogger(logger zerolog.Logger) Logger { | ||
return zeroLogWrapper{&logger} | ||
} | ||
|
||
// Info takes a message and a set of key/value pairs and logs with level INFO. | ||
// The key of the tuple must be a string. | ||
func (l zeroLogWrapper) Info(msg string, keyVals ...interface{}) { | ||
l.Logger.Info().Fields(keyVals).Msg(msg) | ||
} | ||
|
||
// Warn takes a message and a set of key/value pairs and logs with level WARN. | ||
// The key of the tuple must be a string. | ||
func (l zeroLogWrapper) Warn(msg string, keyVals ...interface{}) { | ||
l.Logger.Warn().Fields(keyVals).Msg(msg) | ||
} | ||
|
||
// Error takes a message and a set of key/value pairs and logs with level ERROR. | ||
// The key of the tuple must be a string. | ||
func (l zeroLogWrapper) Error(msg string, keyVals ...interface{}) { | ||
l.Logger.Error().Fields(keyVals).Msg(msg) | ||
} | ||
|
||
// Debug takes a message and a set of key/value pairs and logs with level DEBUG. | ||
// The key of the tuple must be a string. | ||
func (l zeroLogWrapper) Debug(msg string, keyVals ...interface{}) { | ||
l.Logger.Debug().Fields(keyVals).Msg(msg) | ||
} | ||
|
||
// With returns a new wrapped logger with additional context provided by a set. | ||
func (l zeroLogWrapper) With(keyVals ...interface{}) Logger { | ||
logger := l.Logger.With().Fields(keyVals).Logger() | ||
return zeroLogWrapper{&logger} | ||
} | ||
|
||
// WithContext returns a new wrapped logger with additional context provided by a set. | ||
func (l zeroLogWrapper) WithContext(keyVals ...interface{}) any { | ||
logger := l.Logger.With().Fields(keyVals).Logger() | ||
return zeroLogWrapper{&logger} | ||
} | ||
|
||
// Impl returns the underlying zerolog logger. | ||
// It can be used to used zerolog structured API directly instead of the wrapper. | ||
func (l zeroLogWrapper) Impl() interface{} { | ||
return l.Logger | ||
} | ||
|
||
// NewNopLogger returns a new logger that does nothing. | ||
func NewNopLogger() Logger { | ||
// The custom nopLogger is about 3x faster than a zeroLogWrapper with zerolog.Nop(). | ||
return nopLogger{} | ||
} | ||
|
||
// nopLogger is a Logger that does nothing when called. | ||
// See the "specialized nop logger" benchmark and compare with the "zerolog nop logger" benchmark. | ||
// The custom implementation is about 3x faster. | ||
type nopLogger struct{} | ||
|
||
func (nopLogger) Info(string, ...any) {} | ||
func (nopLogger) Warn(string, ...any) {} | ||
func (nopLogger) Error(string, ...any) {} | ||
func (nopLogger) Debug(string, ...any) {} | ||
func (nopLogger) With(...any) Logger { return nopLogger{} } | ||
func (nopLogger) WithContext(...any) any { return nopLogger{} } | ||
func (nopLogger) Impl() any { return nopLogger{} } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"cosmossdk.io/log" | ||
) | ||
|
||
func TestVersionCommand_Error(t *testing.T) { | ||
logger := log.NewTestLogger(t).With(log.ModuleKey, "cosmovisor") | ||
|
||
rootCmd := NewRootCmd() | ||
Check failure on line 16 in tools/cosmovisor/cmd/cosmovisor/version_test.go GitHub Actions / tests (02)
|
||
rootCmd.SetArgs([]string{"version"}) | ||
|
||
out := bytes.NewBufferString("") | ||
rootCmd.SetOut(out) | ||
rootCmd.SetErr(out) | ||
|
||
ctx := context.WithValue(context.Background(), log.ContextKey, logger) //nolint:staticcheck // temporary issue in dependency | ||
|
||
require.Error(t, rootCmd.ExecuteContext(ctx)) | ||
require.Contains(t, out.String(), "DAEMON_NAME is not set") | ||
} |