1 /*************************************************************************** 2 * Copyright (C) 2005-2019 by the FIFE team * 3 * http://www.fifengine.net * 4 * This file is part of FIFE. * 5 * * 6 * FIFE is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 22 #ifndef FIFE_LOGGER_H 23 #define FIFE_LOGGER_H 24 25 // Standard C++ library includes 26 #include <iomanip> 27 #include <iostream> 28 #include <list> 29 #include <sstream> 30 #include <string> 31 #include <vector> 32 #include <map> 33 #include <set> 34 35 // 3rd party library includes 36 37 // FIFE includes 38 // These includes are split up in two parts, separated by one empty line 39 // First block: files included from the FIFE root src directory 40 // Second block: files included from the same folder 41 #include "util/base/fife_stdint.h" 42 43 #include "modules.h" 44 45 #ifdef LOG_ENABLED 46 47 /** Logs given message with log level "debug" using given logger instance 48 */ 49 #define FL_DBG(logger, msg) do { if (FIFE::LogManager::instance()->isVisible(logger.getModule())) logger.log(FIFE::LogManager::LEVEL_DEBUG, msg); } while(0) 50 51 /** Logs given message with log level "log" using given logger instance 52 */ 53 #define FL_LOG(logger, msg) do { if (FIFE::LogManager::instance()->isVisible(logger.getModule())) logger.log(FIFE::LogManager::LEVEL_LOG, msg); } while(0) 54 55 /** Logs given message with log level "warning" using given logger instance 56 */ 57 #define FL_WARN(logger, msg) do { if (FIFE::LogManager::instance()->isVisible(logger.getModule())) logger.log(FIFE::LogManager::LEVEL_WARN, msg); } while(0) 58 59 /** Logs given message with log level "error" using given logger instance 60 */ 61 #define FL_ERR(logger, msg) do { if (FIFE::LogManager::instance()->isVisible(logger.getModule())) logger.log(FIFE::LogManager::LEVEL_ERROR, msg); } while(0) 62 63 /** Logs given message with log level "pacic" using given logger instance. 64 * Causes also program to abort 65 */ 66 #define FL_PANIC(logger, msg) do { if (FIFE::LogManager::instance()->isVisible(logger.getModule())) logger.log(FIFE::LogManager::LEVEL_PANIC, msg); } while(0) 67 68 #else 69 // empty definitions in case logs are turned off for speed 70 #define FL_DBG(logger, msg) 71 #define FL_LOG(logger, msg) 72 #define FL_WARN(logger, msg) 73 #define FL_ERR(logger, msg) 74 #define FL_PANIC(logger, msg) 75 #endif 76 77 namespace FIFE { 78 79 /** Helper class to create log strings out from separate parts 80 * Usage: LMsg("some text") << variable << ", " << other variable 81 */ 82 class LMsg { 83 public: str(msg)84 LMsg(const std::string& msg=""): str(msg) {} ~LMsg()85 ~LMsg() {} 86 87 template <typename T> LMsg& operator<<(const T& t) { 88 std::ostringstream stream; 89 stream << t; 90 str += stream.str(); 91 return *this; 92 } 93 94 std::string str; 95 }; 96 97 /** Logmanager takes care of log filtering and output direction 98 */ 99 class LogManager { 100 public: 101 /** Loglevel is used to set a treshold for output messages + related filter 102 * E.g. in case log message has LEVEL_WARN, but the filter treshold is LEVEL_ERROR, 103 * log message is not outputted 104 */ 105 enum LogLevel { 106 LEVEL_DEBUG = 0, 107 LEVEL_LOG = 1, 108 LEVEL_WARN = 2, 109 LEVEL_ERROR = 3, 110 LEVEL_PANIC = 4 111 }; 112 113 /** Returns instance to log manager. Log manager is a singleton class 114 */ 115 static LogManager* instance(); 116 117 /** Destructor 118 */ 119 ~LogManager(); 120 121 /** Logs given message 122 * @param level level of this log (e.g. warning) 123 * @param module module where this log message is coming from. Modules are defined in modules.h-file 124 * @param msg message to log 125 * @note do not use this method directly, instead use FL_WARN (or any other FL_XXX) macro 126 */ 127 void log(LogLevel level, logmodule_t module, const std::string& msg); 128 129 /** Sets currently used level filter. 130 * For usage, @see LogManager::LogLevel 131 */ 132 void setLevelFilter(LogLevel level); 133 134 /** Gets currently used level filter. 135 * @see LogManager::LogLevel 136 */ 137 LogLevel getLevelFilter(); 138 139 /** Adds visible module into logmanager 140 * Module corresponds some module in the engine. Modules may contain other modules. 141 * Modules and their structure is defined in file modules.h. 142 * In case module is not visible, LogManager filters corresponding log messages 143 * from output. In case some lower-level module is set visible, it also sets 144 * all upper level modules visible 145 * @param module module to set visible 146 */ 147 void addVisibleModule(logmodule_t module); 148 149 /** Removes visible module, @see addVisibleModule 150 */ 151 void removeVisibleModule(logmodule_t module); 152 153 /** Removes all visible modules, @see addVisibleModule 154 */ 155 void clearVisibleModules(); 156 157 /** Tells if given module is visible 158 */ 159 bool isVisible(logmodule_t module); 160 161 /** Sets LogManager to log to prompt 162 */ 163 void setLogToPrompt(bool logtoprompt); 164 165 /** Returns if LogManager is set to log to prompt 166 */ 167 bool isLogToPrompt(); 168 169 /** Sets LogManager to log to a file 170 */ 171 void setLogToFile(bool logtofile); 172 173 /** Returns if LogManager is set to log to a file 174 */ 175 bool isLogToFile(); 176 177 /** Gets display name for given module id 178 * E.g. LM_AUDIO -> "Audio" 179 */ 180 std::string getModuleName(logmodule_t module); 181 182 private: 183 void validateModule(logmodule_t m); 184 185 // hidden constructor for singleton 186 LogManager(); 187 // validates if definitions in module.h are valid 188 void validateModuleDescription(logmodule_t module); 189 190 // singleton instance 191 static LogManager* m_instance; 192 // current filter level 193 LogLevel m_level; 194 // visibility array for modules 195 bool m_modules[LM_MODULE_MAX]; 196 // used during module description validation to check cycles in hierarchy 197 std::vector<logmodule_t> module_check_stack; 198 199 bool m_logtofile; 200 bool m_logtoprompt; 201 202 std::ofstream* m_logfile; 203 }; 204 205 /** Create a Logger instance to communicate with LogManager 206 * Logger stores information about the current module thus reducing 207 * the typing needed for individual traces 208 * Common way of doing things is to instantiate a static Logger on 209 * top of .cpp file and then use that in .cpp-file's methods 210 */ 211 class Logger { 212 public: 213 /** Creates new logger and associates it with given module 214 */ 215 Logger(logmodule_t module); 216 217 /** Destructor 218 */ 219 ~Logger(); 220 221 /** logs given message with given log level 222 */ 223 void log(LogManager::LogLevel level, const std::string& msg); 224 225 /** logs given message with given log level. 226 * Message is wrapped into LMsg instance for easy formatting 227 */ 228 void log(LogManager::LogLevel level, const LMsg& msg); 229 230 /** gets module where this logger is associated to 231 */ getModule()232 inline logmodule_t getModule() const { return m_module; } 233 234 private: 235 logmodule_t m_module; 236 }; 237 238 /** Helper for printing a pointer 239 * 240 * This is a helper structure that allows printing any kind of pointer 241 * on (hopefully) any platform in hex, kind of like the %p format 242 * string of printf. 243 * 244 * The mechanism is used by calling something like: 245 * somestream << pprint(ptr); 246 **/ 247 struct pprint { 248 void* p; pprintpprint249 pprint( void* _p ) : p(_p) {} 250 }; 251 } 252 253 namespace std { 254 /** Print a pprint object to an ostream. 255 * 256 * This is pure Stroustrup, overloading the ostream operator<< to print 257 * a formatted pointer from a pprint object to an ostream. 258 * 259 * \param s output stream 260 * \param p pointer to print 261 * \return reference to the modified stream 262 * */ 263 template <class Ch, class Tr> 264 basic_ostream<Ch,Tr>& operator<<( basic_ostream<Ch,Tr>& s, const FIFE::pprint& p ) { 265 s << "0x" 266 << hex << setw( 2*sizeof(void*) ) << setfill('0') 267 << reinterpret_cast<uint64_t>( p.p ); 268 269 return s; 270 } 271 } 272 273 274 #endif 275