// ---------------------------------------------------------------------------- // - Open3D: www.open3d.org - // ---------------------------------------------------------------------------- // Copyright (c) 2018-2023 www.open3d.org // SPDX-License-Identifier: MIT // ---------------------------------------------------------------------------- #pragma once #include #include #include // NVCC does not support deprecated attribute on Windows prior to v11. #if defined(__CUDACC__) && defined(_MSC_VER) && __CUDACC_VER_MAJOR__ < 11 #ifndef FMT_DEPRECATED #define FMT_DEPRECATED #endif #endif #include #include #include #define DEFAULT_IO_BUFFER_SIZE 1024 #include "open3d/Macro.h" // Mimic "macro in namespace" by concatenating `utility::` and a macro. // Ref: https://stackoverflow.com/a/11791202 // // We avoid using (format, ...) since in this case __VA_ARGS__ can be // empty, and the behavior of pruning trailing comma with ##__VA_ARGS__ is not // officially standard. // Ref: https://stackoverflow.com/a/28074198 // // __PRETTY_FUNCTION__ has to be converted, otherwise a bug regarding [noreturn] // will be triggered. // Ref: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94742 // LogError throws now a runtime_error with the given error message. This // should be used if there is no point in continuing the given algorithm at // some point and the error is not returned in another way (e.g., via a // bool/int as return value). // // Usage : utility::LogError(format_string, arg0, arg1, ...); // Example: utility::LogError("name: {}, age: {}", "dog", 5); #define LogError(...) \ Logger::LogError_(__FILE__, __LINE__, \ static_cast(OPEN3D_FUNCTION), __VA_ARGS__) // LogWarning is used if an error occurs, but the error is also signaled // via a return value (i.e., there is no need to throw an exception). This // warning should further be used, if the algorithms encounters a state // that does not break its continuation, but the output is likely not to be // what the user expected. // // Usage : utility::LogWarning(format_string, arg0, arg1, ...); // Example: utility::LogWarning("name: {}, age: {}", "dog", 5); #define LogWarning(...) \ Logger::LogWarning_(__FILE__, __LINE__, \ static_cast(OPEN3D_FUNCTION), \ __VA_ARGS__) // LogInfo is used to inform the user with expected output, e.g, pressed a // key in the visualizer prints helping information. // // Usage : utility::LogInfo(format_string, arg0, arg1, ...); // Example: utility::LogInfo("name: {}, age: {}", "dog", 5); #define LogInfo(...) \ Logger::LogInfo_(__FILE__, __LINE__, \ static_cast(OPEN3D_FUNCTION), __VA_ARGS__) // LogDebug is used to print debug/additional information on the state of // the algorithm. // // Usage : utility::LogDebug(format_string, arg0, arg1, ...); // Example: utility::LogDebug("name: {}, age: {}", "dog", 5); #define LogDebug(...) \ Logger::LogDebug_(__FILE__, __LINE__, \ static_cast(OPEN3D_FUNCTION), __VA_ARGS__) namespace open3d { namespace utility { enum class VerbosityLevel { /// LogError throws now a runtime_error with the given error message. This /// should be used if there is no point in continuing the given algorithm at /// some point and the error is not returned in another way (e.g., via a /// bool/int as return value). Error = 0, /// LogWarning is used if an error occurs, but the error is also signaled /// via a return value (i.e., there is no need to throw an exception). This /// warning should further be used, if the algorithms encounters a state /// that does not break its continuation, but the output is likely not to be /// what the user expected. Warning = 1, /// LogInfo is used to inform the user with expected output, e.g, pressed a /// key in the visualizer prints helping information. Info = 2, /// LogDebug is used to print debug/additional information on the state of /// the algorithm. Debug = 3, }; /// Logger class should be used as a global singleton object (GetInstance()). class Logger { public: Logger(Logger const &) = delete; void operator=(Logger const &) = delete; /// Get Logger global singleton instance. static Logger &GetInstance(); /// Overwrite the default print function, this is useful when you want to /// redirect prints rather than printing to stdout. For example, in Open3D's /// python binding, the default print function is replaced with py::print(). /// /// \param print_fcn The function for printing. It should take a string /// input and returns nothing. void SetPrintFunction(std::function print_fcn); /// Reset the print function to the default one (print to console). void ResetPrintFunction(); /// Get the print function used by the Logger. const std::function GetPrintFunction(); /// Set global verbosity level of Open3D. /// /// \param verbosity_level Messages with equal or less than verbosity_level /// verbosity will be printed. void SetVerbosityLevel(VerbosityLevel verbosity_level); /// Get global verbosity level of Open3D. VerbosityLevel GetVerbosityLevel() const; template static void LogError_ [[noreturn]] (const char *file, int line, const char *function, const char *format, Args &&... args) { if (sizeof...(Args) > 0) { Logger::GetInstance().VError( file, line, function, FormatArgs(format, fmt::make_format_args(args...))); } else { Logger::GetInstance().VError(file, line, function, std::string(format)); } } template static void LogWarning_(const char *file, int line, const char *function, const char *format, Args &&... args) { if (Logger::GetInstance().GetVerbosityLevel() >= VerbosityLevel::Warning) { if (sizeof...(Args) > 0) { Logger::GetInstance().VWarning( file, line, function, FormatArgs(format, fmt::make_format_args(args...))); } else { Logger::GetInstance().VWarning(file, line, function, std::string(format)); } } } template static void LogInfo_(const char *file, int line, const char *function, const char *format, Args &&... args) { if (Logger::GetInstance().GetVerbosityLevel() >= VerbosityLevel::Info) { if (sizeof...(Args) > 0) { Logger::GetInstance().VInfo( file, line, function, FormatArgs(format, fmt::make_format_args(args...))); } else { Logger::GetInstance().VInfo(file, line, function, std::string(format)); } } } template static void LogDebug_(const char *file, int line, const char *function, const char *format, Args &&... args) { if (Logger::GetInstance().GetVerbosityLevel() >= VerbosityLevel::Debug) { if (sizeof...(Args) > 0) { Logger::GetInstance().VDebug( file, line, function, FormatArgs(format, fmt::make_format_args(args...))); } else { Logger::GetInstance().VDebug(file, line, function, std::string(format)); } } } private: Logger(); static std::string FormatArgs(const char *format, fmt::format_args args) { std::string err_msg = fmt::vformat(format, args); return err_msg; } void VError [[noreturn]] (const char *file, int line, const char *function, const std::string &message) const; void VWarning(const char *file, int line, const char *function, const std::string &message) const; void VInfo(const char *file, int line, const char *function, const std::string &message) const; void VDebug(const char *file, int line, const char *function, const std::string &message) const; private: struct Impl; std::unique_ptr impl_; }; /// Set global verbosity level of Open3D /// /// \param level Messages with equal or less than verbosity_level verbosity will /// be printed. void SetVerbosityLevel(VerbosityLevel level); /// Get global verbosity level of Open3D. VerbosityLevel GetVerbosityLevel(); class VerbosityContextManager { public: VerbosityContextManager(VerbosityLevel level) : level_(level) {} void Enter() { level_backup_ = Logger::GetInstance().GetVerbosityLevel(); Logger::GetInstance().SetVerbosityLevel(level_); } void Exit() { Logger::GetInstance().SetVerbosityLevel(level_backup_); } private: VerbosityLevel level_; VerbosityLevel level_backup_; }; } // namespace utility } // namespace open3d