From 7015327f44764e821b6e41d2f8c9f119810eba9e Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Mon, 2 Mar 2026 22:36:24 +0530 Subject: [PATCH 1/6] [core] Add ROOT_LOG env var support for RLogger --- core/foundation/inc/ROOT/RLogger.hxx | 55 +++++++++++---- core/foundation/src/RLogger.cxx | 101 ++++++++++++++++++++++++--- 2 files changed, 135 insertions(+), 21 deletions(-) diff --git a/core/foundation/inc/ROOT/RLogger.hxx b/core/foundation/inc/ROOT/RLogger.hxx index 1aa022014856f..00c45b0325067 100644 --- a/core/foundation/inc/ROOT/RLogger.hxx +++ b/core/foundation/inc/ROOT/RLogger.hxx @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace ROOT { @@ -127,19 +128,28 @@ public: A RLogHandler that multiplexes diagnostics to different client `RLogHandler`s and keeps track of the sum of `RLogDiagCount`s for all channels. - `RLogHandler::Get()` returns the process's (static) log manager. - */ + `RLogManager::Get()` returns the process's (static) log manager. + The verbosity of individual channels can be configured at startup via the + `ROOT_LOG` environment variable. The format is a comma-separated list of + `ChannelName=Level` pairs, where `Level` is one of `Fatal`, `Error`, + `Warning`, `Info`, or `Debug` (optionally with an integer verbosity offset, + e.g. `Debug(3)`). Example: + ~~~ + export ROOT_LOG='ROOT.InterpreterPerf=Debug(3),ROOT.RBrowser=Error' + ~~~ + */ class RLogManager : public RLogChannel, public RLogHandler { std::mutex fMutex; std::list> fHandlers; + /// Verbosity overrides parsed from ROOT_LOG, keyed by channel name. + /// Applied to a channel the first time it calls GetEffectiveVerbosity(). + std::unordered_map fEnvVerbosity; + public: - /// Initialize taking a RLogHandler. - RLogManager(std::unique_ptr lh) : RLogChannel(ELogLevel::kWarning) - { - fHandlers.emplace_back(std::move(lh)); - } + /// Initialize taking a RLogHandler. Parses ROOT_LOG and gDebug at construction. + RLogManager(std::unique_ptr lh); static RLogManager &Get(); @@ -152,6 +162,16 @@ public: /// Remove and return the given log handler. Returns `nullptr` if not found. std::unique_ptr Remove(RLogHandler *handler); + /// Return the verbosity override for the named channel, or ELogLevel::kUnset if none. + /// Used by RLogChannel::GetEffectiveVerbosity() to apply ROOT_LOG settings lazily. + ELogLevel GetEnvVerbosity(const std::string &channelName) const + { + auto it = fEnvVerbosity.find(channelName); + if (it != fEnvVerbosity.end()) + return it->second; + return ELogLevel::kUnset; + } + // Emit a `RLogEntry` to the RLogHandlers. // Returns false if further emission of this Log should be suppressed. bool Emit(const RLogEntry &entry) override; @@ -171,7 +191,6 @@ struct RLogLocation { One can construct a RLogEntry through RLogBuilder, including streaming into the diagnostic message and automatic emission. */ - class RLogEntry { public: RLogLocation fLocation; @@ -206,7 +225,6 @@ namespace Detail { ~~~ This will automatically capture the current class and function name, the file and line number. */ - class RLogBuilder : public std::ostringstream { /// The log entry to be built. RLogEntry fEntry; @@ -309,9 +327,20 @@ inline RLogChannel &GetChannelOrManager(RLogChannel &channel) inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) const { - if (fVerbosity == ELogLevel::kUnset) - return mgr.GetVerbosity(); - return fVerbosity; + // If this channel has an explicit verbosity set, use it. + if (fVerbosity != ELogLevel::kUnset) + return fVerbosity; + + // Check if the ROOT_LOG environment variable specified a verbosity for + // this channel by name. Named channels have a non-empty name. + if (!fName.empty()) { + ELogLevel envLevel = mgr.GetEnvVerbosity(fName); + if (envLevel != ELogLevel::kUnset) + return envLevel; + } + + // Fall back to the global manager verbosity. + return mgr.GetVerbosity(); } } // namespace ROOT @@ -360,4 +389,4 @@ inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) cons #define R__LOG_DEBUG(DEBUGLEVEL, ...) R__LOG_TO_CHANNEL(ROOT::ELogLevel::kDebug + DEBUGLEVEL, __VA_ARGS__) ///\} -#endif +#endif \ No newline at end of file diff --git a/core/foundation/src/RLogger.cxx b/core/foundation/src/RLogger.cxx index 239c4511d8215..4a8a666c5399b 100644 --- a/core/foundation/src/RLogger.cxx +++ b/core/foundation/src/RLogger.cxx @@ -19,16 +19,19 @@ #include #include +#include #include +#include +#include #include // pin vtable ROOT::RLogHandler::~RLogHandler() {} namespace { + class RLogHandlerDefault : public ROOT::RLogHandler { public: - // Returns false if further emission of this log entry should be suppressed. bool Emit(const ROOT::RLogEntry &entry) override; }; @@ -55,8 +58,96 @@ inline bool RLogHandlerDefault::Emit(const ROOT::RLogEntry &entry) entry.fMessage.c_str()); return true; } + +/// Trim leading and trailing whitespace from a string. +std::string TrimWhitespace(const std::string &s) +{ + const auto begin = s.find_first_not_of(" \t\r\n"); + if (begin == std::string::npos) + return {}; + const auto end = s.find_last_not_of(" \t\r\n"); + return s.substr(begin, end - begin + 1); +} + +/// Parse a level string such as "Debug", "Debug(3)", "Info", "Warning", "Error", "Fatal". +/// Returns the corresponding ELogLevel. For Debug(N), the returned level is kDebug + N. +ROOT::ELogLevel ParseLogLevel(const std::string &levelStr) +{ + if (levelStr.compare(0, 5, "Debug") == 0) { + int extra = 0; + auto parenOpen = levelStr.find('('); + if (parenOpen != std::string::npos) { + auto parenClose = levelStr.find(')', parenOpen); + if (parenClose != std::string::npos) { + try { + extra = std::stoi(levelStr.substr(parenOpen + 1, parenClose - parenOpen - 1)); + } catch (...) { + extra = 0; + } + } + } + return ROOT::ELogLevel::kDebug + extra; + } + if (levelStr == "Info") return ROOT::ELogLevel::kInfo; + if (levelStr == "Warning") return ROOT::ELogLevel::kWarning; + if (levelStr == "Error") return ROOT::ELogLevel::kError; + if (levelStr == "Fatal") return ROOT::ELogLevel::kFatal; + + // Unrecognised string: return kUnset so the channel falls back to global. + return ROOT::ELogLevel::kUnset; +} + +/// Parse ROOT_LOG and return a map of channel-name -> verbosity level. +/// Format: "Channel1=Level1,Channel2=Debug(N),..." +std::unordered_map ParseRootLogEnvVar() +{ + std::unordered_map result; + + const char *envVal = std::getenv("ROOT_LOG"); + if (!envVal) + return result; + + std::stringstream ss(envVal); + std::string token; + while (std::getline(ss, token, ',')) { + token = TrimWhitespace(token); + if (token.empty()) + continue; + + auto eq = token.find('='); + if (eq == std::string::npos) + continue; + + std::string channelName = TrimWhitespace(token.substr(0, eq)); + std::string levelStr = TrimWhitespace(token.substr(eq + 1)); + + if (channelName.empty() || levelStr.empty()) + continue; + + ROOT::ELogLevel level = ParseLogLevel(levelStr); + if (level != ROOT::ELogLevel::kUnset) + result[channelName] = level; + } + return result; +} + } // unnamed namespace +/// Construct the RLogManager, install the default handler, then apply +/// gDebug and the ROOT_LOG environment variable. +ROOT::RLogManager::RLogManager(std::unique_ptr lh) : RLogChannel(ELogLevel::kWarning) +{ + fHandlers.emplace_back(std::move(lh)); + + // Apply gDebug as a global verbosity floor. + // gDebug == 1 maps to kDebug, gDebug == 2 to kDebug+1, etc. + if (gDebug > 0) + SetVerbosity(ELogLevel::kDebug + (gDebug - 1)); + + // Parse ROOT_LOG and store per-channel overrides for lazy application. + fEnvVerbosity = ParseRootLogEnvVar(); +} + ROOT::RLogManager &ROOT::RLogManager::Get() { static RLogManager instance(std::make_unique()); @@ -85,18 +176,12 @@ bool ROOT::RLogManager::Emit(const ROOT::RLogEntry &entry) if (channel != this) channel->Increment(entry.fLevel); - // Is there a specific level for the channel? If so, take that, - // overruling the global one. if (channel->GetEffectiveVerbosity(*this) < entry.fLevel) return true; - // Lock-protected extraction of handlers, such that they don't get added during the - // handler iteration. std::vector handlers; - { std::lock_guard lock(fMutex); - handlers.resize(fHandlers.size()); std::transform(fHandlers.begin(), fHandlers.end(), handlers.begin(), [](const std::unique_ptr &handlerUPtr) { return handlerUPtr.get(); }); @@ -106,4 +191,4 @@ bool ROOT::RLogManager::Emit(const ROOT::RLogEntry &entry) if (!handler->Emit(entry)) return false; return true; -} +} \ No newline at end of file From 8f759edc778650e6f993b63c975195b69d5fb4f7 Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Tue, 3 Mar 2026 20:42:40 +0530 Subject: [PATCH 2/6] [core] Add test for ROOT_LOG env var in RLogger --- core/foundation/test/RLoggerEnvVar.cxx | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 core/foundation/test/RLoggerEnvVar.cxx diff --git a/core/foundation/test/RLoggerEnvVar.cxx b/core/foundation/test/RLoggerEnvVar.cxx new file mode 100644 index 0000000000000..1b6f0b6d2b9a9 --- /dev/null +++ b/core/foundation/test/RLoggerEnvVar.cxx @@ -0,0 +1,37 @@ +// Test that ROOT_LOG env var correctly configures RLogger channel verbosity. +// ROOT_LOG is parsed once at RLogManager construction (process startup), +// so each test case is a separate executable launched with the env var set. + +#include "ROOT/RLogger.hxx" +#include "gtest/gtest.h" + +// Declare a test channel the same way ROOT modules do +ROOT::RLogChannel &TestChannel() +{ + static ROOT::RLogChannel channel("ROOT.TestChannel"); + return channel; +} + +// Test: channel verbosity set via ROOT_LOG is reflected in GetEnvVerbosity +TEST(RLoggerEnvVar, EnvVerbosityIsStored) +{ + // ROOT_LOG was set to 'ROOT.TestChannel=Error' before process start + // (set in CMakeLists via set_tests_properties) + auto level = ROOT::RLogManager::Get().GetEnvVerbosity("ROOT.TestChannel"); + EXPECT_EQ(level, ROOT::ELogLevel::kError); +} + +// Test: unknown channel returns kUnset +TEST(RLoggerEnvVar, UnknownChannelReturnsUnset) +{ + auto level = ROOT::RLogManager::Get().GetEnvVerbosity("ROOT.DoesNotExist"); + EXPECT_EQ(level, ROOT::ELogLevel::kUnset); +} + +// Test: channel effective verbosity uses env var when channel has no explicit level +TEST(RLoggerEnvVar, EffectiveVerbosityUsesEnvVar) +{ + // Channel has no explicit verbosity set, so should use env var value + auto effective = TestChannel().GetEffectiveVerbosity(ROOT::RLogManager::Get()); + EXPECT_EQ(effective, ROOT::ELogLevel::kError); +} \ No newline at end of file From b81d9d3a70f66503da7c8486aeb1b347b9ec0114 Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Wed, 4 Mar 2026 09:24:24 +0530 Subject: [PATCH 3/6] [core] Restore accidentally removed comments in Emit --- core/foundation/src/RLogger.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/foundation/src/RLogger.cxx b/core/foundation/src/RLogger.cxx index 4a8a666c5399b..dcd9e87cb92ff 100644 --- a/core/foundation/src/RLogger.cxx +++ b/core/foundation/src/RLogger.cxx @@ -175,10 +175,14 @@ bool ROOT::RLogManager::Emit(const ROOT::RLogEntry &entry) Increment(entry.fLevel); if (channel != this) channel->Increment(entry.fLevel); - + + // Is there a specific level for the channel? If so, take that, + // overruling the global one. if (channel->GetEffectiveVerbosity(*this) < entry.fLevel) return true; + // Lock-protected extraction of handlers, such that they don't get added during the + // handler iteration. std::vector handlers; { std::lock_guard lock(fMutex); From eebf61088c624d99c2cf93bdaf5110d1fa3a56eb Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Thu, 5 Mar 2026 20:35:23 +0530 Subject: [PATCH 4/6] [core] Address reviewer feedback on RLogger env var --- core/foundation/src/RLogger.cxx | 14 +++++++++----- core/foundation/test/CMakeLists.txt | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/foundation/src/RLogger.cxx b/core/foundation/src/RLogger.cxx index dcd9e87cb92ff..f3ec7beeb43a4 100644 --- a/core/foundation/src/RLogger.cxx +++ b/core/foundation/src/RLogger.cxx @@ -32,6 +32,7 @@ namespace { class RLogHandlerDefault : public ROOT::RLogHandler { public: + // Returns false if further emission of this log entry should be suppressed. bool Emit(const ROOT::RLogEntry &entry) override; }; @@ -60,10 +61,10 @@ inline bool RLogHandlerDefault::Emit(const ROOT::RLogEntry &entry) } /// Trim leading and trailing whitespace from a string. -std::string TrimWhitespace(const std::string &s) +std::string_view TrimWhitespace(std::string_view s) { const auto begin = s.find_first_not_of(" \t\r\n"); - if (begin == std::string::npos) + if (begin == std::string_view::npos) return {}; const auto end = s.find_last_not_of(" \t\r\n"); return s.substr(begin, end - begin + 1); @@ -83,6 +84,8 @@ ROOT::ELogLevel ParseLogLevel(const std::string &levelStr) extra = std::stoi(levelStr.substr(parenOpen + 1, parenClose - parenOpen - 1)); } catch (...) { extra = 0; + ::Warning("ROOT_LOG", "Cannot parse verbosity level in '%s', defaulting to Debug", + levelStr.c_str()); } } } @@ -93,7 +96,8 @@ ROOT::ELogLevel ParseLogLevel(const std::string &levelStr) if (levelStr == "Error") return ROOT::ELogLevel::kError; if (levelStr == "Fatal") return ROOT::ELogLevel::kFatal; - // Unrecognised string: return kUnset so the channel falls back to global. +// Unrecognised string: warn the user and return kUnset so the channel falls back to global. + ::Warning("ROOT_LOG", "Unrecognized log level '%s', ignoring", levelStr.data()); return ROOT::ELogLevel::kUnset; } @@ -118,8 +122,8 @@ std::unordered_map ParseRootLogEnvVar() if (eq == std::string::npos) continue; - std::string channelName = TrimWhitespace(token.substr(0, eq)); - std::string levelStr = TrimWhitespace(token.substr(eq + 1)); + std::string_view channelName = TrimWhitespace(std::string_view(token).substr(0, eq)); + std::string_view levelStr = TrimWhitespace(std::string_view(token).substr(eq + 1)); if (channelName.empty() || levelStr.empty()) continue; diff --git a/core/foundation/test/CMakeLists.txt b/core/foundation/test/CMakeLists.txt index 0dba82f6289c8..8f45de38d30c6 100644 --- a/core/foundation/test/CMakeLists.txt +++ b/core/foundation/test/CMakeLists.txt @@ -13,3 +13,7 @@ ROOT_ADD_GTEST(testLogger testLogger.cxx LIBRARIES Core) ROOT_ADD_GTEST(testRRangeCast testRRangeCast.cxx LIBRARIES Core) ROOT_ADD_GTEST(testStringUtils testStringUtils.cxx LIBRARIES Core) ROOT_ADD_GTEST(FoundationUtilsTests FoundationUtilsTests.cxx LIBRARIES Core INCLUDE_DIRS ../res) +ROOT_ADD_GTEST(RLoggerEnvVar RLoggerEnvVar.cxx + LIBRARIES Core) +set_tests_properties(RLoggerEnvVar PROPERTIES + ENVIRONMENT "ROOT_LOG=ROOT.TestChannel=Error") \ No newline at end of file From 40d8a5f07cc102941162d7d9f069bb76fd51c151 Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Thu, 5 Mar 2026 21:40:45 +0530 Subject: [PATCH 5/6] [core] Add test for explicit verbosity over ROOT_LOG env var --- core/foundation/test/RLoggerEnvVar.cxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/foundation/test/RLoggerEnvVar.cxx b/core/foundation/test/RLoggerEnvVar.cxx index 1b6f0b6d2b9a9..1d61e6b460c11 100644 --- a/core/foundation/test/RLoggerEnvVar.cxx +++ b/core/foundation/test/RLoggerEnvVar.cxx @@ -34,4 +34,20 @@ TEST(RLoggerEnvVar, EffectiveVerbosityUsesEnvVar) // Channel has no explicit verbosity set, so should use env var value auto effective = TestChannel().GetEffectiveVerbosity(ROOT::RLogManager::Get()); EXPECT_EQ(effective, ROOT::ELogLevel::kError); +} +// Test: explicitly set verbosity on a channel takes precedence over ROOT_LOG env var. +// ROOT_LOG sets ROOT.TestChannel=Error, but we explicitly set it to kInfo here. +// The explicit setting should win. +TEST(RLoggerEnvVar, ExplicitVerbosityTakesPrecedenceOverEnvVar) +{ + // ROOT_LOG set ROOT.TestChannel=Error via environment + // Now explicitly override it to kInfo + TestChannel().SetVerbosity(ROOT::ELogLevel::kInfo); + + // Explicit verbosity should win over env var + EXPECT_EQ(TestChannel().GetEffectiveVerbosity(ROOT::RLogManager::Get()), + ROOT::ELogLevel::kInfo); + + // Reset back to kUnset so other tests are not affected + TestChannel().SetVerbosity(ROOT::ELogLevel::kUnset); } \ No newline at end of file From 35592c2afc0afc40dd611549b1e7eb5cfffe9c05 Mon Sep 17 00:00:00 2001 From: Devesh Bervar Date: Fri, 6 Mar 2026 21:18:16 +0530 Subject: [PATCH 6/6] [core] Fix clang-format and string_view conversion issues --- core/foundation/inc/ROOT/RLogger.hxx | 4 +++- core/foundation/src/RLogger.cxx | 31 ++++++++++++++------------ core/foundation/test/RLoggerEnvVar.cxx | 3 +-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/foundation/inc/ROOT/RLogger.hxx b/core/foundation/inc/ROOT/RLogger.hxx index 00c45b0325067..ddf87af6b7a64 100644 --- a/core/foundation/inc/ROOT/RLogger.hxx +++ b/core/foundation/inc/ROOT/RLogger.hxx @@ -285,7 +285,9 @@ public: /// Construct the scoped count given a counter (e.g. a channel or RLogManager). /// The counter's lifetime must exceed the lifetime of this object! explicit RLogScopedDiagCount(RLogDiagCount &cnt) - : fCounter(&cnt), fInitialWarnings(cnt.GetNumWarnings()), fInitialErrors(cnt.GetNumErrors()), + : fCounter(&cnt), + fInitialWarnings(cnt.GetNumWarnings()), + fInitialErrors(cnt.GetNumErrors()), fInitialFatalErrors(cnt.GetNumFatalErrors()) { } diff --git a/core/foundation/src/RLogger.cxx b/core/foundation/src/RLogger.cxx index f3ec7beeb43a4..0725dca848f0f 100644 --- a/core/foundation/src/RLogger.cxx +++ b/core/foundation/src/RLogger.cxx @@ -72,7 +72,7 @@ std::string_view TrimWhitespace(std::string_view s) /// Parse a level string such as "Debug", "Debug(3)", "Info", "Warning", "Error", "Fatal". /// Returns the corresponding ELogLevel. For Debug(N), the returned level is kDebug + N. -ROOT::ELogLevel ParseLogLevel(const std::string &levelStr) +ROOT::ELogLevel ParseLogLevel(std::string_view levelStr) { if (levelStr.compare(0, 5, "Debug") == 0) { int extra = 0; @@ -81,22 +81,25 @@ ROOT::ELogLevel ParseLogLevel(const std::string &levelStr) auto parenClose = levelStr.find(')', parenOpen); if (parenClose != std::string::npos) { try { - extra = std::stoi(levelStr.substr(parenOpen + 1, parenClose - parenOpen - 1)); + extra = std::stoi(std::string(levelStr.substr(parenOpen + 1, parenClose - parenOpen - 1))); } catch (...) { extra = 0; - ::Warning("ROOT_LOG", "Cannot parse verbosity level in '%s', defaulting to Debug", - levelStr.c_str()); + ::Warning("ROOT_LOG", "Cannot parse verbosity level in '%s', defaulting to Debug", levelStr.data()); } } } return ROOT::ELogLevel::kDebug + extra; } - if (levelStr == "Info") return ROOT::ELogLevel::kInfo; - if (levelStr == "Warning") return ROOT::ELogLevel::kWarning; - if (levelStr == "Error") return ROOT::ELogLevel::kError; - if (levelStr == "Fatal") return ROOT::ELogLevel::kFatal; - -// Unrecognised string: warn the user and return kUnset so the channel falls back to global. + if (levelStr == "Info") + return ROOT::ELogLevel::kInfo; + if (levelStr == "Warning") + return ROOT::ELogLevel::kWarning; + if (levelStr == "Error") + return ROOT::ELogLevel::kError; + if (levelStr == "Fatal") + return ROOT::ELogLevel::kFatal; + + // Unrecognised string: warn the user and return kUnset so the channel falls back to global. ::Warning("ROOT_LOG", "Unrecognized log level '%s', ignoring", levelStr.data()); return ROOT::ELogLevel::kUnset; } @@ -123,14 +126,14 @@ std::unordered_map ParseRootLogEnvVar() continue; std::string_view channelName = TrimWhitespace(std::string_view(token).substr(0, eq)); - std::string_view levelStr = TrimWhitespace(std::string_view(token).substr(eq + 1)); + std::string_view levelStr = TrimWhitespace(std::string_view(token).substr(eq + 1)); if (channelName.empty() || levelStr.empty()) continue; ROOT::ELogLevel level = ParseLogLevel(levelStr); if (level != ROOT::ELogLevel::kUnset) - result[channelName] = level; + result[std::string(channelName)] = level; } return result; } @@ -179,9 +182,9 @@ bool ROOT::RLogManager::Emit(const ROOT::RLogEntry &entry) Increment(entry.fLevel); if (channel != this) channel->Increment(entry.fLevel); - + // Is there a specific level for the channel? If so, take that, - // overruling the global one. + // overruling the global one. if (channel->GetEffectiveVerbosity(*this) < entry.fLevel) return true; diff --git a/core/foundation/test/RLoggerEnvVar.cxx b/core/foundation/test/RLoggerEnvVar.cxx index 1d61e6b460c11..ec9a13b2ac577 100644 --- a/core/foundation/test/RLoggerEnvVar.cxx +++ b/core/foundation/test/RLoggerEnvVar.cxx @@ -45,8 +45,7 @@ TEST(RLoggerEnvVar, ExplicitVerbosityTakesPrecedenceOverEnvVar) TestChannel().SetVerbosity(ROOT::ELogLevel::kInfo); // Explicit verbosity should win over env var - EXPECT_EQ(TestChannel().GetEffectiveVerbosity(ROOT::RLogManager::Get()), - ROOT::ELogLevel::kInfo); + EXPECT_EQ(TestChannel().GetEffectiveVerbosity(ROOT::RLogManager::Get()), ROOT::ELogLevel::kInfo); // Reset back to kUnset so other tests are not affected TestChannel().SetVerbosity(ROOT::ELogLevel::kUnset);