00001 /** 00002 Licensed to the Apache Software Foundation (ASF) under one 00003 or more contributor license agreements. See the NOTICE file 00004 distributed with this work for additional information 00005 regarding copyright ownership. The ASF licenses this file 00006 to you under the Apache License, Version 2.0 (the 00007 "License"); you may not use this file except in compliance 00008 with the License. You may obtain a copy of the License at 00009 00010 http://www.apache.org/licenses/LICENSE-2.0 00011 00012 Unless required by applicable law or agreed to in writing, software 00013 distributed under the License is distributed on an "AS IS" BASIS, 00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 See the License for the specific language governing permissions and 00016 limitations under the License. 00017 */ 00018 00019 /** 00020 * @file Logger.h 00021 * @brief Helpers and Classes related to Logging 00022 * 00023 * @warning Log rolling doesn't work correctly in 3.2.x see: 00024 * https://issues.apache.org/jira/browse/TS-1813 00025 * Apply the patch in TS-1813 to correct log rolling in 3.2.x 00026 * 00027 */ 00028 00029 #pragma once 00030 #ifndef ATSCPPAPI_LOGGER_H_ 00031 #define ATSCPPAPI_LOGGER_H_ 00032 00033 #include <string> 00034 #include <atscppapi/noncopyable.h> 00035 00036 #if !defined(ATSCPPAPI_PRINTFLIKE) 00037 #if defined(__GNUC__) || defined(__clang__) 00038 /** 00039 * This macro will tell GCC that the function takes printf like arugments 00040 * this is helpful because it can produce better warning and error messages 00041 * when a user doesn't use the methods correctly. 00042 * 00043 * @private 00044 */ 00045 #define ATSCPPAPI_PRINTFLIKE(fmt, arg) __attribute__((format(printf, fmt, arg))) 00046 #else 00047 #define ATSCPPAPI_PRINTFLIKE(fmt, arg) 00048 #endif 00049 #endif 00050 00051 /** 00052 * A helper macro for Logger objects that allows you to easily add a debug level message 00053 * which will include file, line, and function name with the message. It's very easy to use: 00054 * \code 00055 * // Suppose you have already created a Logger named logger: 00056 * LOG_DEBUG(logger, "This is a test DEBUG message: %s", "hello"); 00057 * // Outputs [file.cc:125, function()] [DEBUG] This is a test DEBUG message: hello. 00058 * \endcode 00059 */ 00060 #define LOG_DEBUG(log, fmt, ...) \ 00061 do { \ 00062 (log).logDebug("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ 00063 } while (false) 00064 00065 /** 00066 * A helper macro for Logger objects that allows you to easily add a info level message 00067 * which will include file, line, and function name with the message. See example in LOG_DEBUG 00068 */ 00069 #define LOG_INFO(log, fmt, ...) \ 00070 do { \ 00071 (log).logInfo("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ 00072 } while (false) 00073 00074 /** 00075 * A helper macro for Logger objects that allows you to easily add a error level message 00076 * which will include file, line, and function name with the message. See example in LOG_DEBUG 00077 */ 00078 #define LOG_ERROR(log, fmt, ...) \ 00079 do { \ 00080 (log).logError("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ 00081 } while (false) 00082 00083 /** 00084 * We forward declare this because if we didn't we end up writing our 00085 * own version to do the vsnprintf just to call TSDebug and have it do 00086 * an unncessary vsnprintf. 00087 * 00088 * @private 00089 */ 00090 extern "C" void TSDebug(const char *tag, const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3); 00091 00092 /** 00093 * We forward declare this because if we didn't we end up writing our 00094 * own version to do the vsnprintf just to call TSError and have it do 00095 * an unncessary vsnprintf. 00096 * 00097 * @private 00098 */ 00099 extern "C" void TSError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(1,2); 00100 00101 // This is weird, but see the following: 00102 // http://stackoverflow.com/questions/5641427/how-to-make-preprocessor-generate-a-string-for-line-keyword 00103 #define STRINGIFY0(x) #x 00104 #define STRINGIFY(x) STRINGIFY0(x) 00105 #define LINE_NO STRINGIFY(__LINE__) 00106 00107 /** 00108 * A helper macro to get access to the Diag messages available in traffic server. These can be enabled 00109 * via traffic_server -T "tag.*" or since this macro includes the file can you further refine to an 00110 * individual file or even a particular line! This can also be enabled via records.config. 00111 */ 00112 #define TS_DEBUG(tag, fmt, ...) \ 00113 do { \ 00114 TSDebug(tag "." __FILE__ ":" LINE_NO , "[%s()] " fmt, __FUNCTION__, ## __VA_ARGS__); \ 00115 } while (false) 00116 00117 /** 00118 * A helper macro to get access to the error.log messages available in traffic server. This 00119 * will also output a DEBUG message visible via traffic_server -T "tag.*", or by enabling the 00120 * tag in records.config. 00121 */ 00122 #define TS_ERROR(tag, fmt, ...) \ 00123 do { \ 00124 TS_DEBUG(tag, "[ERROR] " fmt, ## __VA_ARGS__); \ 00125 TSError("[%s] [%s:%d, %s()] " fmt, tag, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \ 00126 } while (false) 00127 00128 namespace atscppapi { 00129 00130 struct LoggerState; 00131 00132 /** 00133 * @brief Create log files that are automatically rolled and cleaned up as space is required. 00134 * 00135 * Log files created using the Logger class will be placed in the same directory as 00136 * other log files, that directory is specified in records.config. All of the logging 00137 * configuration such as max space available for all logs includes any logs created 00138 * using the Logger class. 00139 * 00140 * Loggers are very easy to use and a full example is available in examples/logger_example/, 00141 * a simple example is: 00142 * \code 00143 * // See Logger::init() for an explanation of the init() parameters. 00144 * log.init("logger_example", true, true, Logger::LOG_LEVEL_DEBUG); 00145 * // You have two ways to log to a logger, you can log directly on the object itself: 00146 * log.logInfo("Hello World from: %s", argv[0]); 00147 * // Alternatively you can take advantage of the super helper macros for logging 00148 * // that will include the file, function, and line number automatically as part 00149 * // of the log message: 00150 * LOG_INFO(log, "Hello World with more info from: %s", argv[0]); 00151 * \endcode 00152 * 00153 * @warning Log rolling doesn't work correctly in 3.2.x see: 00154 * https://issues.apache.org/jira/browse/TS-1813 00155 * Apply the patch in TS-1813 to correct log rolling in 3.2.x 00156 * 00157 */ 00158 class Logger : noncopyable { 00159 public: 00160 00161 /** 00162 * The available log levels 00163 */ 00164 enum LogLevel { 00165 LOG_LEVEL_NO_LOG = 128, /**< This log level is used to disable all logging */ 00166 LOG_LEVEL_DEBUG = 1, /**< This log level is used for DEBUG level logging (DEBUG + INFO + ERROR) */ 00167 LOG_LEVEL_INFO = 2, /**< This log level is used for INFO level logging (INFO + ERROR) */ 00168 LOG_LEVEL_ERROR = 4 /**< This log level is used for ERROR level logging (ERROR ONLY) */ 00169 }; 00170 00171 Logger(); 00172 ~Logger(); 00173 00174 /** 00175 * You must always init() a Logger before you begin logging. If you do not call init() nothing will 00176 * happen. 00177 * 00178 * @param file The name of the file to create in the logging directory, if you do not specify an extension .log will be used. 00179 * @param add_timestamp Prepend a timestamp to the log lines, the default value is true. 00180 * @param rename_file If a file already exists by the same name it will attempt to rename using a scheme that appends .1, .2, and so on, 00181 * the default value for this argument is true. 00182 * @param level the default log level to use when creating the logger, this is set to LOG_LEVEL_INFO by default. 00183 * @param rolling_enabled if set to true this will enable log rolling on a periodic basis, this is enabled by default. 00184 * @param rolling_interval_seconds how frequently to roll the longs in seconds, this is set to 3600 by default (one hour). 00185 * @return returns true if the logger was successfully created and initialized. 00186 * @see LogLevel 00187 */ 00188 bool init(const std::string &file, bool add_timestamp = true, bool rename_file = true, 00189 LogLevel level = LOG_LEVEL_INFO, bool rolling_enabled = true, int rolling_interval_seconds = 3600); 00190 00191 /** 00192 * Allows you to change the rolling interval in seconds 00193 * @param seconds the number of seconds between rolls 00194 */ 00195 void setRollingIntervalSeconds(int seconds); 00196 00197 /** 00198 * @return the number of seconds between log rolls. 00199 */ 00200 int getRollingIntervalSeconds() const; 00201 00202 /** 00203 * Enables or disables log rolling 00204 * @param enabled true to enable log rolling, false to disable it. 00205 */ 00206 void setRollingEnabled(bool enabled); 00207 00208 /** 00209 * @return A boolean value which represents whether rolling is enabled or disabled. 00210 */ 00211 bool isRollingEnabled() const; 00212 00213 /** 00214 * Change the log level 00215 * 00216 * @param level the new log level to use 00217 * @see LogLevel 00218 */ 00219 void setLogLevel(Logger::LogLevel level); 00220 00221 /** 00222 * @return The current log level. 00223 * @see LogLevel 00224 */ 00225 Logger::LogLevel getLogLevel() const; 00226 00227 /** 00228 * This method allows you to flush any log lines that might have been buffered. 00229 * @warning This method can cause serious performance degredation so you should only 00230 * use it when absolutely necessary. 00231 */ 00232 void flush(); 00233 00234 /** 00235 * This method writes a DEBUG level message to the log file, the LOG_DEBUG 00236 * macro in Logger.h should be used in favor of these when possible because it 00237 * will produce a much more rich debug message. 00238 * 00239 * Sample usage: 00240 * \code 00241 * log.logDebug("Hello you are %d years old", 27); 00242 * \endcode 00243 */ 00244 void logDebug(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3); 00245 00246 /** 00247 * This method writes an INFO level message to the log file, the LOG_INFO 00248 * macro in Logger.h should be used in favor of these when possible because it 00249 * will produce a much more rich info message. 00250 */ 00251 void logInfo(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3); 00252 00253 /** 00254 * This method writes an ERROR level message to the log file, the LOG_ERROR 00255 * macro in Logger.h should be used in favor of these when possible because it 00256 * will produce a much more rich error message. 00257 */ 00258 void logError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3); 00259 private: 00260 LoggerState *state_; /**< Internal state for the Logger */ 00261 }; 00262 00263 } /* atscppapi */ 00264 00265 00266 00267 00268 #endif /* ATSCPPAPI_LOGGER_H_ */