Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion core/foundation/inc/ROOT/RLogger.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <atomic>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <sstream>
Expand Down Expand Up @@ -99,7 +100,8 @@ class RLogChannel : public RLogDiagCount {
std::string fName;

/// Verbosity of this channel. By default, use the global verbosity.
ELogLevel fVerbosity = ELogLevel::kUnset;
mutable ELogLevel fVerbosity = ELogLevel::kUnset;
mutable bool fVerbosityInitialized{false};

public:
/// Construct an anonymous channel.
Expand All @@ -114,6 +116,7 @@ public:
ELogLevel SetVerbosity(ELogLevel verbosity)
{
std::swap(fVerbosity, verbosity);
fVerbosityInitialized = true;
return verbosity;
}
ELogLevel GetVerbosity() const { return fVerbosity; }
Expand Down Expand Up @@ -142,6 +145,8 @@ public:

static RLogManager &Get();

ELogLevel GetConfiguredVerbosity(const std::string &name) const;

/// Add a RLogHandler in the front - to be called before all others.
void PushFront(std::unique_ptr<RLogHandler> handler) { fHandlers.emplace_front(std::move(handler)); }

Expand Down Expand Up @@ -294,6 +299,7 @@ public:
};

namespace Internal {
void ParseRootLogStr(const std::string& env, std::map<std::string, ELogLevel>& out);

inline RLogChannel &GetChannelOrManager()
{
Expand All @@ -308,6 +314,12 @@ inline RLogChannel &GetChannelOrManager(RLogChannel &channel)

inline ELogLevel RLogChannel::GetEffectiveVerbosity(const RLogManager &mgr) const
{
if (!fVerbosityInitialized) {
fVerbosityInitialized = true;
ELogLevel cfg = mgr.GetConfiguredVerbosity(fName);
if (cfg != ELogLevel::kUnset)
fVerbosity = cfg;
}
if (fVerbosity == ELogLevel::kUnset)
return mgr.GetVerbosity();
return fVerbosity;
Expand Down
73 changes: 73 additions & 0 deletions core/foundation/src/RLogger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#include <array>
#include <memory>
#include <vector>
#include <map>
#include <cstdlib>
#include <string>

// pin vtable
ROOT::RLogHandler::~RLogHandler() {}
Expand Down Expand Up @@ -54,14 +57,84 @@ inline bool RLogHandlerDefault::Emit(const ROOT::RLogEntry &entry)
entry.fMessage.c_str());
return true;
}

static ROOT::ELogLevel ParseVerbosityStr(const std::string &str) {
if (str == "Fatal") return ROOT::ELogLevel::kFatal;
if (str == "Error") return ROOT::ELogLevel::kError;
if (str == "Warning") return ROOT::ELogLevel::kWarning;
if (str == "Info") return ROOT::ELogLevel::kInfo;
if (str.compare(0, 5, "Debug") == 0) {
if (str.length() > 6 && str[5] == '(' && str.back() == ')') {
int level = std::stoi(str.substr(6, str.length() - 7));
return static_cast<ROOT::ELogLevel>(static_cast<int>(ROOT::ELogLevel::kDebug) + level);
}
return ROOT::ELogLevel::kDebug;
}
return ROOT::ELogLevel::kUnset;
}

namespace ROOT {
namespace Internal {

void ParseRootLogStr(const std::string& env, std::map<std::string, ROOT::ELogLevel>& sChannelVerbosities) {
std::string s = env;
size_t start = 0;
size_t end = s.find(',');
while (start != std::string::npos) {
std::string part = s.substr(start, end - start);
size_t eq = part.find('=');
if (eq != std::string::npos) {
sChannelVerbosities[part.substr(0, eq)] = ParseVerbosityStr(part.substr(eq + 1));
} else {
sChannelVerbosities[""] = ParseVerbosityStr(part);
}
if (end == std::string::npos) break;
start = end + 1;
end = s.find(',', start);
}
}

} // namespace Internal
} // namespace ROOT

static std::map<std::string, ROOT::ELogLevel>& GetChannelVerbosities() {
static std::map<std::string, ROOT::ELogLevel> sChannelVerbosities;
static bool parsed = false;
if (!parsed) {
parsed = true;
const char *env = std::getenv("ROOT_LOG");
if (env) {
ROOT::Internal::ParseRootLogStr(env, sChannelVerbosities);
}
}
return sChannelVerbosities;
}

} // unnamed namespace

ROOT::RLogManager &ROOT::RLogManager::Get()
{
static RLogManager instance(std::make_unique<RLogHandlerDefault>());
static bool configured = false;
if (!configured) {
configured = true;
auto& cfg = GetChannelVerbosities();
if (cfg.count("")) {
instance.SetVerbosity(cfg[""]);
}
}
return instance;
}

ROOT::ELogLevel ROOT::RLogManager::GetConfiguredVerbosity(const std::string &name) const
{
auto& cfg = GetChannelVerbosities();
auto it = cfg.find(name);
if (it != cfg.end())
return it->second;
return ROOT::ELogLevel::kUnset;
}

std::unique_ptr<ROOT::RLogHandler> ROOT::RLogManager::Remove(RLogHandler *handler)
{
auto iter = std::find_if(fHandlers.begin(), fHandlers.end(), [&](const std::unique_ptr<RLogHandler> &handlerPtr) {
Expand Down
12 changes: 12 additions & 0 deletions core/foundation/test/testLogger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <memory>
#include <vector>
#include <map>

struct TestLogger {
class Handler : public ROOT::RLogHandler {
Expand Down Expand Up @@ -305,3 +306,14 @@ TEST(Logger, ROOTErrorHandlerDiagString)

SetErrorHandler(prevErrorHandler);
}

TEST(Logger, EnvVarParsing)
{
std::map<std::string, ROOT::ELogLevel> cfg;
ROOT::Internal::ParseRootLogStr("ROOT.InterpreterPerf=Debug(3),ROOT.RBrowser=Error,Info", cfg);
EXPECT_EQ(cfg.size(), 3);
EXPECT_EQ(cfg[""], ROOT::ELogLevel::kInfo);
EXPECT_EQ(cfg["ROOT.RBrowser"], ROOT::ELogLevel::kError);
EXPECT_EQ(cfg["ROOT.InterpreterPerf"], static_cast<ROOT::ELogLevel>(static_cast<int>(ROOT::ELogLevel::kDebug) + 3));
}