diff --git a/nano/core_test/toml.cpp b/nano/core_test/toml.cpp index 76de566d0..c61537946 100644 --- a/nano/core_test/toml.cpp +++ b/nano/core_test/toml.cpp @@ -202,6 +202,7 @@ TEST (toml, daemon_config_deserialize_defaults) ASSERT_EQ (conf.node.logging.network_telemetry_logging_value, defaults.node.logging.network_telemetry_logging_value); ASSERT_EQ (conf.node.logging.rotation_size, defaults.node.logging.rotation_size); ASSERT_EQ (conf.node.logging.single_line_record_value, defaults.node.logging.single_line_record_value); + ASSERT_EQ (conf.node.logging.stable_log_filename, defaults.node.logging.stable_log_filename); ASSERT_EQ (conf.node.logging.timing_logging_value, defaults.node.logging.timing_logging_value); ASSERT_EQ (conf.node.logging.active_update_value, defaults.node.logging.active_update_value); ASSERT_EQ (conf.node.logging.upnp_details_logging_value, defaults.node.logging.upnp_details_logging_value); @@ -467,6 +468,7 @@ TEST (toml, daemon_config_deserialize_no_defaults) node_lifetime_tracing = true rotation_size = 999 single_line_record = true + stable_log_filename = true timing = true active_update = true upnp_details = true @@ -598,6 +600,7 @@ TEST (toml, daemon_config_deserialize_no_defaults) ASSERT_NE (conf.node.logging.node_lifetime_tracing_value, defaults.node.logging.node_lifetime_tracing_value); ASSERT_NE (conf.node.logging.rotation_size, defaults.node.logging.rotation_size); ASSERT_NE (conf.node.logging.single_line_record_value, defaults.node.logging.single_line_record_value); + ASSERT_NE (conf.node.logging.stable_log_filename, defaults.node.logging.stable_log_filename); ASSERT_NE (conf.node.logging.timing_logging_value, defaults.node.logging.timing_logging_value); ASSERT_NE (conf.node.logging.active_update_value, defaults.node.logging.active_update_value); ASSERT_NE (conf.node.logging.upnp_details_logging_value, defaults.node.logging.upnp_details_logging_value); diff --git a/nano/node/logging.cpp b/nano/node/logging.cpp index 17f756f4c..bc6802cfd 100644 --- a/nano/node/logging.cpp +++ b/nano/node/logging.cpp @@ -68,9 +68,48 @@ void nano::logging::init (boost::filesystem::path const & application_path_a) #endif } +//clang-format off +#if BOOST_VERSION < 107000 + if (stable_log_filename) + { + stable_log_filename = false; + std::cerr << "The stable_log_filename config setting is only available when building with Boost 1.70 or later. Reverting to old behavior." << std::endl; + } +#endif + auto path = application_path_a / "log"; - file_sink = boost::log::add_file_log (boost::log::keywords::target = path, boost::log::keywords::file_name = path / "log_%Y-%m-%d_%H-%M-%S.%N.log", boost::log::keywords::rotation_size = rotation_size, boost::log::keywords::auto_flush = flush, boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching, boost::log::keywords::max_size = max_size, boost::log::keywords::format = format_with_timestamp); + if (stable_log_filename) + { +#if BOOST_VERSION >= 107000 + // Logging to node.log and node_ instead of log_.log is deliberate. This way, + // existing log monitoring scripts expecting the old logfile structure will fail immediately instead + // of reading only rotated files with old entries. + file_sink = boost::log::add_file_log (boost::log::keywords::target = path, + boost::log::keywords::file_name = path / "node.log", + boost::log::keywords::target_file_name = path / "node_%Y-%m-%d_%H-%M-%S.%N.log", + boost::log::keywords::open_mode = std::ios_base::out | std::ios_base::app, // append to node.log if it exists + boost::log::keywords::enable_final_rotation = false, // for stable log filenames, don't rotate on destruction + boost::log::keywords::rotation_size = rotation_size, // max file size in bytes before rotation + boost::log::keywords::auto_flush = flush, + boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching, + boost::log::keywords::max_size = max_size, // max total size in bytes of all log files + boost::log::keywords::format = format_with_timestamp); +#else + assert (false); +#endif + } + else + { + file_sink = boost::log::add_file_log (boost::log::keywords::target = path, + boost::log::keywords::file_name = path / "log_%Y-%m-%d_%H-%M-%S.%N.log", + boost::log::keywords::rotation_size = rotation_size, + boost::log::keywords::auto_flush = flush, + boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching, + boost::log::keywords::max_size = max_size, + boost::log::keywords::format = format_with_timestamp); + } } + //clang-format on } void nano::logging::release_file_sink () @@ -109,6 +148,7 @@ nano::error nano::logging::serialize_toml (nano::tomlconfig & toml) const toml.put ("flush", flush, "If enabled, immediately flush new entries to log file.\nWarning: this may negatively affect logging performance.\ntype:bool"); toml.put ("min_time_between_output", min_time_between_log_output.count (), "Minimum time that must pass for low priority entries to be logged.\nWarning: decreasing this value may result in a very large amount of logs.\ntype:milliseconds"); toml.put ("single_line_record", single_line_record_value, "Keep log entries on single lines.\ntype:bool"); + toml.put ("stable_log_filename", stable_log_filename, "Append to log/node.log without a timestamp in the filename.\nThe file is not emptied on startup if it exists, but appended to.\ntype:bool"); return toml.get_error (); } @@ -142,6 +182,7 @@ nano::error nano::logging::deserialize_toml (nano::tomlconfig & toml) auto min_time_between_log_output_l = min_time_between_log_output.count (); toml.get ("min_time_between_output", min_time_between_log_output_l); min_time_between_log_output = std::chrono::milliseconds (min_time_between_log_output_l); + toml.get ("stable_log_filename", stable_log_filename); return toml.get_error (); } diff --git a/nano/node/logging.hpp b/nano/node/logging.hpp index 61dcec5e0..e42a7aba5 100644 --- a/nano/node/logging.hpp +++ b/nano/node/logging.hpp @@ -89,6 +89,7 @@ public: bool flush{ true }; uintmax_t max_size{ 128 * 1024 * 1024 }; uintmax_t rotation_size{ 4 * 1024 * 1024 }; + bool stable_log_filename{ false }; std::chrono::milliseconds min_time_between_log_output{ 5 }; bool single_line_record_value{ false }; static void release_file_sink ();