/include/tite/core/log/detail/Log_.hpp
C++ Header | 291 lines | 177 code | 27 blank | 87 comment | 5 complexity | e68bb19e167d9091ee7dc9b36819ff8a MD5 | raw file
1/**************************************************************************** 2** Tite Interactive Text Engine (TiTE) 3** Copyright (C) 2010 Eisoft Group 4** 5** This file is part of TiTE. 6** 7** TiTE is free software: you can redistribute it and/or modify 8** it under the terms of the GNU General Public License as published by 9** the Free Software Foundation, either version 3 of the License, or 10** (at your option) any later version. 11** 12** TiTE is distributed in the hope that it will be useful, 13** but WITHOUT ANY WARRANTY; without even the implied warranty of 14** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15** GNU General Public License for more details. 16** 17** You should have received a copy of the GNU General Public License 18** along with TiTE. If not, see <http://www.gnu.org/licenses/>. 19****************************************************************************/ 20 21/*! 22 * \file Log_.hpp 23 * 24 * \date 01/10/2011 25 */ 26 27#ifndef TITE_CORE_LOG__HPP 28#define TITE_CORE_LOG__HPP 29 30#include <algorithm> 31#include <ctime> 32#include <string> 33#include <vector> 34 35#include <tite/core/log/ILogListener.hpp> 36 37/*! 38 * \namespace tite 39 * 40 * \brief The TiTE namespace. 41 */ 42namespace tite 43{ 44 /*! 45 * \namespace core 46 * 47 * \brief The TiTE core namespace. 48 */ 49 namespace core 50 { 51 /*! 52 * \class Log_ Log_.hpp 53 * 54 * \brief A simple, efficient generic logging class. 55 * 56 * \note The Container template parameter expects an STL-style container. 57 * 58 * \author Jason Omahen 59 * \version 0.02, 12/18/2010 60 */ 61 template< 62 typename T, 63 typename Listener = ILogListener, 64 template <typename, typename> class Container = stdext::vector, 65 typename Allocator = stdext::allocator<T> 66 > 67 class Log_ 68 { 69 // Log_ helper functions to provide a simple interface 70 friend Log_& log_I(void); 71 #if defined(DEBUG) || defined(_DEBUG) 72 friend Log_& log_D(void); 73 #endif 74 friend Log_& log_W(void); 75 friend Log_& log_C(void); 76 friend Log_& log_F(void); 77 78 public: 79 typedef T log_elem_t; 80 typedef Listener listener_t; 81 typedef listener_t* listener_ptr_t; 82 typedef listener_t *const listener_const_ptr_t; 83 84 Log_(void); 85 ~Log_(void); 86 87 void log(const stdext::string & message, log_levels::LogLevel messageLevel); 88 89 void addListener(listener_const_ptr_t pLogListener); 90 void removeListener(listener_const_ptr_t pLogListener); 91 92 template<typename U> 93 Log_& operator<<(const U & u); 94 95 private: 96 char* _getLocalTime(void); 97 void _prepare(log_levels::LogLevel l); 98 void _writeToBuffer(const stdext::string & message); 99 100 std::time_t m_rawTime; 101 log_levels::LogLevel m_currentLogLevel; 102 103 Container<T, Allocator> m_logBuffer; 104 Container<listener_ptr_t, Allocator> m_logListeners; 105 }; 106 107 /*! 108 * \brief Log_ ctor. 109 */ 110 template< 111 typename T, 112 typename Listener, 113 template <typename, typename> class Container, 114 typename Allocator 115 > 116 Log_<T, Listener, Container, Allocator>::Log_(void) 117 : m_currentLogLevel(log_levels::None) 118 { 119 log("[Log Singleton] Starting up ...\n", log_levels::Info); 120 } 121 122 /*! 123 * \brief Log_ dtor. 124 */ 125 template< 126 typename T, 127 typename Listener, 128 template <typename, typename> class Container, 129 typename Allocator 130 > 131 Log_<T, Listener, Container, Allocator>::~Log_(void) 132 { 133 log("[Log Singleton] Shutting down ...\n", log_levels::Warning); 134 135 for (Container<listener_ptr_t, Allocator>::iterator it = m_logListeners.begin(); it != m_logListeners.end(); ++it) 136 safe_delete(&(*it)); 137 } 138 139 /*! 140 * \brief Logs a message at the specified log level. 141 * 142 * \param message Contents to log. 143 * \param messageLevel Message type. 144 */ 145 template< 146 typename T, 147 typename Listener, 148 template <typename, typename> class Container, 149 typename Allocator 150 > 151 void Log_<T, Listener, Container, Allocator>::log(const std::string & message, log_levels::LogLevel messageLevel) 152 { 153 _prepare(messageLevel); 154 _writeToBuffer(message); 155 } 156 157 template< 158 typename T, 159 typename Listener, 160 template <typename, typename> class Container, 161 typename Allocator 162 > 163 void Log_<T, Listener, Container, Allocator>::addListener(typename Log_<T, Listener, Container, Allocator>::listener_const_ptr_t pLogListener) 164 { 165 if (pLogListener) 166 m_logListeners.push_back(pLogListener); 167 } 168 169 template< 170 typename T, 171 typename Listener, 172 template <typename, typename> class Container, 173 typename Allocator 174 > 175 void Log_<T, Listener, Container, Allocator>::removeListener(typename Log_<T, Listener, Container, Allocator>::listener_const_ptr_t pLogListener) 176 { 177 m_logListeners.erase(stdext::remove(m_logListeners.begin(), 178 m_logListeners.end(), 179 pLogListener), 180 m_logListeners.end()); 181 } 182 183 /*! 184 * \brief Overloaded "stream" insertion operator; writes contents directly 185 * to the log buffer. 186 * 187 * \note Use in conjunction with the log_X helper functions for increased 188 * clarity and simplicity. 189 * 190 * \param u std::string-convertable message to log. 191 * 192 * \return Modified Log_ object after message was logged. 193 */ 194 template< 195 typename T, 196 typename Listener, 197 template <typename, typename> class Container, 198 typename Allocator 199 > 200 template<typename U> 201 Log_<T, Listener, Container, Allocator>& Log_<T, Listener, Container, Allocator>::operator<<(const U & u) 202 { 203 _writeToBuffer(u); 204 return *this; 205 } 206 207 /*! 208 * \brief Formats the computer's local date/time into an ASCII string. 209 * 210 * \return The local date/time. 211 */ 212 template< 213 typename T, 214 typename Listener, 215 template <typename, typename> class Container, 216 typename Allocator 217 > 218 char* Log_<T, Listener, Container, Allocator>::_getLocalTime(void) 219 { 220 std::time(&m_rawTime); 221 return std::asctime(std::localtime(&m_rawTime)); 222 } 223 224 /*! 225 * \brief Prepares the logging buffer for a specific LogLevel. 226 * 227 * \param l Logging level. 228 */ 229 template< 230 typename T, 231 typename Listener, 232 template <typename, typename> class Container, 233 typename Allocator 234 > 235 void Log_<T, Listener, Container, Allocator>::_prepare(log_levels::LogLevel l) 236 { 237 stdext::string header, time(_getLocalTime()); 238 239 // Remove \n character from the time string 240 time.pop_back(); 241 242 switch (l) 243 { 244 case log_levels::Info: 245 header = "[INFO.]"; 246 break; 247 case log_levels::Debug: 248 header = "[DEBUG]"; 249 break; 250 case log_levels::Warning: 251 header = "[WARN!]"; 252 break; 253 case log_levels::Critical: 254 case log_levels::Fatal: 255 header = "[FATAL]"; 256 break; 257 } 258 header += "[" + time + "] "; 259 260 // Write the prefix message 261 m_currentLogLevel = l; 262 _writeToBuffer(header); 263 } 264 265 /*! 266 * \brief Commits the message to the internal logging buffer. 267 * 268 * \param message Contents to log. 269 */ 270 template< 271 typename T, 272 typename Listener, 273 template <typename, typename> class Container, 274 typename Allocator 275 > 276 void Log_<T, Listener, Container, Allocator>::_writeToBuffer(const stdext::string & message) 277 { 278 // A buffer may be completely unnecessary now... waste memory for already processed 279 // messages? Eh... let's rethink this! 280 m_logBuffer.insert(m_logBuffer.end(), message.begin(), message.end()); 281 stdext::for_each(m_logListeners.begin(), 282 m_logListeners.end(), 283 stdext::bind(&Listener::logMessage, 284 stdext::placeholders::_1, 285 stdext::cref(message), 286 m_currentLogLevel)); 287 } 288 }// End of core namespace 289}// End of tite namespace 290 291#endif /* TITE_CORE_LOG__HPP */