• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 #ifndef IWLOG_H
3 #define IWLOG_H
4 
5 /**************************************************************************************************
6  * IOWOW library
7  *
8  * MIT License
9  *
10  * Copyright (c) 2012-2022 Softmotions Ltd <info@softmotions.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  *  copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28  * SOFTWARE.
29  *************************************************************************************************/
30 
31 #ifdef __clang__
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
34 #endif
35 
36 /**
37  * @file
38  * @brief Error logging/reporting routines.
39  * @author Anton Adamansky (adamansky@softmotions.com)
40  *
41  * Before using API of this module you should call
42  * `iw_init(void)` iowow module initialization routine.
43  *
44  * By default all logging output redirected to the `stderr`
45  * you can owerride it by passing  instance of `IWLOG_DEFAULT_OPTS`
46  * to the `iwlog_set_logfn_opts(void*)`
47  *
48  * A custom error logging function may be implemented with `IWLOG_FN` signature
49  * and registered by `void iwlog_set_logfn(IWLOG_FN fp)`
50  *
51  * The following methods normally used for logging:
52  * @verbatim
53     iwlog_{debug,info,warn,error}
54     iwlog_ecode_{debug,info,warn,error} @endverbatim
55  */
56 
57 #include "iowow.h"
58 
59 #include <stdint.h>
60 #include <stdarg.h>
61 #include <stdio.h>
62 
63 #ifdef __APPLE__
64 #include <xlocale.h>
65 #else
66 #include <locale.h>
67 #endif
68 
69 IW_EXTERN_C_START
70 
71 /**
72  * @enum iw_ecode
73  * @brief Common used error codes.
74  */
75 typedef enum {
76   IW_OK         = 0,              /**< No error. */
77   IW_ERROR_FAIL = IW_ERROR_START, /**< Unspecified error. */
78   IW_ERROR_ERRNO,                 /**< Error with expected errno status set. */
79   IW_ERROR_IO_ERRNO,              /**< IO error with expected errno status set. */
80   IW_ERROR_AGAIN,
81   IW_ERROR_NOT_EXISTS,            /**< Resource is not exists. */
82   IW_ERROR_READONLY,              /**< Resource is readonly. */
83   IW_ERROR_ALREADY_OPENED,        /**< Resource is already opened. */
84   IW_ERROR_THREADING,             /**< Threading error. */
85   IW_ERROR_THREADING_ERRNO,       /**< Threading error with errno status set. */
86   IW_ERROR_ASSERTION,             /**< Generic assertion error. */
87   IW_ERROR_INVALID_HANDLE,        /**< Invalid HANDLE value. */
88   IW_ERROR_OUT_OF_BOUNDS,         /**< Invalid bounds specified. */
89   IW_ERROR_NOT_IMPLEMENTED,       /**< Method is not implemented. */
90   IW_ERROR_ALLOC,                 /**< Memory allocation failed. */
91   IW_ERROR_INVALID_STATE,         /**< Illegal state error. */
92   IW_ERROR_NOT_ALIGNED,           /**< Argument is not aligned properly. */
93   IW_ERROR_FALSE,                 /**< Request rejection/false response. */
94   IW_ERROR_INVALID_ARGS,          /**< Invalid function arguments. */
95   IW_ERROR_OVERFLOW,              /**< Overflow. */
96   IW_ERROR_INVALID_VALUE,         /**< Invalid value. */
97   IW_ERROR_UNEXPECTED_RESPONSE,   /**< Unexpected response (IW_ERROR_UNEXPECTED_RESPONSE) */
98   IW_ERROR_NOT_ALLOWED,           /**< Action is not allowed. (IW_ERROR_NOT_ALLOWED) */
99   IW_ERROR_UNSUPPORTED,           /**< Unsupported opration. (IW_ERROR_UNSUPPORTED) */
100   IW_ERROR_EOF,                   /**< End of IO stream/file (IW_ERROR_EOF) */
101   IW_ERROR_UNEXPECTED_INPUT,      /**< Unexpected input/data (IW_ERROR_UNEXPECTED_INPUT) */
102   IW_ERROR_IO,                    /**< IO error (IW_ERROR_IO) */
103   IW_ERROR_INVALID_CONFIG,        /**< Invalid configuration (IW_ERROR_INVALID_CONFIG) */
104 } iw_ecode;
105 
106 /**
107  * @enum iwlog_lvl
108  * @brief Available logging vebosity levels.
109  */
110 typedef enum {
111   IWLOG_ERROR   = 0,
112   IWLOG_WARN    = 1,
113   IWLOG_INFO    = 2,
114   IWLOG_VERBOSE = 3,
115   IWLOG_DEBUG   = 4,
116 } iwlog_lvl;
117 
118 /**
119  * @brief Options for the default logging function.
120  * @see iwlog_set_logfn_opts(void*)
121  */
122 typedef struct {
123   FILE *out; /**< Output file stream. Default: `stderr`  */
124 } IWLOG_DEFAULT_OPTS;
125 
126 /**
127  * @brief Logging function pointer.
128  *
129  * @param locale Locale used to print error message.
130  * @param lvl Log level.
131  * @param ecode Error code specified.
132  * @param errno_code Optional errno code. Set it to 0 if errno not used.
133  * @param file File name. Can be `NULL`
134  * @param line Line number in the file.
135  * @param ts Message time-stamp
136  * @param fmt `printf` style message format
137  * @return Not zero error code in the case of error.
138  *
139  * @see iwlog_set_logfn(IWLOG_FN)
140  */
141 typedef iwrc (*IWLOG_FN)(
142   FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode,
143   int errno_code, int werror_code, const char *file,
144   int line, uint64_t ts, void *opts, const char *fmt,
145   va_list argp, bool no_va);
146 
147 /**
148  * @brief Return the locale aware error code explanation message.
149  *
150  * @param locale Locale used. Can be `NULL`
151  * @param ecode Error code
152  * @return Message string describes a given error code or `NULL` if
153  *         no message found.
154  */
155 typedef const char* (*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode);
156 
157 /**
158  * @brief Attach the specified @a errno_code code into @a rc code
159  * @param rc IOWOW error code
160  * @param errno_code Error code will be embedded into.
161  * @return Updated rc code
162  */
163 IW_EXPORT iwrc iwrc_set_errno(iwrc rc, int errno_code);
164 
165 /**
166  * @brief Strip the attached `errno` code from the specified @a rc and
167  * return errno code.
168  *
169  * @param rc `errno` code or `0`
170  */
171 IW_EXPORT uint32_t iwrc_strip_errno(iwrc *rc);
172 
173 #ifdef _WIN32
174 
175 /**
176  * @brief Attach the specified windows @a werror code into @a rc code
177  * @param rc IOWOW error code
178  * @param errno_code Error code will be embedded into.
179  * @return Updated rc code
180  */
181 IW_EXPORT iwrc iwrc_set_werror(iwrc rc, uint32_t werror);
182 
183 /**
184  * @brief Strip the attached windows `werror` code from the specified @a rc and
185  * return this errno code.
186  *
187  * @param rc `errno` code or `0`
188  */
189 IW_EXPORT uint32_t iwrc_strip_werror(iwrc *rc);
190 
191 #endif
192 
193 /**
194  * @brief Remove embedded @a errno code from the passed @a rc
195  * @param [in,out] rc
196  */
197 IW_EXPORT void iwrc_strip_code(iwrc *rc);
198 
199 /**
200  * @brief Sets current logging function.
201  * @warning Not thread safe.
202  *
203  * @param fp Logging function pointer.
204  * @return Not zero if error occured.
205  */
206 IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp, void *opts);
207 
208 /**
209  * @brief Get a default logging function.
210  *
211  */
212 IW_EXPORT IWLOG_FN iwlog_get_logfn(void);
213 
214 /**
215  * @brief Returns string representation of a given error code.
216  * @param ecode Error code
217  * @return
218  */
219 IW_EXPORT const char* iwlog_ecode_explained(iwrc ecode);
220 
221 /**
222  * @brief Register error code explanation function.
223  * @note Up to `128` @a fp functions can be registered.
224  * @param fp
225  * @return `0` on success or error code.
226  */
227 IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp);
228 
229 /**
230  * @brief Logs a message.
231  * @param lvl       Logging level.
232  * @param ecode     Error code or zero.
233  * @param file      Module file, can be `NULL`
234  * @param line      Line in module.
235  * @param fmt       Printf like message format.
236  * @return
237  */
238 IW_EXPORT iwrc iwlog(
239   iwlog_lvl lvl, iwrc ecode, const char *file, int line,
240   const char *fmt, ...) __attribute__((format(__printf__, 5, 6)));
241 
242 IW_EXPORT void iwlog2(
243   iwlog_lvl lvl, iwrc ecode, const char *file, int line,
244   const char *fmt, ...) __attribute__((format(__printf__, 5, 6)));
245 
246 IW_EXPORT void iwlog3(
247   iwlog_lvl lvl, iwrc ecode, const char *file, int line,
248   const char *data);
249 
250 IW_EXPORT iwrc iwlog_va(
251   FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line,
252   const char *fmt, va_list argp, bool no_va);
253 
254 #ifdef _DEBUG
255 #define iwlog_debug(IW_fmt, ...) \
256   iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
257 #else
258 #define iwlog_debug(IW_fmt, ...)
259 #endif
260 #define iwlog_verbose(IW_fmt, ...) \
261   iwlog2(IWLOG_VERBOSE, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
262 #define iwlog_info(IW_fmt, ...) \
263   iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
264 #define iwlog_warn(IW_fmt, ...) \
265   iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
266 #define iwlog_error(IW_fmt, ...) \
267   iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
268 
269 #ifdef _DEBUG
270 #define iwlog_debug2(IW_fmt) \
271   iwlog3(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt))
272 #else
273 #define iwlog_debug2(IW_fmt)
274 #endif
275 #define iwlog_verbose2(IW_fmt) iwlog3(IWLOG_VERBOSE, 0, __FILE__, __LINE__, (IW_fmt))
276 #define iwlog_info2(IW_fmt)    iwlog3(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt))
277 #define iwlog_warn2(IW_fmt)    iwlog3(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt))
278 #define iwlog_error2(IW_fmt) \
279   iwlog3(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt))
280 
281 #ifdef _DEBUG
282 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) \
283   iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
284 #else
285 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...)
286 #endif
287 #define iwlog_ecode_verbose(IW_ecode, IW_fmt, ...) \
288   iwlog2(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
289 #define iwlog_ecode_info(IW_ecode, IW_fmt, ...) \
290   iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
291 #define iwlog_ecode_warn(IW_ecode, IW_fmt, ...) \
292   iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
293 #define iwlog_ecode_error(IW_ecode, IW_fmt, ...) \
294   iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ## __VA_ARGS__)
295 
296 #ifdef _DEBUG
297 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) \
298   iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
299 #else
300 #define iwlog_ecode_debug2(IW_ecode, IW_fmt)
301 #endif
302 #define iwlog_ecode_verbose2(IW_ecode, IW_fmt) \
303   iwlog3(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
304 #define iwlog_ecode_info2(IW_ecode, IW_fmt) \
305   iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
306 #define iwlog_ecode_warn2(IW_ecode, IW_fmt) \
307   iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
308 #define iwlog_ecode_error2(IW_ecode, IW_fmt) \
309   iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt))
310 
311 #ifdef _DEBUG
312 #define iwlog_ecode_debug3(IW_ecode) \
313   iwlog3(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "")
314 #else
315 #define iwlog_ecode_debug3(IW_ecode)
316 #endif
317 #define iwlog_ecode_verbose3(IW_ecode) iwlog3(IWLOG_VERBOSE, (IW_ecode), __FILE__, __LINE__, ""))
318 #define iwlog_ecode_info3(IW_ecode)    iwlog3(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, ""))
319 #define iwlog_ecode_warn3(IW_ecode) \
320   iwlog3(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "")
321 #define iwlog_ecode_error3(IW_ecode) \
322   iwlog3(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "")
323 
324 #define IWRC(IW_act, IW_rc)                                   \
325   {                                                           \
326     iwrc __iwrc = (IW_act);                                   \
327     if (__iwrc) {                                             \
328       if (!(IW_rc))                                           \
329       (IW_rc) = __iwrc;                                       \
330       else                                                    \
331       iwlog3(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, "");    \
332     }                                                         \
333   }
334 
335 #define IWRC2(IW_act, IW_lvl)                                   \
336   {                                                             \
337     iwrc __iwrc = (IW_act);                                     \
338     if (__iwrc) {                                               \
339       iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
340     }                                                           \
341   }
342 
343 #define IWRC3(IW_act, IW_rc, IW_lvl)                            \
344   {                                                             \
345     iwrc __iwrc = (IW_act);                                     \
346     if (__iwrc) {                                               \
347       if (!(IW_rc))                                             \
348       (IW_rc) = __iwrc;                                         \
349       else                                                      \
350       iwlog3(IWLOG_ ## IW_lvl, __iwrc, __FILE__, __LINE__, ""); \
351     }                                                           \
352   }
353 
354 /**
355  * @brief Initiate this submodule.
356  * @return `0` on success or error code.
357  */
358 IW_EXPORT iwrc iwlog_init(void);
359 
360 #ifdef __clang__
361 #pragma clang diagnostic pop
362 #endif
363 
364 IW_EXTERN_C_END
365 #endif
366