diff --git a/main/src/hadd.cxx b/main/src/hadd.cxx index d27ebd1efe0cc..89df5631919eb 100644 --- a/main/src/hadd.cxx +++ b/main/src/hadd.cxx @@ -151,6 +151,7 @@ #include #include "haddCommandLineOptionsHelp.h" +#include "logging.hxx" #include #include @@ -168,56 +169,13 @@ //////////////////////////////////////////////////////////////////////////////// -// NOTE: TFileMerger will use PrintLevel = gHaddVerbosity - 1. If PrintLevel is < 1, it will print nothing, otherwise +// NOTE: TFileMerger will use PrintLevel = GetLogVerbosity() - 1. If PrintLevel is < 1, it will print nothing, otherwise // it will print everything. To give some granularity to hadd, we do the following: -// gHaddVerbosity = 0: only print hadd errors -// gHaddVerbosity = 1: only print hadd errors + warnings -// gHaddVerbosity = 2: print hadd errors + warnings and TFileMerger messages -// gHaddVerbosity > 2: print all hadd and TFileMerger messages. +// LogVerbosity = 0: only print hadd errors +// LogVerbosity = 1: only print hadd errors + warnings +// LogVerbosity = 2: print hadd errors + warnings and TFileMerger messages +// LogVerbosity > 2: print all hadd and TFileMerger messages. static constexpr int kDefaultHaddVerbosity = 2; -static int gHaddVerbosity = kDefaultHaddVerbosity; - -namespace { - -class NullBuf : public std::streambuf { -public: - int overflow(int c) final { return c; } -}; - -class NullStream : public std::ostream { - NullBuf fBuf; - -public: - NullStream() : std::ostream(&fBuf) {} -}; - -} // namespace - -static NullStream &GetNullStream() -{ - static NullStream nullStream; - return nullStream; -} - -static inline std::ostream &Err() -{ - std::cerr << "Error in : "; - return std::cerr; -} - -static inline std::ostream &Warn() -{ - std::ostream &s = gHaddVerbosity < 1 ? GetNullStream() : std::cerr; - s << "Warning in : "; - return s; -} - -static inline std::ostream &Info(int minLevel) -{ - std::ostream &s = gHaddVerbosity < minLevel ? GetNullStream() : std::cerr; - s << "Info in : "; - return s; -} using IntFlag_t = uint32_t; @@ -658,6 +616,8 @@ static Int_t ParseFilterFile(const std::optional &filterFileName, int main(int argc, char **argv) { + InitLog("hadd", kDefaultHaddVerbosity); + const auto argsOpt = ParseArgs(argc, argv); if (!argsOpt) return 1; @@ -670,7 +630,7 @@ int main(int argc, char **argv) ROOT::TIOFeatures features = args.fFeatures.value_or(ROOT::TIOFeatures{}); Int_t maxopenedfiles = args.fMaxOpenedFiles.value_or(0); - gHaddVerbosity = args.fVerbosity.value_or(kDefaultHaddVerbosity); + SetLogVerbosity(args.fVerbosity.value_or(kDefaultHaddVerbosity)); Int_t newcomp = args.fCompressionSettings.value_or(-1); TString cacheSize = args.fCacheSize.value_or(""); @@ -731,7 +691,7 @@ int main(int argc, char **argv) TFileMerger fileMerger(kFALSE, kFALSE); fileMerger.SetMsgPrefix("hadd"); - fileMerger.SetPrintLevel(gHaddVerbosity - 1); + fileMerger.SetPrintLevel(GetLogVerbosity() - 1); if (maxopenedfiles > 0) { fileMerger.SetMaxOpenedFiles(maxopenedfiles); } @@ -896,7 +856,7 @@ int main(int argc, char **argv) auto parallelMerge = [&](int start) { TFileMerger mergerP(kFALSE, kFALSE); mergerP.SetMsgPrefix("hadd"); - mergerP.SetPrintLevel(gHaddVerbosity - 1); + mergerP.SetPrintLevel(GetLogVerbosity() - 1); if (maxopenedfiles > 0) { mergerP.SetMaxOpenedFiles(maxopenedfiles / nProcesses); } diff --git a/main/src/logging.hxx b/main/src/logging.hxx new file mode 100644 index 0000000000000..9534c186dbef3 --- /dev/null +++ b/main/src/logging.hxx @@ -0,0 +1,75 @@ +/// +/// Basic logging utilities meant to be used by binaries. +/// Use instead of RLogger for user-facing messages. +/// +#ifndef ROOT_Main_Logging +#define ROOT_Main_Logging + +#include + +namespace Detail { + +class NullBuf : public std::streambuf { +public: + int overflow(int c) final { return c; } +}; + +// A stream that discards all input. +class NullStream : public std::ostream { + NullBuf fBuf; + +public: + NullStream() : std::ostream(&fBuf) {} +}; + +inline const char *gLogName = ""; +/// Log verbosity works this way: +/// If it's <= 0, all warnings are suppressed. +/// Additionally, when Info(lv) is called, it is only displayed if lv <= LogVerbosity. +inline int gLogVerbosity = 1; + +inline NullStream &GetNullStream() +{ + static NullStream nullStream; + return nullStream; +} + +} // namespace Detail + +inline void InitLog(const char *name, int defaultVerbosity = 1) +{ + Detail::gLogName = name; + Detail::gLogVerbosity = defaultVerbosity; +} + +inline void SetLogVerbosity(int verbosity) +{ + Detail::gLogVerbosity = verbosity; +} + +inline int GetLogVerbosity() +{ + return Detail::gLogVerbosity; +} + +inline std::ostream &Err() +{ + std::cerr << "Error in <" << Detail::gLogName << ">: "; + return std::cerr; +} + +inline std::ostream &Warn() +{ + std::ostream &s = Detail::gLogVerbosity < 1 ? Detail::GetNullStream() : std::cerr; + s << "Warning in <" << Detail::gLogName << ">: "; + return s; +} + +inline std::ostream &Info(int minLevel) +{ + std::ostream &s = Detail::gLogVerbosity < minLevel ? Detail::GetNullStream() : std::cerr; + s << "Info in <" << Detail::gLogName << ">: "; + return s; +} + +#endif diff --git a/main/src/rootbrowse.cxx b/main/src/rootbrowse.cxx index 29d79df70e5fd..e164f0248f3a0 100644 --- a/main/src/rootbrowse.cxx +++ b/main/src/rootbrowse.cxx @@ -6,6 +6,7 @@ /// \date 2025-08-21 #include +#include "logging.hxx" #include "optparse.hxx" #include @@ -44,12 +45,6 @@ positional arguments: Open the ROOT file 'file.root' in a TBrowser )"; -static ROOT::RLogChannel &RootBrowseLog() -{ - static ROOT::RLogChannel channel("RootBrowse"); - return channel; -} - struct RootBrowseArgs { enum class EPrintUsage { kNo, @@ -97,6 +92,8 @@ static RootBrowseArgs ParseArgs(const char **args, int nArgs) int main(int argc, char **argv) { + InitLog("rootbrowse"); + auto args = ParseArgs(const_cast(argv) + 1, argc - 1); if (args.fPrintHelp != RootBrowseArgs::EPrintUsage::kNo) { std::cerr << kShortHelp; @@ -119,7 +116,8 @@ int main(int argc, char **argv) gErrorIgnoreLevel = kError; file = std::unique_ptr(TFile::Open(std::string(args.fFileName).c_str(), "READ")); if (!file || file->IsZombie()) { - R__LOG_WARNING(RootBrowseLog()) << "File " << args.fFileName << " does not exist or is unreadable."; + Err() << "File " << args.fFileName << " does not exist or is unreadable."; + return 1; } gErrorIgnoreLevel = kUnset; } diff --git a/main/src/rootls.cxx b/main/src/rootls.cxx index 7e29b3f11ff39..bed2164f75bda 100644 --- a/main/src/rootls.cxx +++ b/main/src/rootls.cxx @@ -22,6 +22,7 @@ #include #include +#include "logging.hxx" #include "optparse.hxx" #include "wildcards.hpp" @@ -107,12 +108,6 @@ positional arguments: Display contents of the ROOT file 'example.root', traversing recursively any TDirectory. )"; -static ROOT::RLogChannel &RootLsChannel() -{ - static ROOT::RLogChannel sLog("ROOTLS"); - return sLog; -} - static bool ClassInheritsFrom(const char *class_, const char *baseClass) { const auto *cl = TClass::GetClass(class_); @@ -385,7 +380,7 @@ static void PrintNodesDetailed(std::ostream &stream, const RootLsTree &tree, const auto &desc = reader->GetDescriptor(); PrintRNTuple(stream, desc, indent + 2, desc.GetFieldZero()); } else { - R__LOG_ERROR(RootLsChannel()) << "failed to read RNTuple object: " << child.fName; + Err() << "failed to read RNTuple object: " << child.fName; } } } @@ -691,7 +686,7 @@ static RootLsArgs ParseArgs(const char **args, int nArgs) opts.Parse(args, nArgs); for (const auto &err : opts.GetErrors()) - R__LOG_ERROR(RootLsChannel()) << err; + Err() << err; if (opts.GetSwitch("help")) { outArgs.fPrintUsageAndExit = RootLsArgs::EPrintUsage::kLong; @@ -745,6 +740,8 @@ int main(int argc, char **argv) // Ignore diagnostics up to (but excluding) kError to avoid spamming users with TClass::Init warnings. gErrorIgnoreLevel = kError; + InitLog("rootls"); + auto args = ParseArgs(const_cast(argv) + 1, argc - 1); if (args.fPrintUsageAndExit != RootLsArgs::EPrintUsage::kNo) { std::cerr << "usage: rootls [-1hltr] FILE [FILE ...]\n";