1/*---------------------------------------------------------------------------*
2 *  plog.h  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20#ifndef PLOG_H
21#define PLOG_H
22
23
24
25#include "ESR_ReturnCode.h"
26#include "PortPrefix.h"
27#ifdef USE_STACKTRACE
28#include "PStackTrace.h"
29#endif
30#include "passert.h"
31#include "PFileSystem.h"
32#include "ptypes.h"
33
34/**
35 * @addtogroup PLogModule PLogger API functions
36 * Logging API.
37 *
38 * Must call pmemInit() before using this module.
39 *
40 * The logging API is composed of a Logger.
41 * A Logger is an object who implements an API to actually write log messages.
42 * The logging API uses the logger when logging is to be performed but does
43 * not depend on an actual implementation of this API.
44 *
45 * When a request for logging is performed, the current level of the logging
46 * API is compared with the current stack-trace level.  If the logger's log
47 * level is greater than or equal to the stack-trace level, then the
48 * message is being logged through the use of the Logger.  Otherwise, the
49 * message is not logged.  Setting the log level of the API to UINT_MAX is
50 * equivalent to unconditionally log all messages from all modules. Conversely,
51 * setting the log level of the API to 0 is equivalent to disabling logging globally.
52 *
53 * @{
54 */
55
56
57/**
58 * Portable logging framework.
59 */
60typedef struct PLogger_t
61{
62  /**
63   * Prints and formats a message to the log.
64   *
65   * @param self the Logger.
66   *
67   * @param format the format string specifying the next arguments (a la
68   * printf).
69   *
70   * @return ESR_SUCCESS if success, otherwise a status code indicating the
71   * nature of the error.
72   */
73  ESR_ReturnCode(*printf)(struct PLogger_t *self,
74                          const LCHAR *format, ...);
75
76  /**
77   * Flushes internal buffer.  This function can be left unimplemented if no
78   * buffering is performed by the logger.
79
80   * @param self the Logger
81   *
82   * @return ESR_SUCCESS if success, otherwise a status code indicating the nature of the error.
83   */
84  ESR_ReturnCode(*flush)(struct PLogger_t *self);
85
86  /**
87   * Destroys the logger.  This function is responsible to deallocate any
88   * resources used by the logger.  In particular, if buffering is internally
89   * used, it needs to flush the buffer.
90   */
91  void(*destroy)(struct PLogger_t *self);
92}
93PLogger;
94
95/**
96 * Type used to control output format.
97 */
98typedef asr_uint16_t LOG_OUTPUT_FORMAT;
99
100/**
101 * Specifies that no extra information is to be output.
102 */
103#define LOG_OUTPUT_FORMAT_NONE 0x0000
104
105/**
106 * Specifies that the date and time is to be output.
107 */
108#define LOG_OUTPUT_FORMAT_DATE_TIME 0x0001
109
110/**
111 * Specifies that thread id of thread generating the message is to be output.
112 */
113#define LOG_OUTPUT_FORMAT_THREAD_ID 0x0002
114
115/**
116 * Specifies that the module name of the module generating the message is to
117 * be output.
118 */
119#define LOG_OUTPUT_FORMAT_MODULE_NAME 0x0004
120
121/**
122 * Initializes the LOG library.  This function must be called before any
123 * logging can take place. PtrdInit() must be called before this function on
124 * platforms that support threads.
125 *
126 * @param logger The logger to be used to output the messages.  If NULL, then
127 * logging goes to PSTDERR.
128 *
129 * @param logLevel The level of logging requested.
130 *
131 * @return ESR_SUCCESS if success, otherwise a status code indicating the
132 * nature of the error. In particular, it returns ESR_INVALID_STATE if already
133 * initialized.
134 */
135PORTABLE_API ESR_ReturnCode PLogInit(PLogger *logger, unsigned int logLevel);
136
137/**
138 * Indicates if PLog module is initialized.
139 *
140 * @param isInit True if module is initialized
141 * @return ESR_INVALID_ARGUMENT if isLocked is null
142 */
143PORTABLE_API ESR_ReturnCode PLogIsInitialized(ESR_BOOL* isInit);
144
145/**
146 * Indicates if PLog module is locked inside a critical section. This is for internal use only.
147 *
148 * @param isLocked True if module is locked
149 * @return ESR_INVALID_ARGUMENT if isLocked is null
150 */
151PORTABLE_API ESR_ReturnCode PLogIsLocked(ESR_BOOL* isLocked);
152
153/**
154 * Shutdowns the LOG library.  Once this function is called, no logging
155 * activity can be performed.
156 *
157 * @return ESR_SUCCESS if success, otherwise a status code indicating the
158 * nature of the error.  In particular, it returns ESR_INVALID_STATE if not
159 * initialized or already shutted down.
160 */
161PORTABLE_API ESR_ReturnCode PLogShutdown(void);
162
163/**
164 * Sets the format of the logging messages.  If this function is never called,
165 * the default format is
166 *
167 * <code>LOG_OUTPUT_FORMAT_MODULE_NAME | LOG_OUTPUT_FORMAT_DATE_TIME</code>.
168 *
169 * @param format the format specification for new messages.
170 *
171 * @return ESR_SUCCESS if success, otherwise a status code indicating the
172 * nature of the error.
173 */
174PORTABLE_API ESR_ReturnCode PLogSetFormat(LOG_OUTPUT_FORMAT format);
175
176/**
177 * Gets the current log level of the LOG API.
178 *
179 * @param logLevel A pointer to where the log level is to be stored.  If NULL,
180 * the function returns ESR_INVALID_ARGUMENT.
181 *
182 * @return ESR_SUCCESS if success, otherwise a status code indicating the
183 * nature of the error.  In particular, it returns ESR_INVALID_STATE if the
184 * API is not initialized.
185 */
186PORTABLE_API ESR_ReturnCode PLogGetLevel(unsigned int *logLevel);
187
188
189/**
190 * Sets the current log level of the LOG API.
191 *
192 * @param logLevel The new log level.
193 *
194 * @return ESR_SUCCESS if success, otherwise a status code indicating the
195 * nature of the error.  In particular, it returns ESR_INVALID_STATE if the
196 * API is not initialized.
197 */
198PORTABLE_API ESR_ReturnCode PLogSetLevel(unsigned int logLevel);
199
200/**
201 * Conditionally Logs a message.  The message is logged only if module is enabled.
202 *
203 * @param msg The message format specification (ala printf).
204 *
205 * @return ESR_SUCCESS if success, otherwise a status code indicating the
206 * nature of the error.  In particular, it returns ESR_INVALID_STATE if
207 * the API is not initialized.
208 */
209PORTABLE_API ESR_ReturnCode PLogMessage(const LCHAR* msg, ...);
210
211/**
212 * Unconditionally logs an error message.
213 *
214 * @param msg The message format specification (ala printf).
215 *
216 * @return ESR_SUCCESS if success, otherwise a status code indicating the
217 * nature of the error.  In particular, it returns ESR_INVALID_STATE if
218 * the API is not initialized.
219 */
220PORTABLE_API ESR_ReturnCode PLogError(const LCHAR* msg, ...);
221
222
223/**
224 *
225 * Creates a logger that logs to a file.
226 *
227 * @param file The file to log to.
228 * @param logger logger handle receiving the created logger.
229 *
230 * @return ESR_SUCCESS if success, otherwise a status code indicating the
231 * nature of the error.
232 */
233PORTABLE_API ESR_ReturnCode PLogCreateFileLogger(PFile* file,
234    PLogger** logger);
235
236/**
237 * Creates a logger that logs to a circular file.
238 *
239 * @param filename The name of the file to be created.
240 * @param maxsize The maximum number of bytes that the file may have.
241 * @param logger logger handle receiving the created logger.
242 *
243 * @return ESR_SUCCESS if success, otherwise a status code indicating the
244 * nature of the error.
245 */
246PORTABLE_API ESR_ReturnCode PLogCreateCircularFileLogger(const LCHAR* filename,
247    unsigned int maxsize,
248    PLogger** logger);
249
250
251
252/**
253 * Runs a function, checks its return-code. In case of an error, logs it and jumps to
254 * the CLEANUP label.
255 */
256/* show more information for vxworks due to lack of stack trace */
257#define CHKLOG(rc, function) do { rc = (function); if (rc != ESR_SUCCESS) { PLogError("%s in %s:%d", ESR_rc2str(rc),  __FILE__, __LINE__); goto CLEANUP; } } while (0)
258/**
259 * Invokes the function with args and if it is not ESR_SUCCESS, logs and
260 * returns it.
261 *
262 * @param rc Used to store the function return value
263 * @param function Function name
264 * @param args Function arguments
265 */
266#define PLOG_CHKRC_ARGS(rc, function, args) do { if((rc = (function args)) != ESR_SUCCESS) { PLogError(ESR_rc2str(rc)); return rc; } } while (0)
267
268/**
269 * Checks the function return-code and if it is not ESR_SUCCESS, logs and
270 * returns it.
271 */
272#define PLOG_CHKRC(rc, function) do { rc = (function); if (rc != ESR_SUCCESS) { PLogError(rc); return rc; } } while (0)
273
274#if defined(_DEBUG) && !defined(ENABLE_PLOG_TRACE) && ENABLE_STACKTRACE
275#define ENABLE_PLOG_TRACE
276#endif
277
278/**
279 * Macro used to have logging enabled on debug build only.
280 */
281#ifdef ENABLE_PLOG_TRACE
282
283#define PLOG_DBG_ERROR(msg) ((void) (PLogError msg))
284/**
285 * Usage: PLOG_DBG_TRACE((printf-arguments))
286 *
287 * The reason we require double brackets is to allow the use of printf-style variable
288 * argument listings in a macro.
289 */
290#define PLOG_DBG_TRACE(args) ((void) (PLogMessage args))
291#define PLOG_DBG_BLOCK(block) block
292#define PLOG_DBG_API_ENTER() \
293  do \
294  { \
295    LCHAR text[P_MAX_FUNCTION_NAME]; \
296    size_t len = P_MAX_FUNCTION_NAME; \
297    ESR_ReturnCode rc; \
298    \
299    rc = PStackTraceGetFunctionName(text, &len); \
300    if (rc==ESR_SUCCESS) \
301      PLogMessage(L("%s entered."), text); \
302    else if (rc!=ESR_NOT_SUPPORTED) \
303      pfprintf(PSTDERR, L("[%s:%d] PStackTraceGetValue failed with %s\n"), __FILE__, __LINE__, ESR_rc2str(rc)); \
304  } while (0)
305
306#define PLOG_DBG_API_EXIT(rc) \
307  \
308  do \
309  { \
310    LCHAR text[P_MAX_FUNCTION_NAME]; \
311    size_t len = P_MAX_FUNCTION_NAME; \
312    ESR_ReturnCode rc2; \
313    \
314    rc2 = PStackTraceGetFunctionName(text, &len); \
315    if (rc2==ESR_SUCCESS) \
316      PLogMessage(L("%s returned %s"), text, ESR_rc2str(rc)); \
317    else if (rc!=ESR_NOT_SUPPORTED) \
318      pfprintf(PSTDERR, "[%s:%d] PStackTraceGetValue failed with %s\n", __FILE__, __LINE__, ESR_rc2str(rc2)); \
319  } while (0)
320
321#else
322
323#ifndef DOXYGEN_SHOULD_SKIP_THIS
324#define PLOG_DBG_ERROR(msg) ((void) 0)
325#define PLOG_DBG_MODULE(name, logLevel)
326#define PLOG_DBG_TRACE(args) ((void) 0)
327#define PLOG_DBG_BLOCK(block)
328#define PLOG_DBG_API_ENTER() ((void) 0)
329#define PLOG_DBG_API_EXIT(rc) ((void) 0)
330#endif /* DOXYGEN_SHOULD_SKIP_THIS */
331#endif /* ENABLE_PLOG_TRACE */
332
333/**
334 * @}
335 */
336
337
338#endif
339