1 /** \file logstream.hxx 2 * Stream based logging mechanism. 3 */ 4 5 // Written by Bernie Bright, 1998 6 // 7 // Copyright (C) 1998 Bernie Bright - bbright@c031.aone.net.au 8 // 9 // This library is free software; you can redistribute it and/or 10 // modify it under the terms of the GNU Library General Public 11 // License as published by the Free Software Foundation; either 12 // version 2 of the License, or (at your option) any later version. 13 // 14 // This library is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 // Library General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with this program; if not, write to the Free Software 21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 // 23 // $Id$ 24 25 #ifndef _LOGSTREAM_H 26 #define _LOGSTREAM_H 27 28 #include <simgear/compiler.h> 29 #include <simgear/debug/debug_types.h> 30 31 #include <sstream> 32 #include <vector> 33 #include <memory> 34 35 // forward decls 36 class SGPath; 37 38 namespace simgear 39 { 40 41 class LogCallback; 42 /** 43 * Helper force a console on platforms where it might optional, when 44 * we need to show a console. This basically means Windows at the 45 * moment - on other plaforms it's a no-op 46 */ 47 void requestConsole(); 48 49 void shutdownLogging(); 50 51 } // of namespace simgear 52 53 /** 54 * Class to manage the debug logging stream. 55 */ 56 class logstream 57 { 58 public: 59 ~logstream(); 60 61 static void initGlobalLogstream(); 62 63 /** 64 * Helper force a console on platforms where it might optional, when 65 * we need to show a console. This basically means Windows at the 66 * moment - on other plaforms it's a no-op 67 */ 68 void requestConsole(); 69 70 /** 71 * Set the global log class and priority level. 72 * @param c debug class 73 * @param p priority 74 */ 75 void setLogLevels( sgDebugClass c, sgDebugPriority p ); 76 77 bool would_log( sgDebugClass c, sgDebugPriority p ) const; 78 79 void logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p ); 80 81 void set_log_priority( sgDebugPriority p); 82 83 void set_log_classes( sgDebugClass c); 84 85 sgDebugClass get_log_classes() const; 86 87 sgDebugPriority get_log_priority() const; 88 89 /** 90 @brief convert a string value to a log prioirty. 91 throws std::invalid_argument if the string is not valid 92 */ 93 static sgDebugPriority priorityFromString(const std::string& s); 94 /** 95 * set developer mode on/off. In developer mode, SG_DEV_WARN messags 96 * are treated as warnings. In normal (non-developer) mode they are 97 * treated as SG_DEBUG. 98 */ 99 void setDeveloperMode(bool devMode); 100 101 /** 102 * set output of file:line mode on/off. If on, all log messages are 103 * prefixed by the file:line of the caller of SG_LOG(). 104 */ 105 void setFileLine(bool fileLine); 106 107 /** 108 * the core logging method 109 */ 110 void log( sgDebugClass c, sgDebugPriority p, 111 const char* fileName, int line, const std::string& msg); 112 113 // overload of above, which can transfer ownership of the file-name. 114 // this is unecesary overhead when logging from C++, since __FILE__ points 115 // to constant data, but it's needed when the filename is Nasal data (for 116 // example) since during shutdown the filename is freed by Nasal GC 117 // asynchronously with the logging thread. 118 void logCopyingFilename( sgDebugClass c, sgDebugPriority p, 119 const char* fileName, int line, const std::string& msg); 120 121 /** 122 * output formatted hex dump of memory block 123 */ 124 void hexdump(sgDebugClass c, sgDebugPriority p, const char* fileName, int line, const void *mem, unsigned int len, unsigned int columns = 16); 125 126 127 /** 128 * support for the SG_POPUP logging class 129 * set the content of the popup message 130 */ 131 void popup( const std::string& msg); 132 133 /** 134 * retrieve the contents of the popup message and clear it's internal 135 * content. The return value may be an empty string. 136 */ 137 std::string get_popup(); 138 139 /** 140 * return true if a new popup message is available. false otherwise. 141 */ 142 bool has_popup(); 143 144 /** 145 * \relates logstream 146 * Return the one and only logstream instance. 147 * We use a function instead of a global object so we are assured that cerr 148 * has been initialised. 149 * @return current logstream 150 */ 151 friend logstream& sglog(); 152 153 /** 154 * register a logging callback. Note callbacks are run in a 155 * dedicated thread, so callbacks which pass data to other threads 156 * must use appropriate locking. 157 */ 158 void addCallback(simgear::LogCallback* cb); 159 160 void removeCallback(simgear::LogCallback* cb); 161 162 void removeCallbacks(); 163 164 /** 165 * optionally record all entries and submit them to new log callbacks that 166 * are added. This allows simplified logging configuration, but still including 167 * early startup information in all logs. 168 */ 169 void setStartupLoggingEnabled(bool enabled); 170 171 /** 172 * Set up the logstream for running in test mode. For example the callbacks 173 * will be unregistered and the behaviour of the would_log() function 174 * sanitized. 175 */ 176 void setTestingMode(bool testMode); 177 178 private: 179 // constructor 180 logstream(); 181 182 class LogStreamPrivate; 183 184 std::unique_ptr<LogStreamPrivate> d; 185 }; 186 187 logstream& sglog(); 188 189 190 191 /** \def SG_LOG(C,P,M) 192 * Log a message. 193 * @param C debug class 194 * @param P priority 195 * @param M message 196 */ 197 # define SG_LOGX(C,P,M) \ 198 do { if(sglog().would_log(C,P)) { \ 199 std::ostringstream os; os << M; \ 200 sglog().log(C, P, __FILE__, __LINE__, os.str()); \ 201 if ((P) == SG_POPUP) sglog().popup(os.str()); \ 202 } } while(0) 203 #ifdef FG_NDEBUG 204 # define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0) 205 # define SG_LOG_NAN(C,P,M) SG_LOG(C,P,M) 206 # define SG_HEXDUMP(C,P,MEM,LEN) 207 #else 208 # define SG_LOG(C,P,M) SG_LOGX(C,P,M) 209 # define SG_LOG_NAN(C,P,M) do { SG_LOGX(C,P,M); throw std::overflow_error(M); } while(0) 210 # define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN) 211 #endif 212 213 #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__) 214 215 #endif // _LOGSTREAM_H 216 217