• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Logger.h

Go to the documentation of this file.
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_ */

Generated by  doxygen 1.7.1