mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 11:32:46 +01:00
merge bitcoin#25614: Severity-based logging, step 2
This commit is contained in:
parent
21470fdeb3
commit
52a1263989
@ -390,8 +390,10 @@ Run configure with the `--enable-gprof` option, then make.
|
|||||||
If the code is behaving strangely, take a look in the `debug.log` file in the data directory;
|
If the code is behaving strangely, take a look in the `debug.log` file in the data directory;
|
||||||
error and debugging messages are written there.
|
error and debugging messages are written there.
|
||||||
|
|
||||||
The `-debug=...` command-line option controls debugging; running with just `-debug` or `-debug=1` will turn
|
Debug logging can be enabled on startup with the `-debug` and `-loglevel`
|
||||||
on all categories (and give you a very large `debug.log` file).
|
configuration options and toggled while dashd is running with the `logging`
|
||||||
|
RPC. For instance, launching dashd with `-debug` or `-debug=1` will turn on
|
||||||
|
all log categories and `-loglevel=trace` will turn on all log severity levels.
|
||||||
|
|
||||||
The Qt code routes `qDebug()` output to `debug.log` under category "qt": run with `-debug=qt`
|
The Qt code routes `qDebug()` output to `debug.log` under category "qt": run with `-debug=qt`
|
||||||
to see it.
|
to see it.
|
||||||
|
@ -1212,6 +1212,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
|||||||
|
|
||||||
// ********************************************************* Step 3: parameter-to-internal-flags
|
// ********************************************************* Step 3: parameter-to-internal-flags
|
||||||
init::SetLoggingCategories(args);
|
init::SetLoggingCategories(args);
|
||||||
|
init::SetLoggingLevel(args);
|
||||||
|
|
||||||
fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
|
fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks());
|
||||||
fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
|
fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <node/ui_interface.h>
|
#include <node/ui_interface.h>
|
||||||
#include <random.h>
|
#include <random.h>
|
||||||
|
#include <util/string.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
@ -57,11 +58,12 @@ bool SanityChecks()
|
|||||||
void AddLoggingArgs(ArgsManager& argsman)
|
void AddLoggingArgs(ArgsManager& argsman)
|
||||||
{
|
{
|
||||||
argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
argsman.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||||
argsman.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). "
|
argsman.AddArg("-debug=<category>", "Output debug and trace logging (default: -nodebug, supplying <category> is optional). "
|
||||||
"If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.",
|
"If <category> is not supplied or if <category> = 1, output all debug and trace logging. <category> can be: " + LogInstance().LogCategoriesString() + ". This option can be specified multiple times to output multiple categories.",
|
||||||
ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-debugexclude=<category>", "Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except the specified category. This option can be specified multiple times to exclude multiple categories.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-debugexclude=<category>", "Exclude debug and trace logging for a category. Can be used in conjunction with -debug=1 to output debug and trace logging for all categories except the specified category. This option can be specified multiple times to exclude multiple categories.", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
argsman.AddArg("-loglevel=<level>|<category>:<level>", strprintf("Set the global or per-category severity level for logging categories enabled with the -debug configuration option or the logging RPC: %s (default=%s); warning and error levels are always logged. If <category>:<level> is supplied, the setting will override the global one and may be specified multiple times to set multiple category-specific levels. <category> can be: %s.", LogInstance().LogLevelsString(), LogInstance().LogLevelToStr(BCLog::DEFAULT_LOG_LEVEL), LogInstance().LogCategoriesString()), ArgsManager::DISALLOW_NEGATION | ArgsManager::DISALLOW_ELISION | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
#ifdef HAVE_THREAD_LOCAL
|
#ifdef HAVE_THREAD_LOCAL
|
||||||
argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
@ -89,6 +91,26 @@ void SetLoggingOptions(const ArgsManager& args)
|
|||||||
fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
|
fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetLoggingLevel(const ArgsManager& args)
|
||||||
|
{
|
||||||
|
if (args.IsArgSet("-loglevel")) {
|
||||||
|
for (const std::string& level_str : args.GetArgs("-loglevel")) {
|
||||||
|
if (level_str.find_first_of(':', 3) == std::string::npos) {
|
||||||
|
// user passed a global log level, i.e. -loglevel=<level>
|
||||||
|
if (!LogInstance().SetLogLevel(level_str)) {
|
||||||
|
InitWarning(strprintf(_("Unsupported global logging level -loglevel=%s. Valid values: %s."), level_str, LogInstance().LogLevelsString()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// user passed a category-specific log level, i.e. -loglevel=<category>:<level>
|
||||||
|
const auto& toks = SplitString(level_str, ':');
|
||||||
|
if (!(toks.size() == 2 && LogInstance().SetCategoryLogLevel(toks[0], toks[1]))) {
|
||||||
|
InitWarning(strprintf(_("Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."), level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetLoggingCategories(const ArgsManager& args)
|
void SetLoggingCategories(const ArgsManager& args)
|
||||||
{
|
{
|
||||||
if (args.IsArgSet("-debug")) {
|
if (args.IsArgSet("-debug")) {
|
||||||
|
@ -21,6 +21,7 @@ bool SanityChecks();
|
|||||||
void AddLoggingArgs(ArgsManager& args);
|
void AddLoggingArgs(ArgsManager& args);
|
||||||
void SetLoggingOptions(const ArgsManager& args);
|
void SetLoggingOptions(const ArgsManager& args);
|
||||||
void SetLoggingCategories(const ArgsManager& args);
|
void SetLoggingCategories(const ArgsManager& args);
|
||||||
|
void SetLoggingLevel(const ArgsManager& args);
|
||||||
bool StartLogging(const ArgsManager& args);
|
bool StartLogging(const ArgsManager& args);
|
||||||
void LogPackageVersion();
|
void LogPackageVersion();
|
||||||
} // namespace init
|
} // namespace init
|
||||||
|
@ -5,15 +5,17 @@
|
|||||||
|
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
|
#include <util/string.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/threadnames.h>
|
#include <util/threadnames.h>
|
||||||
#include <util/string.h>
|
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
|
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
|
||||||
|
constexpr auto MAX_USER_SETABLE_SEVERITY_LEVEL{BCLog::Level::Info};
|
||||||
|
|
||||||
BCLog::Logger& LogInstance()
|
BCLog::Logger& LogInstance()
|
||||||
{
|
{
|
||||||
@ -122,6 +124,19 @@ bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
|
|||||||
return (m_categories.load(std::memory_order_relaxed) & category) != 0;
|
return (m_categories.load(std::memory_order_relaxed) & category) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BCLog::Logger::WillLogCategoryLevel(BCLog::LogFlags category, BCLog::Level level) const
|
||||||
|
{
|
||||||
|
// Log messages at Warning and Error level unconditionally, so that
|
||||||
|
// important troubleshooting information doesn't get lost.
|
||||||
|
if (level >= BCLog::Level::Warning) return true;
|
||||||
|
|
||||||
|
if (!WillLogCategory(category)) return false;
|
||||||
|
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
const auto it{m_category_log_levels.find(category)};
|
||||||
|
return level >= (it == m_category_log_levels.end() ? LogLevel() : it->second);
|
||||||
|
}
|
||||||
|
|
||||||
bool BCLog::Logger::DefaultShrinkDebugFile() const
|
bool BCLog::Logger::DefaultShrinkDebugFile() const
|
||||||
{
|
{
|
||||||
return m_categories == BCLog::NONE;
|
return m_categories == BCLog::NONE;
|
||||||
@ -135,7 +150,7 @@ struct CLogCategoryDesc {
|
|||||||
const CLogCategoryDesc LogCategories[] =
|
const CLogCategoryDesc LogCategories[] =
|
||||||
{
|
{
|
||||||
{BCLog::NONE, "0"},
|
{BCLog::NONE, "0"},
|
||||||
{BCLog::NONE, "none"},
|
{BCLog::NONE, ""},
|
||||||
{BCLog::NET, "net"},
|
{BCLog::NET, "net"},
|
||||||
{BCLog::TOR, "tor"},
|
{BCLog::TOR, "tor"},
|
||||||
{BCLog::MEMPOOL, "mempool"},
|
{BCLog::MEMPOOL, "mempool"},
|
||||||
@ -201,11 +216,11 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LogLevelToStr(BCLog::Level level)
|
std::string BCLog::Logger::LogLevelToStr(BCLog::Level level) const
|
||||||
{
|
{
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case BCLog::Level::None:
|
case BCLog::Level::Trace:
|
||||||
return "none";
|
return "trace";
|
||||||
case BCLog::Level::Debug:
|
case BCLog::Level::Debug:
|
||||||
return "debug";
|
return "debug";
|
||||||
case BCLog::Level::Info:
|
case BCLog::Level::Info:
|
||||||
@ -214,6 +229,8 @@ std::string LogLevelToStr(BCLog::Level level)
|
|||||||
return "warning";
|
return "warning";
|
||||||
case BCLog::Level::Error:
|
case BCLog::Level::Error:
|
||||||
return "error";
|
return "error";
|
||||||
|
case BCLog::Level::None:
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -223,7 +240,7 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
|
|||||||
// Each log category string representation should sync with LogCategories
|
// Each log category string representation should sync with LogCategories
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case BCLog::LogFlags::NONE:
|
case BCLog::LogFlags::NONE:
|
||||||
return "none";
|
return "";
|
||||||
case BCLog::LogFlags::NET:
|
case BCLog::LogFlags::NET:
|
||||||
return "net";
|
return "net";
|
||||||
case BCLog::LogFlags::TOR:
|
case BCLog::LogFlags::TOR:
|
||||||
@ -318,6 +335,25 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<BCLog::Level> GetLogLevel(const std::string& level_str)
|
||||||
|
{
|
||||||
|
if (level_str == "trace") {
|
||||||
|
return BCLog::Level::Trace;
|
||||||
|
} else if (level_str == "debug") {
|
||||||
|
return BCLog::Level::Debug;
|
||||||
|
} else if (level_str == "info") {
|
||||||
|
return BCLog::Level::Info;
|
||||||
|
} else if (level_str == "warning") {
|
||||||
|
return BCLog::Level::Warning;
|
||||||
|
} else if (level_str == "error") {
|
||||||
|
return BCLog::Level::Error;
|
||||||
|
} else if (level_str == "none") {
|
||||||
|
return BCLog::Level::None;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<LogCategory> BCLog::Logger::LogCategoriesList(bool enabled_only) const
|
std::vector<LogCategory> BCLog::Logger::LogCategoriesList(bool enabled_only) const
|
||||||
{
|
{
|
||||||
// Sort log categories by alphabetical order.
|
// Sort log categories by alphabetical order.
|
||||||
@ -338,6 +374,18 @@ std::vector<LogCategory> BCLog::Logger::LogCategoriesList(bool enabled_only) con
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Log severity levels that can be selected by the user. */
|
||||||
|
static constexpr std::array<BCLog::Level, 3> LogLevelsList()
|
||||||
|
{
|
||||||
|
return {BCLog::Level::Info, BCLog::Level::Debug, BCLog::Level::Trace};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BCLog::Logger::LogLevelsString() const
|
||||||
|
{
|
||||||
|
const auto& levels = LogLevelsList();
|
||||||
|
return Join(std::vector<BCLog::Level>{levels.begin(), levels.end()}, ", ", [this](BCLog::Level level) { return LogLevelToStr(level); });
|
||||||
|
}
|
||||||
|
|
||||||
std::string BCLog::Logger::LogTimestampStr(const std::string& str)
|
std::string BCLog::Logger::LogTimestampStr(const std::string& str)
|
||||||
{
|
{
|
||||||
std::string strStamped;
|
std::string strStamped;
|
||||||
@ -385,7 +433,7 @@ namespace BCLog {
|
|||||||
}
|
}
|
||||||
} // namespace BCLog
|
} // namespace BCLog
|
||||||
|
|
||||||
void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level)
|
void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level)
|
||||||
{
|
{
|
||||||
StdLockGuard scoped_lock(m_cs);
|
StdLockGuard scoped_lock(m_cs);
|
||||||
std::string str_prefixed = LogEscapeMessage(str);
|
std::string str_prefixed = LogEscapeMessage(str);
|
||||||
@ -494,3 +542,24 @@ void BCLog::Logger::ShrinkDebugFile()
|
|||||||
else if (file != nullptr)
|
else if (file != nullptr)
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BCLog::Logger::SetLogLevel(const std::string& level_str)
|
||||||
|
{
|
||||||
|
const auto level = GetLogLevel(level_str);
|
||||||
|
if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
|
||||||
|
m_log_level = level.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BCLog::Logger::SetCategoryLogLevel(const std::string& category_str, const std::string& level_str)
|
||||||
|
{
|
||||||
|
BCLog::LogFlags flag;
|
||||||
|
if (!GetLogCategory(flag, category_str)) return false;
|
||||||
|
|
||||||
|
const auto level = GetLogLevel(level_str);
|
||||||
|
if (!level.has_value() || level.value() > MAX_USER_SETABLE_SEVERITY_LEVEL) return false;
|
||||||
|
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
m_category_log_levels[flag] = level.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
#define BITCOIN_LOGGING_H
|
#define BITCOIN_LOGGING_H
|
||||||
|
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <tinyformat.h>
|
|
||||||
#include <threadsafety.h>
|
#include <threadsafety.h>
|
||||||
|
#include <tinyformat.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@ -17,6 +17,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
static const bool DEFAULT_LOGTIMEMICROS = false;
|
static const bool DEFAULT_LOGTIMEMICROS = false;
|
||||||
@ -92,12 +93,14 @@ namespace BCLog {
|
|||||||
ALL = ~(uint64_t)0,
|
ALL = ~(uint64_t)0,
|
||||||
};
|
};
|
||||||
enum class Level {
|
enum class Level {
|
||||||
Debug = 0,
|
Trace = 0, // High-volume or detailed logging for development/debugging
|
||||||
None = 1,
|
Debug, // Reasonably noisy logging, but still usable in production
|
||||||
Info = 2,
|
Info, // Default
|
||||||
Warning = 3,
|
Warning,
|
||||||
Error = 4,
|
Error,
|
||||||
|
None, // Internal use only
|
||||||
};
|
};
|
||||||
|
constexpr auto DEFAULT_LOG_LEVEL{Level::Debug};
|
||||||
|
|
||||||
class Logger
|
class Logger
|
||||||
{
|
{
|
||||||
@ -115,6 +118,13 @@ namespace BCLog {
|
|||||||
*/
|
*/
|
||||||
std::atomic_bool m_started_new_line{true};
|
std::atomic_bool m_started_new_line{true};
|
||||||
|
|
||||||
|
//! Category-specific log level. Overrides `m_log_level`.
|
||||||
|
std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs);
|
||||||
|
|
||||||
|
//! If there is no category-specific log level, all logs with a severity
|
||||||
|
//! level lower than `m_log_level` will be ignored.
|
||||||
|
std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL};
|
||||||
|
|
||||||
/** Log categories bitfield. */
|
/** Log categories bitfield. */
|
||||||
std::atomic<uint64_t> m_categories{0};
|
std::atomic<uint64_t> m_categories{0};
|
||||||
|
|
||||||
@ -137,7 +147,7 @@ namespace BCLog {
|
|||||||
std::atomic<bool> m_reopen_file{false};
|
std::atomic<bool> m_reopen_file{false};
|
||||||
|
|
||||||
/** Send a string to the log output */
|
/** Send a string to the log output */
|
||||||
void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, const int source_line, const BCLog::LogFlags category, const BCLog::Level level);
|
void LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level);
|
||||||
|
|
||||||
/** Returns whether logs will be written to any output */
|
/** Returns whether logs will be written to any output */
|
||||||
bool Enabled() const
|
bool Enabled() const
|
||||||
@ -168,6 +178,22 @@ namespace BCLog {
|
|||||||
|
|
||||||
void ShrinkDebugFile();
|
void ShrinkDebugFile();
|
||||||
|
|
||||||
|
std::unordered_map<LogFlags, Level> CategoryLevels() const
|
||||||
|
{
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
return m_category_log_levels;
|
||||||
|
}
|
||||||
|
void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels)
|
||||||
|
{
|
||||||
|
StdLockGuard scoped_lock(m_cs);
|
||||||
|
m_category_log_levels = levels;
|
||||||
|
}
|
||||||
|
bool SetCategoryLogLevel(const std::string& category_str, const std::string& level_str);
|
||||||
|
|
||||||
|
Level LogLevel() const { return m_log_level.load(); }
|
||||||
|
void SetLogLevel(Level level) { m_log_level = level; }
|
||||||
|
bool SetLogLevel(const std::string& level);
|
||||||
|
|
||||||
uint64_t GetCategoryMask() const { return m_categories.load(); }
|
uint64_t GetCategoryMask() const { return m_categories.load(); }
|
||||||
|
|
||||||
void EnableCategory(LogFlags flag);
|
void EnableCategory(LogFlags flag);
|
||||||
@ -176,6 +202,8 @@ namespace BCLog {
|
|||||||
bool DisableCategory(const std::string& str);
|
bool DisableCategory(const std::string& str);
|
||||||
|
|
||||||
bool WillLogCategory(LogFlags category) const;
|
bool WillLogCategory(LogFlags category) const;
|
||||||
|
bool WillLogCategoryLevel(LogFlags category, Level level) const;
|
||||||
|
|
||||||
/** Returns a vector of the log categories in alphabetical order. */
|
/** Returns a vector of the log categories in alphabetical order. */
|
||||||
std::vector<LogCategory> LogCategoriesList(bool enabled_only = false) const;
|
std::vector<LogCategory> LogCategoriesList(bool enabled_only = false) const;
|
||||||
/** Returns a string with the log categories in alphabetical order. */
|
/** Returns a string with the log categories in alphabetical order. */
|
||||||
@ -184,6 +212,12 @@ namespace BCLog {
|
|||||||
return Join(LogCategoriesList(enabled_only), ", ", [&](const LogCategory& i) { return i.category; });
|
return Join(LogCategoriesList(enabled_only), ", ", [&](const LogCategory& i) { return i.category; });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Returns a string with all user-selectable log levels.
|
||||||
|
std::string LogLevelsString() const;
|
||||||
|
|
||||||
|
//! Returns the string representation of a log level.
|
||||||
|
std::string LogLevelToStr(BCLog::Level level) const;
|
||||||
|
|
||||||
bool DefaultShrinkDebugFile() const;
|
bool DefaultShrinkDebugFile() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,12 +228,7 @@ BCLog::Logger& LogInstance();
|
|||||||
/** Return true if log accepts specified category, at the specified level. */
|
/** Return true if log accepts specified category, at the specified level. */
|
||||||
static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
|
static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
|
||||||
{
|
{
|
||||||
// Log messages at Warning and Error level unconditionally, so that
|
return LogInstance().WillLogCategoryLevel(category, level);
|
||||||
// important troubleshooting information doesn't get lost.
|
|
||||||
if (level >= BCLog::Level::Warning) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return LogInstance().WillLogCategory(category);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return true if str parses as a log category and set the flag */
|
/** Return true if str parses as a log category and set the flag */
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <i2p.h>
|
#include <i2p.h>
|
||||||
|
#include <logging.h>
|
||||||
#include <netaddress.h>
|
#include <netaddress.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <test/util/logging.h>
|
#include <test/util/logging.h>
|
||||||
@ -20,6 +21,8 @@ BOOST_FIXTURE_TEST_SUITE(i2p_tests, BasicTestingSetup)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(unlimited_recv)
|
BOOST_AUTO_TEST_CASE(unlimited_recv)
|
||||||
{
|
{
|
||||||
|
const auto prev_log_level{LogInstance().LogLevel()};
|
||||||
|
LogInstance().SetLogLevel(BCLog::Level::Trace);
|
||||||
auto CreateSockOrig = CreateSock;
|
auto CreateSockOrig = CreateSock;
|
||||||
|
|
||||||
// Mock CreateSock() to create MockSock.
|
// Mock CreateSock() to create MockSock.
|
||||||
@ -40,6 +43,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CreateSock = CreateSockOrig;
|
CreateSock = CreateSockOrig;
|
||||||
|
LogInstance().SetLogLevel(prev_log_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <init/common.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <logging/timer.h>
|
#include <logging/timer.h>
|
||||||
#include <test/util/setup_common.h>
|
#include <test/util/setup_common.h>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -17,6 +19,12 @@
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(logging_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
static void ResetLogger()
|
||||||
|
{
|
||||||
|
LogInstance().SetLogLevel(BCLog::DEFAULT_LOG_LEVEL);
|
||||||
|
LogInstance().SetCategoryLogLevel({});
|
||||||
|
}
|
||||||
|
|
||||||
struct LogSetup : public BasicTestingSetup {
|
struct LogSetup : public BasicTestingSetup {
|
||||||
fs::path prev_log_path;
|
fs::path prev_log_path;
|
||||||
fs::path tmp_log_path;
|
fs::path tmp_log_path;
|
||||||
@ -25,6 +33,8 @@ struct LogSetup : public BasicTestingSetup {
|
|||||||
bool prev_log_timestamps;
|
bool prev_log_timestamps;
|
||||||
bool prev_log_threadnames;
|
bool prev_log_threadnames;
|
||||||
bool prev_log_sourcelocations;
|
bool prev_log_sourcelocations;
|
||||||
|
std::unordered_map<BCLog::LogFlags, BCLog::Level> prev_category_levels;
|
||||||
|
BCLog::Level prev_log_level;
|
||||||
|
|
||||||
LogSetup() : prev_log_path{LogInstance().m_file_path},
|
LogSetup() : prev_log_path{LogInstance().m_file_path},
|
||||||
tmp_log_path{m_args.GetDataDirBase() / "tmp_debug.log"},
|
tmp_log_path{m_args.GetDataDirBase() / "tmp_debug.log"},
|
||||||
@ -32,14 +42,21 @@ struct LogSetup : public BasicTestingSetup {
|
|||||||
prev_print_to_file{LogInstance().m_print_to_file},
|
prev_print_to_file{LogInstance().m_print_to_file},
|
||||||
prev_log_timestamps{LogInstance().m_log_timestamps},
|
prev_log_timestamps{LogInstance().m_log_timestamps},
|
||||||
prev_log_threadnames{LogInstance().m_log_threadnames},
|
prev_log_threadnames{LogInstance().m_log_threadnames},
|
||||||
prev_log_sourcelocations{LogInstance().m_log_sourcelocations}
|
prev_log_sourcelocations{LogInstance().m_log_sourcelocations},
|
||||||
|
prev_category_levels{LogInstance().CategoryLevels()},
|
||||||
|
prev_log_level{LogInstance().LogLevel()}
|
||||||
{
|
{
|
||||||
LogInstance().m_file_path = tmp_log_path;
|
LogInstance().m_file_path = tmp_log_path;
|
||||||
LogInstance().m_reopen_file = true;
|
LogInstance().m_reopen_file = true;
|
||||||
LogInstance().m_print_to_file = true;
|
LogInstance().m_print_to_file = true;
|
||||||
LogInstance().m_log_timestamps = false;
|
LogInstance().m_log_timestamps = false;
|
||||||
LogInstance().m_log_threadnames = false;
|
LogInstance().m_log_threadnames = false;
|
||||||
LogInstance().m_log_sourcelocations = true;
|
|
||||||
|
// Prevent tests from failing when the line number of the logs changes.
|
||||||
|
LogInstance().m_log_sourcelocations = false;
|
||||||
|
|
||||||
|
LogInstance().SetLogLevel(BCLog::Level::Debug);
|
||||||
|
LogInstance().SetCategoryLogLevel({});
|
||||||
}
|
}
|
||||||
|
|
||||||
~LogSetup()
|
~LogSetup()
|
||||||
@ -51,6 +68,8 @@ struct LogSetup : public BasicTestingSetup {
|
|||||||
LogInstance().m_log_timestamps = prev_log_timestamps;
|
LogInstance().m_log_timestamps = prev_log_timestamps;
|
||||||
LogInstance().m_log_threadnames = prev_log_threadnames;
|
LogInstance().m_log_threadnames = prev_log_threadnames;
|
||||||
LogInstance().m_log_sourcelocations = prev_log_sourcelocations;
|
LogInstance().m_log_sourcelocations = prev_log_sourcelocations;
|
||||||
|
LogInstance().SetLogLevel(prev_log_level);
|
||||||
|
LogInstance().SetCategoryLogLevel(prev_category_levels);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +93,7 @@ BOOST_AUTO_TEST_CASE(logging_timer)
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
|
BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
|
||||||
{
|
{
|
||||||
|
LogInstance().m_log_sourcelocations = true;
|
||||||
LogPrintf_("fn1", "src1", 1, BCLog::LogFlags::NET, BCLog::Level::Debug, "foo1: %s", "bar1\n");
|
LogPrintf_("fn1", "src1", 1, BCLog::LogFlags::NET, BCLog::Level::Debug, "foo1: %s", "bar1\n");
|
||||||
LogPrintf_("fn2", "src2", 2, BCLog::LogFlags::NET, BCLog::Level::None, "foo2: %s", "bar2\n");
|
LogPrintf_("fn2", "src2", 2, BCLog::LogFlags::NET, BCLog::Level::None, "foo2: %s", "bar2\n");
|
||||||
LogPrintf_("fn3", "src3", 3, BCLog::LogFlags::NONE, BCLog::Level::Debug, "foo3: %s", "bar3\n");
|
LogPrintf_("fn3", "src3", 3, BCLog::LogFlags::NONE, BCLog::Level::Debug, "foo3: %s", "bar3\n");
|
||||||
@ -94,9 +114,6 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintf_, LogSetup)
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)
|
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)
|
||||||
{
|
{
|
||||||
// Prevent tests from failing when the line number of the following log calls changes.
|
|
||||||
LogInstance().m_log_sourcelocations = false;
|
|
||||||
|
|
||||||
LogPrintf("foo5: %s\n", "bar5");
|
LogPrintf("foo5: %s\n", "bar5");
|
||||||
LogPrint(BCLog::NET, "foo6: %s\n", "bar6");
|
LogPrint(BCLog::NET, "foo6: %s\n", "bar6");
|
||||||
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo7: %s\n", "bar7");
|
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo7: %s\n", "bar7");
|
||||||
@ -120,16 +137,14 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros, LogSetup)
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)
|
BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)
|
||||||
{
|
{
|
||||||
// Prevent tests from failing when the line number of the following log calls changes.
|
|
||||||
LogInstance().m_log_sourcelocations = false;
|
|
||||||
LogInstance().EnableCategory(BCLog::LogFlags::ALL);
|
LogInstance().EnableCategory(BCLog::LogFlags::ALL);
|
||||||
const auto concated_categery_names = LogInstance().LogCategoriesString();
|
const auto concatenated_category_names = LogInstance().LogCategoriesString();
|
||||||
std::vector<std::pair<BCLog::LogFlags, std::string>> expected_category_names;
|
std::vector<std::pair<BCLog::LogFlags, std::string>> expected_category_names;
|
||||||
const auto category_names = SplitString(concated_categery_names, ',');
|
const auto category_names = SplitString(concatenated_category_names, ',');
|
||||||
for (const auto& category_name : category_names) {
|
for (const auto& category_name : category_names) {
|
||||||
BCLog::LogFlags category = BCLog::NONE;
|
BCLog::LogFlags category;
|
||||||
const auto trimmed_category_name = TrimString(category_name);
|
const auto trimmed_category_name = TrimString(category_name);
|
||||||
BOOST_TEST(GetLogCategory(category, trimmed_category_name));
|
BOOST_REQUIRE(GetLogCategory(category, trimmed_category_name));
|
||||||
expected_category_names.emplace_back(category, trimmed_category_name);
|
expected_category_names.emplace_back(category, trimmed_category_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,4 +165,92 @@ BOOST_FIXTURE_TEST_CASE(logging_LogPrintMacros_CategoryName, LogSetup)
|
|||||||
BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(logging_SeverityLevels, LogSetup)
|
||||||
|
{
|
||||||
|
LogInstance().EnableCategory(BCLog::LogFlags::ALL);
|
||||||
|
|
||||||
|
LogInstance().SetLogLevel(BCLog::Level::Debug);
|
||||||
|
LogInstance().SetCategoryLogLevel(/*category_str=*/"net", /*level_str=*/"info");
|
||||||
|
|
||||||
|
// Global log level
|
||||||
|
LogPrintLevel(BCLog::HTTP, BCLog::Level::Info, "foo1: %s\n", "bar1");
|
||||||
|
LogPrintLevel(BCLog::MEMPOOL, BCLog::Level::Trace, "foo2: %s. This log level is lower than the global one.\n", "bar2");
|
||||||
|
LogPrintLevel(BCLog::VALIDATION, BCLog::Level::Warning, "foo3: %s\n", "bar3");
|
||||||
|
LogPrintLevel(BCLog::RPC, BCLog::Level::Error, "foo4: %s\n", "bar4");
|
||||||
|
|
||||||
|
// Category-specific log level
|
||||||
|
LogPrintLevel(BCLog::NET, BCLog::Level::Warning, "foo5: %s\n", "bar5");
|
||||||
|
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "foo6: %s. This log level is the same as the global one but lower than the category-specific one, which takes precedence. \n", "bar6");
|
||||||
|
LogPrintLevel(BCLog::NET, BCLog::Level::Error, "foo7: %s\n", "bar7");
|
||||||
|
|
||||||
|
std::vector<std::string> expected = {
|
||||||
|
"[http:info] foo1: bar1",
|
||||||
|
"[validation:warning] foo3: bar3",
|
||||||
|
"[rpc:error] foo4: bar4",
|
||||||
|
"[net:warning] foo5: bar5",
|
||||||
|
"[net:error] foo7: bar7",
|
||||||
|
};
|
||||||
|
std::ifstream file{tmp_log_path};
|
||||||
|
std::vector<std::string> log_lines;
|
||||||
|
for (std::string log; std::getline(file, log);) {
|
||||||
|
log_lines.push_back(log);
|
||||||
|
}
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(log_lines.begin(), log_lines.end(), expected.begin(), expected.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
|
||||||
|
{
|
||||||
|
// Set global log level
|
||||||
|
{
|
||||||
|
ResetLogger();
|
||||||
|
ArgsManager args;
|
||||||
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
const char* argv_test[] = {"dashd", "-loglevel=debug"};
|
||||||
|
std::string err;
|
||||||
|
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
||||||
|
init::SetLoggingLevel(args);
|
||||||
|
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set category-specific log level
|
||||||
|
{
|
||||||
|
ResetLogger();
|
||||||
|
ArgsManager args;
|
||||||
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
const char* argv_test[] = {"dashd", "-loglevel=net:trace"};
|
||||||
|
std::string err;
|
||||||
|
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
|
||||||
|
init::SetLoggingLevel(args);
|
||||||
|
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::DEFAULT_LOG_LEVEL);
|
||||||
|
|
||||||
|
const auto& category_levels{LogInstance().CategoryLevels()};
|
||||||
|
const auto net_it{category_levels.find(BCLog::LogFlags::NET)};
|
||||||
|
BOOST_REQUIRE(net_it != category_levels.end());
|
||||||
|
BOOST_CHECK_EQUAL(net_it->second, BCLog::Level::Trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set both global log level and category-specific log level
|
||||||
|
{
|
||||||
|
ResetLogger();
|
||||||
|
ArgsManager args;
|
||||||
|
args.AddArg("-loglevel", "...", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
|
||||||
|
const char* argv_test[] = {"dashd", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
|
||||||
|
std::string err;
|
||||||
|
BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
|
||||||
|
init::SetLoggingLevel(args);
|
||||||
|
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
|
||||||
|
|
||||||
|
const auto& category_levels{LogInstance().CategoryLevels()};
|
||||||
|
BOOST_CHECK_EQUAL(category_levels.size(), 2);
|
||||||
|
|
||||||
|
const auto net_it{category_levels.find(BCLog::LogFlags::NET)};
|
||||||
|
BOOST_CHECK(net_it != category_levels.end());
|
||||||
|
BOOST_CHECK_EQUAL(net_it->second, BCLog::Level::Trace);
|
||||||
|
|
||||||
|
const auto http_it{category_levels.find(BCLog::LogFlags::HTTP)};
|
||||||
|
BOOST_CHECK(http_it != category_levels.end());
|
||||||
|
BOOST_CHECK_EQUAL(http_it->second, BCLog::Level::Info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -149,6 +149,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
|
|||||||
"-logsourcelocations",
|
"-logsourcelocations",
|
||||||
"-logtimemicros",
|
"-logtimemicros",
|
||||||
"-logthreadnames",
|
"-logthreadnames",
|
||||||
|
"-loglevel=trace",
|
||||||
"-debug",
|
"-debug",
|
||||||
"-debugexclude=libevent",
|
"-debugexclude=libevent",
|
||||||
"-debugexclude=leveldb",
|
"-debugexclude=leveldb",
|
||||||
|
@ -125,6 +125,8 @@ class TestNode():
|
|||||||
self.args.append("-logthreadnames")
|
self.args.append("-logthreadnames")
|
||||||
if self.version_is_at_least(21000000):
|
if self.version_is_at_least(21000000):
|
||||||
self.args.append("-logsourcelocations")
|
self.args.append("-logsourcelocations")
|
||||||
|
if self.version_is_at_least(22010000):
|
||||||
|
self.args.append("-loglevel=trace")
|
||||||
|
|
||||||
# Default behavior from global -v2transport flag is added to args to persist it over restarts.
|
# Default behavior from global -v2transport flag is added to args to persist it over restarts.
|
||||||
# May be overwritten in individual tests, using extra_args.
|
# May be overwritten in individual tests, using extra_args.
|
||||||
|
Loading…
Reference in New Issue
Block a user