From fa9f537e59781bba5fbb19d47e0272f334bf43c2 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 10 Oct 2019 15:10:41 +1100 Subject: [PATCH] log: prepare to expand headers --- CMakeLists.txt | 4 +- log.hpp | 141 +--------------------------------- log.cpp => log/log.cpp | 54 ++++++++++---- log/log.hpp | 166 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 153 deletions(-) rename log.cpp => log/log.cpp (86%) create mode 100644 log/log.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 989fb416..5df0af84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -421,8 +421,10 @@ list ( library.hpp list/node.hpp list/sort.hpp - log.cpp log.hpp + log/fwd.hpp + log/log.hpp + log/log.cpp map/fixed.cpp map/fixed.hpp maths.cpp diff --git a/log.hpp b/log.hpp index 9530c7f6..0eb8510b 100644 --- a/log.hpp +++ b/log.hpp @@ -1,145 +1,10 @@ + /* * 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 + * Copyright 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; - }; -} +#include "log/log.hpp" diff --git a/log.cpp b/log/log.cpp similarity index 86% rename from log.cpp rename to log/log.cpp index 00dc1f51..98466e78 100644 --- a/log.cpp +++ b/log/log.cpp @@ -9,9 +9,10 @@ #include "log.hpp" -#include "term.hpp" -#include "time.hpp" -#include "cast.hpp" +#include "../term.hpp" +#include "../time.hpp" +#include "../cast.hpp" +#include "../string.hpp" #include #include @@ -40,13 +41,24 @@ ALL_LEVELS[] = { /// /// conversion is case insensitive /// throws std::range_error if unable to convert -static cruft::log::level_t -to_level (std::string name) +cruft::log::level_t +cruft::log::to_level (std::string_view name) { if (std::empty (name)) return cruft::log::EMERGENCY; - static const std::map NAME_LEVELS = { + std::string upper (name.size (), char{}); + std::transform ( + name.cbegin (), + name.cend (), + upper.begin (), + ::toupper + ); + + static constexpr struct { + char const *name; + cruft::log::level_t value; + } VALUES[] = { { "EMERGENCY", cruft::log::EMERGENCY }, { "ALERT", cruft::log::ALERT }, { "CRITICAL", cruft::log::CRITICAL }, @@ -59,13 +71,11 @@ to_level (std::string name) { "DEBUG", cruft::log::DEBUG } }; - std::transform (name.cbegin (), name.cend (), name.begin (), ::toupper); + for (auto const [key, val]: VALUES) + if (!strcmp (upper.data (), key)) + return val; - auto pos = NAME_LEVELS.find (name); - if (pos == NAME_LEVELS.end ()) - throw std::range_error (name); - - return pos->second; + throw std::invalid_argument (std::string (name)); } @@ -111,7 +121,7 @@ initial_log_level (void) return cruft::log::DEFAULT_LOG_LEVEL; try { - return to_level (env); + return cruft::log::to_level (env); } catch (...) { std::clog << "Invalid environment LOG_LEVEL: '" << env << "'\n"; return cruft::log::DEFAULT_LOG_LEVEL; @@ -160,7 +170,7 @@ needs_break (cruft::log::level_t level) return false; try { - break_level = to_level (env); + break_level = cruft::log::to_level (env); return true; } catch (...) { return false; @@ -221,6 +231,22 @@ level_width (void) /////////////////////////////////////////////////////////////////////////////// void cruft::log::write (level_t level, const std::string &msg) +{ + return write (level, std::string_view (msg)); +} + + +//----------------------------------------------------------------------------- +void +cruft::log::write (level_t level, char const *msg) +{ + return write (level, std::string_view (msg)); +} + + +//----------------------------------------------------------------------------- +void +cruft::log::write (level_t level, std::string_view msg) { if (level <= log_level ()) { static const size_t time_len = strlen("YYYY-mm-dd HHMMhSS") + 1; diff --git a/log/log.hpp b/log/log.hpp new file mode 100644 index 00000000..6d281548 --- /dev/null +++ b/log/log.hpp @@ -0,0 +1,166 @@ +/* + * 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); + level_t to_level (std::string_view); + + //------------------------------------------------------------------------- + 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, std::string const &msg); + void write (level_t, char const *msg); + void write (level_t, std::string_view msg); + + + //------------------------------------------------------------------------- + template + void + write (level_t l, FormatT fmt, ArgsT &&...args) + { + write ( + l, + to_string ( + format::printf ( + std::forward (fmt), + std::forward (args)... + ) + ) + ); + } + + + //------------------------------------------------------------------------- + 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; + }; +}