1 /*
   2  * Copyright (c) 2019, 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 <windows.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 struct LogEvent {
  49     SYSTEMTIME ts;
  50     long tid;
  51     long pid;
  52     tstring moduleName;
  53     tstring logLevel;
  54     tstring fileName;
  55     int lineNum;
  56     tstring funcName;
  57     tstring message;
  58 
  59     LogEvent();
  60 };
  61 
  62 
  63 class LogAppender {
  64 public:
  65     virtual ~LogAppender() {
  66     }
  67     virtual void append(const LogEvent& v) = 0;
  68 };
  69 
  70 
  71 class NopLogAppender: public LogAppender {
  72 public:
  73     virtual void append(const LogEvent& v) {};
  74 };
  75 
  76 
  77 class TeeLogAppender: public LogAppender {
  78 public:
  79     TeeLogAppender(LogAppender* first, LogAppender* second):
  80             first(first), second(second) {
  81     }
  82     virtual ~TeeLogAppender() {
  83     }
  84     virtual void append(const LogEvent& v) {
  85         if (first) {
  86             first->append(v);
  87         }
  88         if (second) {
  89             second->append(v);
  90         }
  91     }
  92 private:
  93     LogAppender* first;
  94     LogAppender* second;
  95 };
  96 
  97 
  98 /**
  99  * Writes log events to stderr.
 100  */
 101 class StderrLogAppender: public LogAppender {
 102 public:
 103     explicit StderrLogAppender();
 104 
 105     virtual void append(const LogEvent& v);
 106 };
 107 
 108 
 109 class Logger {
 110 public:
 111     enum LogLevel {
 112         LOG_TRACE,
 113         LOG_INFO,
 114         LOG_WARNING,
 115         LOG_ERROR
 116     };
 117 
 118     static Logger& defaultLogger();
 119 
 120     explicit Logger(LogAppender& appender, LogLevel logLevel = LOG_TRACE);
 121     ~Logger();
 122 
 123     LogAppender& setAppender(LogAppender& v) {
 124         LogAppender& oldAppender = *appender;
 125         appender = &v;
 126         return oldAppender;
 127     }
 128 
 129     LogAppender& getAppender() const {
 130         return *appender;
 131     }
 132 
 133     void setLogLevel(LogLevel logLevel);
 134 
 135     bool isLoggable(LogLevel logLevel) const ;
 136     void log(LogLevel logLevel, LPCTSTR fileName, int lineNum,
 137             LPCTSTR funcName, const tstring& message) const;
 138     void log(LogLevel logLevel, LPCTSTR fileName, int lineNum,
 139             LPCTSTR funcName, const tstrings::any& message) const {
 140         return log(logLevel, fileName, lineNum, funcName, message.tstr());
 141     }
 142     void log(LogLevel logLevel, LPCTSTR fileName, int lineNum,
 143             LPCTSTR funcName, tstring::const_pointer message) const {
 144         return log(logLevel, fileName, lineNum, funcName, tstring(message));
 145     }
 146 
 147     // internal class for scope tracing
 148     class ScopeTracer {
 149     public:
 150         ScopeTracer(Logger &logger, LogLevel logLevel, LPCTSTR fileName,
 151                 int lineNum, LPCTSTR funcName, const tstring& scopeName);
 152         ~ScopeTracer();
 153 
 154     private:
 155         const Logger &log;
 156         const LogLevel level;
 157         const bool needLog;
 158         const tstring file;
 159         const int line;
 160         const tstring func;
 161         const tstring scope;
 162     };
 163 
 164 private:
 165     LogLevel level;
 166     LogAppender* appender;
 167 };
 168 
 169 
 170 // base logging macro
 171 #define LOGGER_LOG(logger, logLevel, message) \
 172     do { \
 173         if (logger.isLoggable(logLevel)) { \
 174             logger.log(logLevel, _T(__FILE__), __LINE__, _T(__FUNCTION__), message); \
 175         } \
 176     } while(false)
 177 
 178 
 179 // custom logger macros
 180 #define LOGGER_TRACE(logger, message)   LOGGER_LOG(logger, Logger::LOG_TRACE, message)
 181 #define LOGGER_INFO(logger, message)    LOGGER_LOG(logger, Logger::LOG_INFO, message)
 182 #define LOGGER_WARNING(logger, message) LOGGER_LOG(logger, Logger::LOG_WARNING, message)
 183 #define LOGGER_ERROR(logger, message)   LOGGER_LOG(logger, Logger::LOG_ERROR, message)
 184 // scope tracing macros
 185 #define LOGGER_TRACE_SCOPE(logger, scopeName) \
 186     Logger::ScopeTracer tracer__COUNTER__(logger, Logger::LOG_TRACE, _T(__FILE__), __LINE__, _T(__FUNCTION__), scopeName)
 187 #define LOGGER_TRACE_FUNCTION(logger)   LOGGER_TRACE_SCOPE(logger, _T(__FUNCTION__))
 188 
 189 
 190 // default logger macros
 191 #define LOG_TRACE(message)              LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_TRACE, message)
 192 #define LOG_INFO(message)               LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_INFO, message)
 193 #define LOG_WARNING(message)            LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_WARNING, message)
 194 #define LOG_ERROR(message)              LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_ERROR, message)
 195 // scope tracing macros
 196 // logs (_T("Entering ") + scopeName) at the beging, (_T("Exiting ") + scopeName) at the end of scope
 197 #define LOG_TRACE_SCOPE(scopeName)      LOGGER_TRACE_SCOPE(Logger::defaultLogger(), scopeName)
 198 // logs (_T("Entering ") + functionName) at the beging, (_T("Exiting ") + __FUNCTION__) at the end of scope
 199 #define LOG_TRACE_FUNCTION()            LOGGER_TRACE_FUNCTION(Logger::defaultLogger())
 200 
 201 
 202 #endif // __LOG_H_INCLUDED_