1 /* 2 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #ifndef __LOG_H_INCLUDED_ 27 #define __LOG_H_INCLUDED_ 28 29 #include "PlatformLogEvent.h" 30 #include "tstrings.h" 31 32 33 /* Default logger (Logger::defaultLogger()) writes log messages to 34 * the default log file. 35 * Common scenario: 36 * - main() function configures default logger: 37 * FileLogAppender appender(_T("my_log_filename.log")); 38 * Logger::defaultLogger().setAppender(appender); 39 * Logger::defaultLogger().setLogLevel(LOG_INFO); 40 * If the default file name and log level are not set, 41 * _T("jusched.log")/LOG_TRACE are used. 42 * 43 * Logger fileName specifies only file name, 44 * full path for the log file depends on the platform 45 * (usually value of the TMP env. var) 46 */ 47 48 class Logger; 49 class StreamLogAppender; 50 51 struct LogEvent: public PlatformLogEvent { 52 tstring logLevel; 53 tstring fileName; 54 int lineNum; 55 tstring funcName; 56 tstring message; 57 58 LogEvent(); 59 60 friend class Logger; 61 friend class StreamLogAppender; 62 63 private: 64 static void init(PlatformLogEvent& logEvent); 65 static void appendFormatted(const PlatformLogEvent& logEvent, 66 tstring& buffer); 67 }; 68 69 70 class LogAppender { 71 public: ~LogAppender()72 virtual ~LogAppender() { 73 } 74 virtual void append(const LogEvent& v) = 0; 75 }; 76 77 78 class NopLogAppender: public LogAppender { 79 public: append(const LogEvent & v)80 virtual void append(const LogEvent& v) {}; 81 }; 82 83 84 class TeeLogAppender: public LogAppender { 85 public: TeeLogAppender(LogAppender * first,LogAppender * second)86 TeeLogAppender(LogAppender* first, LogAppender* second): 87 first(first), second(second) { 88 } ~TeeLogAppender()89 virtual ~TeeLogAppender() { 90 } append(const LogEvent & v)91 virtual void append(const LogEvent& v) { 92 if (first) { 93 first->append(v); 94 } 95 if (second) { 96 second->append(v); 97 } 98 } 99 private: 100 LogAppender* first; 101 LogAppender* second; 102 }; 103 104 105 /** 106 * Writes log events to the given std::ostream. 107 * Supposed to be used with std::cout or std::cerr 108 */ 109 class StreamLogAppender: public LogAppender { 110 public: StreamLogAppender(std::ostream & consumer)111 explicit StreamLogAppender(std::ostream& consumer) : consumer(&consumer) { 112 } 113 114 virtual void append(const LogEvent& v); 115 116 private: 117 std::ostream* consumer; 118 }; 119 120 121 class Logger { 122 public: 123 enum LogLevel { 124 LOG_TRACE, 125 LOG_INFO, 126 LOG_WARNING, 127 LOG_ERROR 128 }; 129 130 static Logger& defaultLogger(); 131 132 explicit Logger(LogAppender& appender, LogLevel logLevel = LOG_TRACE); 133 ~Logger(); 134 setAppender(LogAppender & v)135 LogAppender& setAppender(LogAppender& v) { 136 LogAppender& oldAppender = *appender; 137 appender = &v; 138 return oldAppender; 139 } 140 getAppender()141 LogAppender& getAppender() const { 142 return *appender; 143 } 144 145 void setLogLevel(LogLevel logLevel); 146 147 bool isLoggable(LogLevel logLevel) const ; 148 void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, 149 LPCTSTR funcName, const tstring& message) const; log(LogLevel logLevel,LPCTSTR fileName,int lineNum,LPCTSTR funcName,const tstrings::any & message)150 void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, 151 LPCTSTR funcName, const tstrings::any& message) const { 152 return log(logLevel, fileName, lineNum, funcName, message.tstr()); 153 } log(LogLevel logLevel,LPCTSTR fileName,int lineNum,LPCTSTR funcName,tstring::const_pointer message)154 void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, 155 LPCTSTR funcName, tstring::const_pointer message) const { 156 return log(logLevel, fileName, lineNum, funcName, tstring(message)); 157 } 158 159 // internal class for scope tracing 160 class ScopeTracer { 161 public: 162 ScopeTracer(Logger &logger, LogLevel logLevel, LPCTSTR fileName, 163 int lineNum, LPCTSTR funcName, const tstring& scopeName); 164 ~ScopeTracer(); 165 166 private: 167 const Logger &log; 168 const LogLevel level; 169 const tstring file; 170 const int line; 171 const tstring func; 172 const tstring scope; 173 const bool needLog; 174 }; 175 176 private: 177 static void initializingLogging(); 178 static void initializeLogging(); 179 180 private: 181 LogLevel level; 182 LogAppender* appender; 183 }; 184 185 186 class WithExtraLogAppender { 187 public: WithExtraLogAppender(LogAppender & logAppender)188 WithExtraLogAppender(LogAppender& logAppender): 189 oldLogAppender(Logger::defaultLogger().getAppender()), 190 newLogAppender(&Logger::defaultLogger().getAppender(), 191 &logAppender) { 192 Logger::defaultLogger().setAppender(newLogAppender); 193 } 194 ~WithExtraLogAppender()195 virtual ~WithExtraLogAppender() { 196 Logger::defaultLogger().setAppender(oldLogAppender); 197 } 198 199 private: 200 LogAppender& oldLogAppender; 201 TeeLogAppender newLogAppender; 202 }; 203 204 205 // base logging macro 206 #define LOGGER_LOG(logger, logLevel, message) \ 207 do { \ 208 if (logger.isLoggable(logLevel)) { \ 209 logger.log(logLevel, _T(__FILE__), __LINE__, _T(__FUNCTION__), message); \ 210 } \ 211 } while(false) 212 213 214 // custom logger macros 215 #define LOGGER_TRACE(logger, message) LOGGER_LOG(logger, Logger::LOG_TRACE, message) 216 #define LOGGER_INFO(logger, message) LOGGER_LOG(logger, Logger::LOG_INFO, message) 217 #define LOGGER_WARNING(logger, message) LOGGER_LOG(logger, Logger::LOG_WARNING, message) 218 #define LOGGER_ERROR(logger, message) LOGGER_LOG(logger, Logger::LOG_ERROR, message) 219 // scope tracing macros 220 #define LOGGER_TRACE_SCOPE(logger, scopeName) \ 221 Logger::ScopeTracer tracer__COUNTER__(logger, Logger::LOG_TRACE, _T(__FILE__), __LINE__, _T(__FUNCTION__), scopeName) 222 #define LOGGER_TRACE_FUNCTION(logger) LOGGER_TRACE_SCOPE(logger, _T(__FUNCTION__)) 223 224 225 // default logger macros 226 #define LOG_TRACE(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_TRACE, message) 227 #define LOG_INFO(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_INFO, message) 228 #define LOG_WARNING(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_WARNING, message) 229 #define LOG_ERROR(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_ERROR, message) 230 // scope tracing macros 231 // logs (_T("Entering ") + scopeName) at the beging, (_T("Exiting ") + scopeName) at the end of scope 232 #define LOG_TRACE_SCOPE(scopeName) LOGGER_TRACE_SCOPE(Logger::defaultLogger(), scopeName) 233 // logs (_T("Entering ") + functionName) at the beging, (_T("Exiting ") + __FUNCTION__) at the end of scope 234 #define LOG_TRACE_FUNCTION() LOGGER_TRACE_FUNCTION(Logger::defaultLogger()) 235 236 237 #endif // __LOG_H_INCLUDED_ 238