/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2012-2019 Danny Robson */ #pragma once #include "format.hpp" #include #include #include // Windows.h or one of its friends defines a macro 'ERROR'. Screw Microsoft. #ifdef ERROR #undef ERROR #endif namespace cruft::log { /////////////////////////////////////////////////////////////////////////// // rfc5424 log levels. It is assumed they are contiguous to simplify array // indexing in logging code. enum level_t { EMERGENCY, /** system is unusable */ ALERT, /** action must be taken immediately */ CRITICAL, /** critical conditions */ ERROR, /** error conditions */ WARNING, WARN = WARNING, /** warning conditions */ NOTICE, /** normal but significant condition */ INFORMATIONAL, INFO = INFORMATIONAL, /** informational messages */ DEBUG /** debug-level messages */ }; #define MAP_LEVEL_T(F) MAP0(F, EMERGENCY, ALERT, CRITICAL, ERROR, WARN, NOTICE, INFO, DEBUG) constexpr auto DEFAULT_LOG_LEVEL = NOTICE; //------------------------------------------------------------------------- const std::string& to_string (level_t); //------------------------------------------------------------------------- std::ostream& operator<< (std::ostream&, level_t); /////////////////////////////////////////////////////////////////////////// // Query or set the global logging level filter. If the severity passed to // a logging call is less than this then the output is discarded. // // The initial logging level can be controlled by setting the environment // variable LOG_LEVEL to a string corresponding to the names of the values // in level_t. // // Otherwise we fall back to the hard coded default from above. // // As a special case, a blank value for the environment variable LOG_LEVEL // corresponds to the maximum log level. It indicates a preference for // minimum output, and may be changed to disable all output in future // updates. level_t log_level (void); level_t log_level (level_t); /////////////////////////////////////////////////////////////////////////// void write (level_t, const std::string &msg); template void write (level_t l, const char (&fmt)[N], Args &&...args) { write ( l, to_string ( format::printf (fmt) ( std::forward (args)... ) ) ); } //------------------------------------------------------------------------- // Various convenience macros for logging specific strings with a well // known severity. // // LOG_DEBUG is treated similarly to assert; if NDEBUG is defined then we // compile out the statement so as to gain a little runtime efficiency // speed. #define LOG_EMERGENCY(...) do { cruft::log::write (cruft::log::EMERGENCY, ##__VA_ARGS__); } while (0) #define LOG_ALERT(...) do { cruft::log::write (cruft::log::ALERT, ##__VA_ARGS__); } while (0) #define LOG_CRITICAL(...) do { cruft::log::write (cruft::log::CRITICAL, ##__VA_ARGS__); } while (0) #define LOG_ERROR(...) do { cruft::log::write (cruft::log::ERROR, ##__VA_ARGS__); } while (0) #define LOG_WARNING(...) do { cruft::log::write (cruft::log::WARNING, ##__VA_ARGS__); } while (0) #define LOG_WARN(...) do { cruft::log::write (cruft::log::WARN, ##__VA_ARGS__); } while (0) #define LOG_NOTICE(...) do { cruft::log::write (cruft::log::NOTICE, ##__VA_ARGS__); } while (0) #define LOG_INFO(...) do { cruft::log::write (cruft::log::INFO, ##__VA_ARGS__); } while (0) #if !defined(NDEBUG) #define LOG_DEBUG(...) do { cruft::log::write (cruft::log::DEBUG, ##__VA_ARGS__); } while (0) #else #define LOG_DEBUG(...) do { ; } while (0) #endif /////////////////////////////////////////////////////////////////////////// class scoped_logger { public: scoped_logger (level_t, std::string); ~scoped_logger (); scoped_logger (scoped_logger const&) = delete; scoped_logger& operator= (scoped_logger const&) = delete; scoped_logger (scoped_logger &&) = delete; scoped_logger& operator= (scoped_logger &&) = delete; protected: const level_t m_level; const std::string m_message; }; /////////////////////////////////////////////////////////////////////////// class scoped_timer { public: scoped_timer (level_t, std::string); ~scoped_timer (); scoped_timer (scoped_timer const&) = delete; scoped_timer& operator= (scoped_timer const&) = delete; scoped_timer (scoped_timer &&) = delete; scoped_timer& operator= (scoped_timer &&) = delete; private: const level_t m_level; const std::string m_message; uint64_t m_start; }; }