/* * 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-2016 Danny Robson */ #include "level.hpp" #include "../parse/enum.hpp" #include #include /////////////////////////////////////////////////////////////////////////////// /// convert a string representation of a log-level into an enumeration value. /// /// conversion is case insensitive /// throws std::range_error if unable to convert cruft::log::level_t cruft::log::to_level (std::string_view name) { if (std::empty (name)) return cruft::log::EMERGENCY; std::string upper (name.size (), char{}); std::transform ( name.cbegin (), name.cend (), upper.begin (), ::toupper ); #define ITEM(NAME) \ if (!strcmp (#NAME, upper.data ())) \ return NAME; MAP_LEVEL_T(ITEM) #undef ITEM throw std::invalid_argument (std::string (name)); } /////////////////////////////////////////////////////////////////////////////// const std::string& cruft::log::to_string (level_t l) { switch (l) { #define CASE(L) \ case cruft::log::L: { \ static const std::string STR = #L; \ return STR; \ } MAP_LEVEL_T(CASE) #undef CASE } unreachable (); } //----------------------------------------------------------------------------- std::ostream& cruft::log::operator<< (std::ostream& os, level_t l) { return os << to_string (l); } /////////////////////////////////////////////////////////////////////////////// // Determine what the value for LOG_LEVEL should be at the beginning of // execution given the system environment. // // Note that the LOG macros _cannot_ be used from within this function as it // will likely result in infinite recursion. static cruft::log::level_t initial_log_level (void) { const char *env = getenv ("LOG_LEVEL"); if (!env) return cruft::log::DEFAULT_LOG_LEVEL; try { return cruft::log::to_level (env); } catch (...) { std::clog << "Invalid environment LOG_LEVEL: '" << env << "'\n"; return cruft::log::DEFAULT_LOG_LEVEL; } } //----------------------------------------------------------------------------- // We shouldn't ever actually get to use the default value, but we set it to // the most verbose option just in case we've made a mistake elsewhere. static bool s_log_level_done; static cruft::log::level_t s_log_level_value; //----------------------------------------------------------------------------- cruft::log::level_t cruft::log::log_level (level_t _level) { s_log_level_value = _level; s_log_level_done = true; return s_log_level_value; } //----------------------------------------------------------------------------- cruft::log::level_t cruft::log::log_level (void) { if (!s_log_level_done) { s_log_level_value = initial_log_level (); s_log_level_done = true; } return s_log_level_value; } /////////////////////////////////////////////////////////////////////////////// std::size_t cruft::log::level_width (void) { return cruft::max ( #define ITEM(NAME) strlen(#NAME), MAP_LEVEL_T(ITEM) #undef ITEM 0u ); } /////////////////////////////////////////////////////////////////////////////// cruft::parse::enumeration::cookie cruft::log::setup_level_reflection (void) { #define ITEM(NAME) { #NAME, NAME }, return parse::enumeration::setup ( std::map { MAP_LEVEL_T(ITEM) } ); #undef ITEM }