config: add log encoding option

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2025-03-21 18:00:04 +03:00
parent 3cfba1bde4
commit 83e138000b
6 changed files with 107 additions and 51 deletions

View file

@ -296,6 +296,7 @@ var (
func HandleLoggingParams(ctx *cli.Context, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
var (
level = zapcore.InfoLevel
encoding = "console"
err error
)
if len(cfg.LogLevel) > 0 {
@ -304,6 +305,9 @@ func HandleLoggingParams(ctx *cli.Context, cfg config.ApplicationConfiguration)
return nil, nil, nil, fmt.Errorf("log setting: %w", err)
}
}
if len(cfg.LogEncoding) > 0 {
encoding = cfg.LogEncoding
}
if ctx != nil && ctx.Bool("debug") {
level = zapcore.DebugLevel
}
@ -318,7 +322,7 @@ func HandleLoggingParams(ctx *cli.Context, cfg config.ApplicationConfiguration)
} else {
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
}
cc.Encoding = "console"
cc.Encoding = encoding
cc.Level = zap.NewAtomicLevelAt(level)
cc.Sampling = nil

View file

@ -96,7 +96,9 @@ func TestHandleLoggingParams(t *testing.T) {
logfile := filepath.Join(d, "logdir")
require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
cfg := config.ApplicationConfiguration{
Logger: config.Logger{
LogPath: filepath.Join(logfile, "file.log"),
},
}
_, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.Error(t, err)
@ -106,8 +108,10 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("broken level", func(t *testing.T) {
cfg := config.ApplicationConfiguration{
Logger: config.Logger{
LogPath: testLog,
LogLevel: "qwerty",
},
}
_, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.Error(t, err)
@ -117,7 +121,9 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("default", func(t *testing.T) {
cfg := config.ApplicationConfiguration{
Logger: config.Logger{
LogPath: testLog,
},
}
logger, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.NotNil(t, lvl)
@ -134,8 +140,10 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("warn", func(t *testing.T) {
cfg := config.ApplicationConfiguration{
Logger: config.Logger{
LogPath: testLog,
LogLevel: "warn",
},
}
logger, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.NoError(t, err)
@ -151,7 +159,9 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("debug", func(t *testing.T) {
cfg := config.ApplicationConfiguration{
Logger: config.Logger{
LogPath: testLog,
},
}
*debug = true
t.Cleanup(func() { *debug = false })

View file

@ -17,6 +17,7 @@ node-related settings described in the table below.
| Section | Type | Default value | Description |
| --- | --- | --- | --- |
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
| LogEncoding | `string` | "console" | Logs output format (can be "console" or "json"). |
| LogLevel | `string` | "info" | Minimal logged messages level (can be "debug", "info", "warn", "error", "dpanic", "panic" or "fatal"). |
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead (it requires going through the whole DB which can take minutes), doing it too rarely will leave more useless data in the DB. Always compare this to `MaxTraceableBlocks`, values lower than 10% of it are likely too low, values higher than 50% are likely to leave more garbage than is possible to collect. The default value is more aligned with NeoFS networks that have low MTB values, but for N3 mainnet it's too low. |
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExchangeExtensions` section in the ProtocolConfiguration for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | |

View file

@ -15,8 +15,7 @@ type ApplicationConfiguration struct {
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
LogLevel string `yaml:"LogLevel"`
LogPath string `yaml:"LogPath"`
Logger `yaml:",inline"`
P2P P2P `yaml:"P2P"`
@ -153,5 +152,8 @@ func (a *ApplicationConfiguration) Validate() error {
if err := a.RPC.Validate(); err != nil {
return fmt.Errorf("invalid RPC config: %w", err)
}
if err := a.Logger.Validate(); err != nil {
return fmt.Errorf("invalid logger config: %w", err)
}
return nil
}

View file

@ -135,9 +135,9 @@ func TestGetAddresses(t *testing.T) {
}
}
func TestNeoFSBlockFetcherValidation(t *testing.T) {
func TestApplicationConfiguration_Validate(t *testing.T) {
type testcase struct {
cfg NeoFSBlockFetcher
cfg ApplicationConfiguration
shouldFail bool
errMsg string
}
@ -146,7 +146,8 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
cases := []testcase{
{
cfg: NeoFSBlockFetcher{
cfg: ApplicationConfiguration{
NeoFSBlockFetcher: NeoFSBlockFetcher{
InternalService: InternalService{Enabled: true},
Timeout: time.Second,
ContainerID: validContainerID,
@ -156,10 +157,12 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
SkipIndexFilesSearch: true,
DownloaderWorkersCount: 4,
},
},
shouldFail: false,
},
{
cfg: NeoFSBlockFetcher{
cfg: ApplicationConfiguration{
NeoFSBlockFetcher: NeoFSBlockFetcher{
InternalService: InternalService{Enabled: true},
Timeout: time.Second,
ContainerID: "",
@ -167,11 +170,13 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
OIDBatchSize: 10,
BQueueSize: 20,
},
},
shouldFail: true,
errMsg: "container ID is not set",
},
{
cfg: NeoFSBlockFetcher{
cfg: ApplicationConfiguration{
NeoFSBlockFetcher: NeoFSBlockFetcher{
InternalService: InternalService{Enabled: true},
Timeout: time.Second,
ContainerID: invalidContainerID,
@ -179,11 +184,13 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
OIDBatchSize: 10,
BQueueSize: 20,
},
},
shouldFail: true,
errMsg: "invalid container ID",
},
{
cfg: NeoFSBlockFetcher{
cfg: ApplicationConfiguration{
NeoFSBlockFetcher: NeoFSBlockFetcher{
InternalService: InternalService{Enabled: true},
Timeout: time.Second,
ContainerID: validContainerID,
@ -191,11 +198,13 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
OIDBatchSize: 10,
BQueueSize: 20,
},
},
shouldFail: true,
errMsg: "addresses are not set",
},
{
cfg: NeoFSBlockFetcher{
cfg: ApplicationConfiguration{
NeoFSBlockFetcher: NeoFSBlockFetcher{
InternalService: InternalService{Enabled: true},
Timeout: time.Second,
ContainerID: validContainerID,
@ -203,9 +212,19 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
OIDBatchSize: 10,
BQueueSize: 5,
},
},
shouldFail: true,
errMsg: "BQueueSize (5) is lower than OIDBatchSize (10)",
},
{
cfg: ApplicationConfiguration{
Logger: Logger{
LogEncoding: "unknown",
},
},
shouldFail: true,
errMsg: "invalid logger config: invalid LogEncoding: unknown",
},
}
for _, c := range cases {

20
pkg/config/logger.go Normal file
View file

@ -0,0 +1,20 @@
package config
import (
"fmt"
)
// Logger contains node logger configuration.
type Logger struct {
LogEncoding string `yaml:"LogEncoding"`
LogLevel string `yaml:"LogLevel"`
LogPath string `yaml:"LogPath"`
}
// Validate returns an error if Logger configuration is not valid.
func (l Logger) Validate() error {
if len(l.LogEncoding) > 0 && l.LogEncoding != "console" && l.LogEncoding != "json" {
return fmt.Errorf("invalid LogEncoding: %s", l.LogEncoding)
}
return nil
}