-
Notifications
You must be signed in to change notification settings - Fork 787
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Logging overhaul #4375
Logging overhaul #4375
Conversation
std::cout << initialization_text << std::endl; | ||
logger.always_log (initialization_text); | ||
// This avoids a blank prompt during any node initialization delays | ||
logger.info (nano::log::type::daemon, "Starting up Nano node..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep these startup messages as std::cout to make sure the initialization process is shown in the console even when configured for file logging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe if someone explicitly wants to disable console output for whatever reason then we should not print anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments are mostly minor or subtle behaviour changes I noticed that don't need changing.
I was wondering about the performance since previously we short-circuited log message construction with a boolean check before constructing the actual message. I see that the spdlog library implementation forwards all of the log message arguments and checks if that particular logger is enabled before constructing the log message so I don't see this as a problem.
Very nice overhaul.
nano/lib/config.cpp
Outdated
}; | ||
|
||
// First try to load config from the current working directory, then from the node data directory | ||
if (auto toml = try_load_toml (config_filename); toml) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "; toml" isn't needed as the assignment expression will yield the assigned value
@@ -404,4 +408,28 @@ bool is_sanitizer_build (); | |||
|
|||
/** Set the active network to the dev network */ | |||
void force_nano_dev_network (); | |||
|
|||
/** | |||
* Attempt to read a configuration file from specified directory. Returns empty tomlconfig if nothing is found. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it returns a file containing the overrides, if overrides are specified.
|
||
enum class type | ||
{ | ||
all = 0, // reserved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment to explain what happens when someone sets the "all" log type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It currently functions as every other logger type. The all
has a special meaning for details where it allows to specify verbosity of type::detail
logger separately from that for the whole type
. It's currently used for tracing to limit the amount of unnecessary noise.
bootstrap_legacy, | ||
}; | ||
|
||
enum class detail |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need an example of how a detail would be used.
else | ||
{ | ||
auto logger_type = logger_name.substr (0, pos); | ||
auto logger_detail = logger_name.substr (pos + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BUG: it should be: pos + 2
} | ||
catch (std::runtime_error const & ex) | ||
{ | ||
std::cerr << "Unable to load log config. Using defaults. Error: " << ex.what () << std::endl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errors with config-log.toml are generally ignored and the program simply prints a message on seder and continues. In order to achieve that, we have extra try/catch blocks than would be necessary if we simply said that any log config errors will cause the program terminate. Why not follow the simplest approach of terminating the program if the log config has a problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log types and details change often during development and experimentation phase. Terminating when any error is encountered is just a bad user experience. And logging is not critical to proper node function.
@@ -171,6 +171,19 @@ class tomlconfig : public nano::configbase | |||
return *this; | |||
} | |||
|
|||
template <typename T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a comment explaining what this functions does.
For example, what happens to non-string entries in the log file?
@@ -60,15 +63,6 @@ void nano::remove_temporary_directories () | |||
{ | |||
std::cerr << "Could not remove temporary directory: " << ec.message () << std::endl; | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a serious change of behaviour and not a logging change.
I personally agree with the change but it should not had been part of the logging PR because this affects node operators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain how this affects node operators? I only saw this function used in unit testing. Generally there was badly implemented code, fixing badly implemented code that culminated in some strange bugs when I needed to ensure orderly node initialization.
…o th elogging overhaul in nanocurrency#4375
@@ -25,13 +26,18 @@ | |||
|
|||
namespace | |||
{ | |||
nano::logger logger{ "wallet_daemon" }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in #4679 this runs before main
and breaks the assertion
nano::logger::logger (std::string identifier) :
identifier{ std::move (identifier) }
{
release_assert (global_initialized, "logging should be initialized before creating a logger");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'm surprised this works on develop. I will look into it, thanks!
This pull request improves the logging functionality of the codebase. The new logger class aims to simplify the logging process and make it more consistent. The new logger class is using
spdlog
library under the hood andfmt
library for formatting, with format string syntax compatible with C++20std::format
.Out of the box, the interface presented to node administrators should be clearer and more intuitive. Each log line is categorized by node component with color coding for different log levels. The output can be configured to be written to a file, with automatic rotation and size limit. The default verbosity when running node in daemon mode is
info
.Configuration
There are two ways to configure the logger. The first is to use
config-log.toml
file, which is located in the data directory alongside other configuration files. The second is to useNANO_LOG
andNANO_LOG_LEVELS
environment variables. The environment variables take precedence over the configuration file.Configuration File
config-log.toml
During normal node operation, the configuration file is loaded from the data directory. When running testsuites, the configuration is loaded from current working directory.
Environment Variables
Envionment variables override the configuration file. This is useful when running testsuites.
Unit tests
By default, the logger is disabled when running unit tests to keep the output clean. To enable it, set
NANO_LOG
environment variable to a desired log level.In testsuite mode, each logline additionally contains the identifier of the node that produced the logline (first 10 characters of its node ID). This makes it easier to follow the flow of events and will become much more useful once full tracing is implemented.
Future Work
Originaly, the plan was to include both logging and tracing functionality in this pull request. However, since the amount of changes is already quite large, I decided to split the work into two pull requests. There might be some previous logging calls that were not converted to the new logger class and those should be converted into tracing calls.
I also plan to allow log calls to be divided into different categories, so that the node administrators can configure the verbosity of each category that can span multiple components.