Merge pull request #3846 from nspcc-dev/ignore-tty

This commit is contained in:
Roman Khimov 2025-03-26 09:28:55 +03:00 committed by GitHub
commit 42beabcde0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 155 additions and 81 deletions

View file

@ -14,7 +14,7 @@ services:
node_one: node_one:
container_name: neo_go_node_one container_name: neo_go_node_one
image: env_neo_go_image image: env_neo_go_image
command: "node --config-path /config --privnet" command: "node --config-path /config --privnet --force-timestamp-logs"
volumes: volumes:
- ../config/protocol.privnet.docker.one.yml:/config/protocol.privnet.yml - ../config/protocol.privnet.docker.one.yml:/config/protocol.privnet.yml
- ./wallets/wallet1.json:/wallet1.json - ./wallets/wallet1.json:/wallet1.json
@ -26,7 +26,7 @@ services:
node_two: node_two:
container_name: neo_go_node_two container_name: neo_go_node_two
image: env_neo_go_image image: env_neo_go_image
command: "node --config-path /config --privnet" command: "node --config-path /config --privnet --force-timestamp-logs"
volumes: volumes:
- ../config/protocol.privnet.docker.two.yml:/config/protocol.privnet.yml - ../config/protocol.privnet.docker.two.yml:/config/protocol.privnet.yml
- ./wallets/wallet2.json:/wallet2.json - ./wallets/wallet2.json:/wallet2.json
@ -38,7 +38,7 @@ services:
node_three: node_three:
container_name: neo_go_node_three container_name: neo_go_node_three
image: env_neo_go_image image: env_neo_go_image
command: "node --config-path /config --privnet" command: "node --config-path /config --privnet --force-timestamp-logs"
volumes: volumes:
- ../config/protocol.privnet.docker.three.yml:/config/protocol.privnet.yml - ../config/protocol.privnet.docker.three.yml:/config/protocol.privnet.yml
- ./wallets/wallet3.json:/wallet3.json - ./wallets/wallet3.json:/wallet3.json
@ -50,7 +50,7 @@ services:
node_four: node_four:
container_name: neo_go_node_four container_name: neo_go_node_four
image: env_neo_go_image image: env_neo_go_image
command: "node --config-path /config --privnet" command: "node --config-path /config --privnet --force-timestamp-logs"
volumes: volumes:
- ../config/protocol.privnet.docker.four.yml:/config/protocol.privnet.yml - ../config/protocol.privnet.docker.four.yml:/config/protocol.privnet.yml
- ./wallets/wallet4.json:/wallet4.json - ./wallets/wallet4.json:/wallet4.json
@ -62,7 +62,7 @@ services:
node_single: node_single:
container_name: neo_go_node_single container_name: neo_go_node_single
image: env_neo_go_image image: env_neo_go_image
command: "node --config-path /config --privnet" command: "node --config-path /config --privnet --force-timestamp-logs"
volumes: volumes:
- ../config/protocol.privnet.docker.single.yml:/config/protocol.privnet.yml - ../config/protocol.privnet.docker.single.yml:/config/protocol.privnet.yml
- ./wallets/wallet1_solo.json:/wallet1.json - ./wallets/wallet1_solo.json:/wallet1.json

View file

@ -157,6 +157,14 @@ var Debug = &cli.BoolFlag{
Usage: "Enable debug logging (LOTS of output, overrides configuration)", Usage: "Enable debug logging (LOTS of output, overrides configuration)",
} }
// ForceTimestampLogs is a flag for commands that run the node. This flag
// enables timestamp logging for every log record even if program is running
// not in terminal.
var ForceTimestampLogs = &cli.BoolFlag{
Name: "force-timestamp-logs",
Usage: "Enable timestamps for log entries",
}
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash") var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag") var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location") var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
@ -285,10 +293,11 @@ var (
// If logPath is configured on Windows -- function returns closer to be // If logPath is configured on Windows -- function returns closer to be
// able to close sink for the opened log output file. // able to close sink for the opened log output file.
// If the program is run in TTY then logger adds timestamp to its entries. // If the program is run in TTY then logger adds timestamp to its entries.
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) { func HandleLoggingParams(ctx *cli.Context, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
var ( var (
level = zapcore.InfoLevel level = zapcore.InfoLevel
err error encoding = "console"
err error
) )
if len(cfg.LogLevel) > 0 { if len(cfg.LogLevel) > 0 {
level, err = zapcore.ParseLevel(cfg.LogLevel) level, err = zapcore.ParseLevel(cfg.LogLevel)
@ -296,7 +305,10 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
return nil, nil, nil, fmt.Errorf("log setting: %w", err) return nil, nil, nil, fmt.Errorf("log setting: %w", err)
} }
} }
if debug { if len(cfg.LogEncoding) > 0 {
encoding = cfg.LogEncoding
}
if ctx != nil && ctx.Bool("debug") {
level = zapcore.DebugLevel level = zapcore.DebugLevel
} }
@ -305,12 +317,14 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
cc.DisableStacktrace = true cc.DisableStacktrace = true
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
if term.IsTerminal(int(os.Stdout.Fd())) { if cfg.LogTimestamp == nil && term.IsTerminal(int(os.Stdout.Fd())) ||
cfg.LogTimestamp != nil && *cfg.LogTimestamp ||
ctx != nil && ctx.Bool("force-timestamp-logs") {
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
} else { } else {
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {} cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
} }
cc.Encoding = "console" cc.Encoding = encoding
cc.Level = zap.NewAtomicLevelAt(level) cc.Level = zap.NewAtomicLevelAt(level)
cc.Sampling = nil cc.Sampling = nil

View file

@ -20,7 +20,7 @@ func dumpBin(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }

View file

@ -39,7 +39,7 @@ func NewCommands() []*cli.Command {
cfgFlags = append(cfgFlags, options.Network...) cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = slices.Clone(cfgFlags) var cfgWithCountFlags = slices.Clone(cfgFlags)
cfgFlags = append(cfgFlags, options.Debug) cfgFlags = append(cfgFlags, options.Debug, options.ForceTimestampLogs)
cfgWithCountFlags = append(cfgWithCountFlags, cfgWithCountFlags = append(cfgWithCountFlags,
&cli.UintFlag{ &cli.UintFlag{
Name: "count", Name: "count",
@ -87,7 +87,7 @@ func NewCommands() []*cli.Command {
{ {
Name: "node", Name: "node",
Usage: "Start a NeoGo node", Usage: "Start a NeoGo node",
UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file]", UsageText: "neo-go node [--config-path path] [-d] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: startServer, Action: startServer,
Flags: cfgFlags, Flags: cfgFlags,
}, },
@ -98,28 +98,28 @@ func NewCommands() []*cli.Command {
{ {
Name: "dump", Name: "dump",
Usage: "Dump blocks (starting with the genesis or specified block) to the file", Usage: "Dump blocks (starting with the genesis or specified block) to the file",
UsageText: "neo-go db dump [-o file] [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db dump [-o file] [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: dumpDB, Action: dumpDB,
Flags: cfgCountOutFlags, Flags: cfgCountOutFlags,
}, },
{ {
Name: "dump-bin", Name: "dump-bin",
Usage: "Dump blocks (starting with the genesis or specified block) to the directory in binary format", Usage: "Dump blocks (starting with the genesis or specified block) to the directory in binary format",
UsageText: "neo-go db dump-bin -o directory [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db dump-bin -o directory [-s start] [-c count] [--config-path path] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: dumpBin, Action: dumpBin,
Flags: cfgCountOutFlags, Flags: cfgCountOutFlags,
}, },
{ {
Name: "restore", Name: "restore",
Usage: "Restore blocks from the file", Usage: "Restore blocks from the file",
UsageText: "neo-go db restore [-i file] [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db restore [-i file] [--dump] [-n] [-c count] [--config-path path] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: restoreDB, Action: restoreDB,
Flags: cfgCountInFlags, Flags: cfgCountInFlags,
}, },
{ {
Name: "reset", Name: "reset",
Usage: "Reset database to the previous state", Usage: "Reset database to the previous state",
UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go db reset --height height [--config-path path] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: resetDB, Action: resetDB,
Flags: cfgHeightFlags, Flags: cfgHeightFlags,
}, },
@ -170,7 +170,7 @@ func dumpDB(ctx *cli.Context) error {
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
@ -226,7 +226,7 @@ func restoreDB(ctx *cli.Context) error {
if err != nil { if err != nil {
return err return err
} }
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
@ -345,7 +345,7 @@ func resetDB(ctx *cli.Context) error {
} }
h := uint32(ctx.Uint("height")) h := uint32(ctx.Uint("height"))
log, _, logCloser, err := options.HandleLoggingParams(ctx.Bool("debug"), cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
@ -455,7 +455,7 @@ func startServer(ctx *cli.Context) error {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
var logDebug = ctx.Bool("debug") var logDebug = ctx.Bool("debug")
log, logLevel, logCloser, err := options.HandleLoggingParams(logDebug, cfg.ApplicationConfiguration) log, logLevel, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }

View file

@ -88,14 +88,19 @@ func TestGetConfigFromContext(t *testing.T) {
func TestHandleLoggingParams(t *testing.T) { func TestHandleLoggingParams(t *testing.T) {
d := t.TempDir() d := t.TempDir()
testLog := filepath.Join(d, "file.log") testLog := filepath.Join(d, "file.log")
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
debug := set.Bool("debug", false, "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
t.Run("logdir is a file", func(t *testing.T) { t.Run("logdir is a file", func(t *testing.T) {
logfile := filepath.Join(d, "logdir") logfile := filepath.Join(d, "logdir")
require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm)) require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
cfg := config.ApplicationConfiguration{ cfg := config.ApplicationConfiguration{
LogPath: filepath.Join(logfile, "file.log"), Logger: config.Logger{
LogPath: filepath.Join(logfile, "file.log"),
},
} }
_, lvl, closer, err := options.HandleLoggingParams(false, cfg) _, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.Error(t, err) require.Error(t, err)
require.Nil(t, lvl) require.Nil(t, lvl)
require.Nil(t, closer) require.Nil(t, closer)
@ -103,10 +108,12 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("broken level", func(t *testing.T) { t.Run("broken level", func(t *testing.T) {
cfg := config.ApplicationConfiguration{ cfg := config.ApplicationConfiguration{
LogPath: testLog, Logger: config.Logger{
LogLevel: "qwerty", LogPath: testLog,
LogLevel: "qwerty",
},
} }
_, lvl, closer, err := options.HandleLoggingParams(false, cfg) _, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.Error(t, err) require.Error(t, err)
require.Nil(t, lvl) require.Nil(t, lvl)
require.Nil(t, closer) require.Nil(t, closer)
@ -114,9 +121,11 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("default", func(t *testing.T) { t.Run("default", func(t *testing.T) {
cfg := config.ApplicationConfiguration{ cfg := config.ApplicationConfiguration{
LogPath: testLog, Logger: config.Logger{
LogPath: testLog,
},
} }
logger, lvl, closer, err := options.HandleLoggingParams(false, cfg) logger, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.NotNil(t, lvl) require.NotNil(t, lvl)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
@ -131,10 +140,12 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("warn", func(t *testing.T) { t.Run("warn", func(t *testing.T) {
cfg := config.ApplicationConfiguration{ cfg := config.ApplicationConfiguration{
LogPath: testLog, Logger: config.Logger{
LogLevel: "warn", LogPath: testLog,
LogLevel: "warn",
},
} }
logger, lvl, closer, err := options.HandleLoggingParams(false, cfg) logger, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
if closer != nil { if closer != nil {
@ -148,9 +159,13 @@ func TestHandleLoggingParams(t *testing.T) {
t.Run("debug", func(t *testing.T) { t.Run("debug", func(t *testing.T) {
cfg := config.ApplicationConfiguration{ cfg := config.ApplicationConfiguration{
LogPath: testLog, Logger: config.Logger{
LogPath: testLog,
},
} }
logger, lvl, closer, err := options.HandleLoggingParams(true, cfg) *debug = true
t.Cleanup(func() { *debug = false })
logger, lvl, closer, err := options.HandleLoggingParams(ctx, cfg)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
if closer != nil { if closer != nil {
@ -176,7 +191,7 @@ func TestInitBCWithMetrics(t *testing.T) {
ctx := cli.NewContext(cli.NewApp(), set, nil) ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx) cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err) require.NoError(t, err)
logger, _, closer, err := options.HandleLoggingParams(true, cfg.ApplicationConfiguration) logger, _, closer, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
require.NoError(t, err) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
if closer != nil { if closer != nil {

View file

@ -87,6 +87,7 @@ func NewCommands() []*cli.Command {
Value: 20, Value: 20,
}, },
options.Debug, options.Debug,
options.ForceTimestampLogs,
}, options.RPC...) }, options.RPC...)
uploadBinFlags = append(uploadBinFlags, options.Wallet...) uploadBinFlags = append(uploadBinFlags, options.Wallet...)
uploadBinFlags = append(uploadBinFlags, neoFSFlags...) uploadBinFlags = append(uploadBinFlags, neoFSFlags...)
@ -98,7 +99,7 @@ func NewCommands() []*cli.Command {
Value: neofs.DefaultStateAttribute, Value: neofs.DefaultStateAttribute,
Action: cmdargs.EnsureNotEmpty("state-attribute"), Action: cmdargs.EnsureNotEmpty("state-attribute"),
}, },
options.Debug, options.Config, options.ConfigFile, options.RelativePath, options.Debug, options.ForceTimestampLogs, options.Config, options.ConfigFile, options.RelativePath,
}, options.Wallet...) }, options.Wallet...)
uploadStateFlags = append(uploadStateFlags, options.Network...) uploadStateFlags = append(uploadStateFlags, options.Network...)
uploadStateFlags = append(uploadStateFlags, neoFSFlags...) uploadStateFlags = append(uploadStateFlags, neoFSFlags...)
@ -189,7 +190,7 @@ func NewCommands() []*cli.Command {
{ {
Name: "upload-state", Name: "upload-state",
Usage: "Start the node, traverse MPT and upload MPT nodes to the NeoFS container at every StateSyncInterval number of blocks", Usage: "Start the node, traverse MPT and upload MPT nodes to the NeoFS container at every StateSyncInterval number of blocks",
UsageText: "neo-go util upload-state --fs-rpc-endpoint <address1>[,<address2>[...]] --container <cid> --state-attribute state --wallet <wallet> [--wallet-config <config>] [--address <address>] [--searchers <num>] [--retries <num>] [--debug] [--config-path path] [-p/-m/-t] [--config-file file]", UsageText: "neo-go util upload-state --fs-rpc-endpoint <address1>[,<address2>[...]] --container <cid> --state-attribute state --wallet <wallet> [--wallet-config <config>] [--address <address>] [--searchers <num>] [--retries <num>] [--debug] [--config-path path] [-p/-m/-t] [--config-file file] [--force-timestamp-logs]",
Action: uploadState, Action: uploadState,
Flags: uploadStateFlags, Flags: uploadStateFlags,
}, },

View file

@ -45,7 +45,7 @@ func uploadState(ctx *cli.Context) error {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }
defer p.Close() defer p.Close()
log, _, logCloser, err := options.HandleLoggingParams(debug, cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(ctx, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return cli.Exit(err, 1) return cli.Exit(err, 1)
} }

View file

@ -480,7 +480,7 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg
store = storage.NewMemoryStore() store = storage.NewMemoryStore()
} }
log, _, logCloser, err := options.HandleLoggingParams(false, cfg.ApplicationConfiguration) log, _, logCloser, err := options.HandleLoggingParams(nil, cfg.ApplicationConfiguration)
if err != nil { if err != nil {
return nil, cli.Exit(fmt.Errorf("failed to init logger: %w", err), 1) return nil, cli.Exit(fmt.Errorf("failed to init logger: %w", err), 1)
} }

View file

@ -17,10 +17,12 @@ node-related settings described in the table below.
| Section | Type | Default value | Description | | Section | Type | Default value | Description |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. | | DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
| 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. | | 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. | | | 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. | |
| 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"). |
| LogPath | `string` | "", so only console logging | File path where to store node logs. | | LogPath | `string` | "", so only console logging | File path where to store node logs. |
| LogTimestamp | `bool` | Defined by TTY probe on stdout channel. | Defines whether to enable timestamp logging. If not set, then timestamp logging enabled iff the program is running in TTY (but this behaviour may be overriden by `--force-timestamp-logs` CLI flag if specified). Note that this option, if combined with `LogEncoding: "json"`, can't completely disable timestamp logging. |
| NeoFSBlockFetcher | [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) | | NeoFS BlockFetcher module configuration. See the [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) section for details. | | NeoFSBlockFetcher | [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) | | NeoFS BlockFetcher module configuration. See the [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) section for details. |
| Oracle | [Oracle Configuration](#Oracle-Configuration) | | Oracle module configuration. See the [Oracle Configuration](#Oracle-Configuration) section for details. | | Oracle | [Oracle Configuration](#Oracle-Configuration) | | Oracle module configuration. See the [Oracle Configuration](#Oracle-Configuration) section for details. |
| P2P | [P2P Configuration](#P2P-Configuration) | | Configuration values for P2P network interaction. See the [P2P Configuration](#P2P-Configuration) section for details. | | P2P | [P2P Configuration](#P2P-Configuration) | | Configuration values for P2P network interaction. See the [P2P Configuration](#P2P-Configuration) section for details. |

View file

@ -15,8 +15,7 @@ type ApplicationConfiguration struct {
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"` DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
LogLevel string `yaml:"LogLevel"` Logger `yaml:",inline"`
LogPath string `yaml:"LogPath"`
P2P P2P `yaml:"P2P"` P2P P2P `yaml:"P2P"`
@ -153,5 +152,8 @@ func (a *ApplicationConfiguration) Validate() error {
if err := a.RPC.Validate(); err != nil { if err := a.RPC.Validate(); err != nil {
return fmt.Errorf("invalid RPC config: %w", err) 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 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 { type testcase struct {
cfg NeoFSBlockFetcher cfg ApplicationConfiguration
shouldFail bool shouldFail bool
errMsg string errMsg string
} }
@ -146,66 +146,85 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
cases := []testcase{ cases := []testcase{
{ {
cfg: NeoFSBlockFetcher{ cfg: ApplicationConfiguration{
InternalService: InternalService{Enabled: true}, NeoFSBlockFetcher: NeoFSBlockFetcher{
Timeout: time.Second, InternalService: InternalService{Enabled: true},
ContainerID: validContainerID, Timeout: time.Second,
Addresses: []string{"127.0.0.1"}, ContainerID: validContainerID,
OIDBatchSize: 10, Addresses: []string{"127.0.0.1"},
BQueueSize: 20, OIDBatchSize: 10,
SkipIndexFilesSearch: true, BQueueSize: 20,
DownloaderWorkersCount: 4, SkipIndexFilesSearch: true,
DownloaderWorkersCount: 4,
},
}, },
shouldFail: false, shouldFail: false,
}, },
{ {
cfg: NeoFSBlockFetcher{ cfg: ApplicationConfiguration{
InternalService: InternalService{Enabled: true}, NeoFSBlockFetcher: NeoFSBlockFetcher{
Timeout: time.Second, InternalService: InternalService{Enabled: true},
ContainerID: "", Timeout: time.Second,
Addresses: []string{"127.0.0.1"}, ContainerID: "",
OIDBatchSize: 10, Addresses: []string{"127.0.0.1"},
BQueueSize: 20, OIDBatchSize: 10,
BQueueSize: 20,
},
}, },
shouldFail: true, shouldFail: true,
errMsg: "container ID is not set", errMsg: "container ID is not set",
}, },
{ {
cfg: NeoFSBlockFetcher{ cfg: ApplicationConfiguration{
InternalService: InternalService{Enabled: true}, NeoFSBlockFetcher: NeoFSBlockFetcher{
Timeout: time.Second, InternalService: InternalService{Enabled: true},
ContainerID: invalidContainerID, Timeout: time.Second,
Addresses: []string{"127.0.0.1"}, ContainerID: invalidContainerID,
OIDBatchSize: 10, Addresses: []string{"127.0.0.1"},
BQueueSize: 20, OIDBatchSize: 10,
BQueueSize: 20,
},
}, },
shouldFail: true, shouldFail: true,
errMsg: "invalid container ID", errMsg: "invalid container ID",
}, },
{ {
cfg: NeoFSBlockFetcher{ cfg: ApplicationConfiguration{
InternalService: InternalService{Enabled: true}, NeoFSBlockFetcher: NeoFSBlockFetcher{
Timeout: time.Second, InternalService: InternalService{Enabled: true},
ContainerID: validContainerID, Timeout: time.Second,
Addresses: []string{}, ContainerID: validContainerID,
OIDBatchSize: 10, Addresses: []string{},
BQueueSize: 20, OIDBatchSize: 10,
BQueueSize: 20,
},
}, },
shouldFail: true, shouldFail: true,
errMsg: "addresses are not set", errMsg: "addresses are not set",
}, },
{ {
cfg: NeoFSBlockFetcher{ cfg: ApplicationConfiguration{
InternalService: InternalService{Enabled: true}, NeoFSBlockFetcher: NeoFSBlockFetcher{
Timeout: time.Second, InternalService: InternalService{Enabled: true},
ContainerID: validContainerID, Timeout: time.Second,
Addresses: []string{"127.0.0.1"}, ContainerID: validContainerID,
OIDBatchSize: 10, Addresses: []string{"127.0.0.1"},
BQueueSize: 5, OIDBatchSize: 10,
BQueueSize: 5,
},
}, },
shouldFail: true, shouldFail: true,
errMsg: "BQueueSize (5) is lower than OIDBatchSize (10)", 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 { for _, c := range cases {

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

@ -0,0 +1,21 @@
package config
import (
"fmt"
)
// Logger contains node logger configuration.
type Logger struct {
LogEncoding string `yaml:"LogEncoding"`
LogLevel string `yaml:"LogLevel"`
LogPath string `yaml:"LogPath"`
LogTimestamp *bool `yaml:"LogTimestamp,omitempty"`
}
// 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
}