atscppapi  1.0.9
C++ wrapper for Apache Traffic Server API
 All Classes Files Functions Enumerations Enumerator Macros
Logger.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 LinkedIn Corp. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of the license at
5  * http://www.apache.org/licenses/LICENSE-2.0
6  *
7  * Unless required by applicable law or agreed to in writing, software distributed under the
8  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
9  * either express or implied.
10  *
11  */
12 
13 /**
14  * @file Logger.h
15  * @author Brian Geffon
16  * @author Manjesh Nilange
17  * @brief Helpers and Classes related to Logging
18  *
19  * @warning Log rolling doesn't work correctly in 3.2.x see:
20  * https://issues.apache.org/jira/browse/TS-1813
21  * Apply the patch in TS-1813 to correct log rolling in 3.2.x
22  *
23  */
24 
25 #pragma once
26 #ifndef ATSCPPAPI_LOGGER_H_
27 #define ATSCPPAPI_LOGGER_H_
28 
29 #include <string>
30 #include <atscppapi/noncopyable.h>
31 
32 #if !defined(ATSCPPAPI_PRINTFLIKE)
33 #if defined(__GNUC__) || defined(__clang__)
34 /**
35  * This macro will tell GCC that the function takes printf like arugments
36  * this is helpful because it can produce better warning and error messages
37  * when a user doesn't use the methods correctly.
38  *
39  * @private
40  */
41 #define ATSCPPAPI_PRINTFLIKE(fmt, arg) __attribute__((format(printf, fmt, arg)))
42 #else
43 #define ATSCPPAPI_PRINTFLIKE(fmt, arg)
44 #endif
45 #endif
46 
47 /**
48  * A helper macro for Logger objects that allows you to easily add a debug level message
49  * which will include file, line, and function name with the message. It's very easy to use:
50  * \code
51  * // Suppose you have already created a Logger named logger:
52  * LOG_DEBUG(logger, "This is a test DEBUG message: %s", "hello");
53  * // Outputs [file.cc:125, function()] [DEBUG] This is a test DEBUG message: hello.
54  * \endcode
55  */
56 #define LOG_DEBUG(log, fmt, ...) \
57  do { \
58  (log).logDebug("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
59  } while (false)
60 
61 /**
62  * A helper macro for Logger objects that allows you to easily add a info level message
63  * which will include file, line, and function name with the message. See example in LOG_DEBUG
64  */
65 #define LOG_INFO(log, fmt, ...) \
66  do { \
67  (log).logInfo("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
68  } while (false)
69 
70 /**
71  * A helper macro for Logger objects that allows you to easily add a error level message
72  * which will include file, line, and function name with the message. See example in LOG_DEBUG
73  */
74 #define LOG_ERROR(log, fmt, ...) \
75  do { \
76  (log).logError("[%s:%d, %s()] " fmt, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
77  } while (false)
78 
79 /**
80  * We forward declare this because if we didn't we end up writing our
81  * own version to do the vsnprintf just to call TSDebug and have it do
82  * an unncessary vsnprintf.
83  *
84  * @private
85  */
86 extern "C" void TSDebug(const char *tag, const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
87 
88 /**
89  * We forward declare this because if we didn't we end up writing our
90  * own version to do the vsnprintf just to call TSError and have it do
91  * an unncessary vsnprintf.
92  *
93  * @private
94  */
95 extern "C" void TSError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(1,2);
96 
97 // This is weird, but see the following:
98 // http://stackoverflow.com/questions/5641427/how-to-make-preprocessor-generate-a-string-for-line-keyword
99 #define STRINGIFY0(x) #x
100 #define STRINGIFY(x) STRINGIFY0(x)
101 #define LINE_NO STRINGIFY(__LINE__)
102 
103 /**
104  * A helper macro to get access to the Diag messages available in traffic server. These can be enabled
105  * via traffic_server -T "tag.*" or since this macro includes the file can you further refine to an
106  * individual file or even a particular line! This can also be enabled via records.config.
107  */
108 #define TS_DEBUG(tag, fmt, ...) \
109  do { \
110  TSDebug(tag "." __FILE__ ":" LINE_NO , "[%s()] " fmt, __FUNCTION__, ## __VA_ARGS__); \
111  } while (false)
112 
113 /**
114  * A helper macro to get access to the error.log messages available in traffic server. This
115  * will also output a DEBUG message visible via traffic_server -T "tag.*", or by enabling the
116  * tag in records.config.
117  */
118 #define TS_ERROR(tag, fmt, ...) \
119  do { \
120  TS_DEBUG(tag, "[ERROR] " fmt, ## __VA_ARGS__); \
121  TSError("[%s] [%s:%d, %s()] " fmt, tag, __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__); \
122  } while (false)
123 
124 namespace atscppapi {
125 
126 class LoggerState;
127 
128 /**
129  * @brief Create log files that are automatically rolled and cleaned up as space is required.
130  *
131  * Log files created using the Logger class will be placed in the same directory as
132  * other log files, that directory is specified in records.config. All of the logging
133  * configuration such as max space available for all logs includes any logs created
134  * using the Logger class.
135  *
136  * Loggers are very easy to use and a full example is available in examples/logger_example/,
137  * a simple example is:
138  * \code
139  * // See Logger::init() for an explanation of the init() parameters.
140  * log.init("logger_example", true, true, Logger::LOG_LEVEL_DEBUG);
141  * // You have two ways to log to a logger, you can log directly on the object itself:
142  * log.logInfo("Hello World from: %s", argv[0]);
143  * // Alternatively you can take advantage of the super helper macros for logging
144  * // that will include the file, function, and line number automatically as part
145  * // of the log message:
146  * LOG_INFO(log, "Hello World with more info from: %s", argv[0]);
147  * \endcode
148  *
149  * @warning Log rolling doesn't work correctly in 3.2.x see:
150  * https://issues.apache.org/jira/browse/TS-1813
151  * Apply the patch in TS-1813 to correct log rolling in 3.2.x
152  *
153  */
154 class Logger : noncopyable {
155 public:
156 
157  /**
158  * The available log levels
159  */
160  enum LogLevel {
161  LOG_LEVEL_NO_LOG = 128, /**< This log level is used to disable all logging */
162  LOG_LEVEL_DEBUG = 1, /**< This log level is used for DEBUG level logging (DEBUG + INFO + ERROR) */
163  LOG_LEVEL_INFO = 2, /**< This log level is used for INFO level logging (INFO + ERROR) */
164  LOG_LEVEL_ERROR = 4 /**< This log level is used for ERROR level logging (ERROR ONLY) */
165  };
166 
167  Logger();
168  ~Logger();
169 
170  /**
171  * You must always init() a Logger before you begin logging. If you do not call init() nothing will
172  * happen.
173  *
174  * @param file The name of the file to create in the logging directory, if you do not specify an extension .log will be used.
175  * @param add_timestamp Prepend a timestamp to the log lines, the default value is true.
176  * @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,
177  * the default value for this argument is true.
178  * @param level the default log level to use when creating the logger, this is set to LOG_LEVEL_INFO by default.
179  * @param rolling_enabled if set to true this will enable log rolling on a periodic basis, this is enabled by default.
180  * @param rolling_interval_seconds how frequently to roll the longs in seconds, this is set to 3600 by default (one hour).
181  * @return returns true if the logger was successfully created and initialized.
182  * @see LogLevel
183  */
184  bool init(const std::string &file, bool add_timestamp = true, bool rename_file = true,
185  LogLevel level = LOG_LEVEL_INFO, bool rolling_enabled = true, int rolling_interval_seconds = 3600);
186 
187  /**
188  * Allows you to change the rolling interval in seconds
189  * @param seconds the number of seconds between rolls
190  */
191  void setRollingIntervalSeconds(int seconds);
192 
193  /**
194  * @return the number of seconds between log rolls.
195  */
196  int getRollingIntervalSeconds() const;
197 
198  /**
199  * Enables or disables log rolling
200  * @param enabled true to enable log rolling, false to disable it.
201  */
202  void setRollingEnabled(bool enabled);
203 
204  /**
205  * @return A boolean value which represents whether rolling is enabled or disabled.
206  */
207  bool isRollingEnabled() const;
208 
209  /**
210  * Change the log level
211  *
212  * @param level the new log level to use
213  * @see LogLevel
214  */
215  void setLogLevel(Logger::LogLevel level);
216 
217  /**
218  * @return The current log level.
219  * @see LogLevel
220  */
222 
223  /**
224  * This method allows you to flush any log lines that might have been buffered.
225  * @warning This method can cause serious performance degredation so you should only
226  * use it when absolutely necessary.
227  */
228  void flush();
229 
230  /**
231  * This method writes a DEBUG level message to the log file, the LOG_DEBUG
232  * macro in Logger.h should be used in favor of these when possible because it
233  * will produce a much more rich debug message.
234  *
235  * Sample usage:
236  * \code
237  * log.logDebug("Hello you are %d years old", 27);
238  * \endcode
239  */
240  void logDebug(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
241 
242  /**
243  * This method writes an INFO level message to the log file, the LOG_INFO
244  * macro in Logger.h should be used in favor of these when possible because it
245  * will produce a much more rich info message.
246  */
247  void logInfo(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
248 
249  /**
250  * This method writes an ERROR level message to the log file, the LOG_ERROR
251  * macro in Logger.h should be used in favor of these when possible because it
252  * will produce a much more rich error message.
253  */
254  void logError(const char *fmt, ...) ATSCPPAPI_PRINTFLIKE(2,3);
255 private:
256  LoggerState *state_; /**< Internal state for the Logger */
257 };
258 
259 } /* atscppapi */
260 
261 
262 
263 
264 #endif /* ATSCPPAPI_LOGGER_H_ */