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-2020 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 #ifndef IW_ERROR_START 72 #define IW_ERROR_START 70000 73 #endif 74 75 /** 76 * @enum iw_ecode 77 * @brief Common used error codes. 78 */ 79 typedef enum { 80 IW_OK = 0, /**< No error. */ 81 IW_ERROR_FAIL = IW_ERROR_START, /**< Unspecified error. */ 82 IW_ERROR_ERRNO, /**< Error with expected errno status set. */ 83 IW_ERROR_IO_ERRNO, /**< IO error with expected errno status set. */ 84 IW_ERROR_NOT_EXISTS, /**< Resource is not exists. */ 85 IW_ERROR_READONLY, /**< Resource is readonly. */ 86 IW_ERROR_ALREADY_OPENED, /**< Resource is already opened. */ 87 IW_ERROR_THREADING, /**< Threading error. */ 88 IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */ 89 IW_ERROR_ASSERTION, /**< Generic assertion error. */ 90 IW_ERROR_INVALID_HANDLE, /**< Invalid HANDLE value. */ 91 IW_ERROR_OUT_OF_BOUNDS, /**< Invalid bounds specified. */ 92 IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */ 93 IW_ERROR_ALLOC, /**< Memory allocation failed. */ 94 IW_ERROR_INVALID_STATE, /**< Illegal state error. */ 95 IW_ERROR_NOT_ALIGNED, /**< Argument is not aligned properly. */ 96 IW_ERROR_FALSE, /**< Request rejection/false response. */ 97 IW_ERROR_INVALID_ARGS, /**< Invalid function arguments. */ 98 IW_ERROR_OVERFLOW, /**< Overflow. */ 99 IW_ERROR_INVALID_VALUE /**< Invalid value. */ 100 } iw_ecode; 101 102 /** 103 * @enum iwlog_lvl 104 * @brief Available logging vebosity levels. 105 */ 106 typedef enum { 107 IWLOG_ERROR = 0, 108 IWLOG_WARN = 1, 109 IWLOG_INFO = 2, 110 IWLOG_DEBUG = 3 111 } iwlog_lvl; 112 113 /** 114 * @brief Options for the default logging function. 115 * @see iwlog_set_logfn_opts(void*) 116 */ 117 typedef struct { 118 FILE *out; /**< Output file stream. Default: `stderr` */ 119 } IWLOG_DEFAULT_OPTS; 120 121 /** 122 * @brief Logging function pointer. 123 * 124 * @param locale Locale used to print error message. 125 * @param lvl Log level. 126 * @param ecode Error code specified. 127 * @param errno_code Optional errno code. Set it to 0 if errno not used. 128 * @param file File name. Can be `NULL` 129 * @param line Line number in the file. 130 * @param ts Message time-stamp 131 * @param fmt `printf` style message format 132 * @return Not zero error code in the case of error. 133 * 134 * @see iwlog_set_logfn(IWLOG_FN) 135 */ 136 typedef iwrc(*IWLOG_FN)(FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode, 137 int errno_code, int werror_code, const char *file, 138 int line, uint64_t ts, void *opts, const char *fmt, 139 va_list argp); 140 141 /** 142 * @brief Return the locale aware error code explanation message. 143 * 144 * @param locale Locale used. Can be `NULL` 145 * @param ecode Error code 146 * @return Message string describes a given error code or `NULL` if 147 * no message found. 148 */ 149 typedef const char *(*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode); 150 151 /** 152 * @brief Attach the specified @a errno_code code into @a rc code 153 * @param rc IOWOW error code 154 * @param errno_code Error code will be embedded into. 155 * @return Updated rc code 156 */ 157 IW_EXPORT iwrc iwrc_set_errno(iwrc rc, int errno_code); 158 159 /** 160 * @brief Strip the attached `errno` code from the specified @a rc and 161 * return errno code. 162 * 163 * @param rc `errno` code or `0` 164 */ 165 IW_EXPORT uint32_t iwrc_strip_errno(iwrc *rc); 166 167 #ifdef _WIN32 168 169 /** 170 * @brief Attach the specified windows @a werror code into @a rc code 171 * @param rc IOWOW error code 172 * @param errno_code Error code will be embedded into. 173 * @return Updated rc code 174 */ 175 IW_EXPORT iwrc iwrc_set_werror(iwrc rc, uint32_t werror); 176 177 /** 178 * @brief Strip the attached windows `werror` code from the specified @a rc and 179 * return this errno code. 180 * 181 * @param rc `errno` code or `0` 182 */ 183 IW_EXPORT uint32_t iwrc_strip_werror(iwrc *rc); 184 185 #endif 186 187 /** 188 * @brief Remove embedded @a errno code from the passed @a rc 189 * @param [in,out] rc 190 */ 191 IW_EXPORT void iwrc_strip_code(iwrc *rc); 192 193 /** 194 * @brief Sets current logging function. 195 * @warning Not thread safe. 196 * 197 * @param fp Logging function pointer. 198 * @return Not zero if error occured. 199 */ 200 IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp); 201 202 /** 203 * @brief Get a default logging function. 204 */ 205 IW_EXPORT IWLOG_FN iwlog_get_logfn(void); 206 207 /** 208 * @brief Set opaque options structure for the 209 * current logging function implementation. 210 * @param opts 211 * @see `IWLOG_DEFAULT_OPTS` 212 * @see `IWLOG_FN` 213 */ 214 IW_EXPORT void iwlog_set_logfn_opts(void *opts); 215 216 /** 217 * @brief Returns string representation of a given error code. 218 * @param ecode Error code 219 * @return 220 */ 221 IW_EXPORT const char *iwlog_ecode_explained(iwrc ecode); 222 223 /** 224 * @brief Register error code explanation function. 225 * @note Up to `128` @a fp functions can be registered. 226 * @param fp 227 * @return `0` on success or error code. 228 */ 229 IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp); 230 231 /** 232 * @brief Logs a message. 233 * @param lvl Logging level. 234 * @param ecode Error code or zero. 235 * @param file Module file, can be `NULL` 236 * @param line Line in module. 237 * @param fmt Printf like message format. 238 * @return 239 */ 240 IW_EXPORT iwrc iwlog(iwlog_lvl lvl, iwrc ecode, const char *file, int line, 241 const char *fmt, ...); 242 243 IW_EXPORT void iwlog2(iwlog_lvl lvl, iwrc ecode, const char *file, int line, 244 const char *fmt, ...); 245 246 IW_EXPORT iwrc iwlog_va(FILE *out, iwlog_lvl lvl, iwrc ecode, const char *file, int line, 247 const char *fmt, va_list argp); 248 249 #ifdef _DEBUG 250 #define iwlog_debug(IW_fmt, ...) \ 251 iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 252 #else 253 #define iwlog_debug(IW_fmt, ...) 254 #endif 255 #define iwlog_info(IW_fmt, ...) \ 256 iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 257 #define iwlog_warn(IW_fmt, ...) \ 258 iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 259 #define iwlog_error(IW_fmt, ...) \ 260 iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 261 262 #ifdef _DEBUG 263 #define iwlog_debug2(IW_fmt) \ 264 iwlog2(IWLOG_DEBUG, 0, __FILE__, __LINE__, (IW_fmt)) 265 #else 266 #define iwlog_debug2(IW_fmt) 267 #endif 268 #define iwlog_info2(IW_fmt) iwlog2(IWLOG_INFO, 0, __FILE__, __LINE__, (IW_fmt)) 269 #define iwlog_warn2(IW_fmt) iwlog2(IWLOG_WARN, 0, __FILE__, __LINE__, (IW_fmt)) 270 #define iwlog_error2(IW_fmt) \ 271 iwlog2(IWLOG_ERROR, 0, __FILE__, __LINE__, (IW_fmt)) 272 273 #ifdef _DEBUG 274 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) \ 275 iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 276 #else 277 #define iwlog_ecode_debug(IW_ecode, IW_fmt, ...) 278 #endif 279 #define iwlog_ecode_info(IW_ecode, IW_fmt, ...) \ 280 iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 281 #define iwlog_ecode_warn(IW_ecode, IW_fmt, ...) \ 282 iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 283 #define iwlog_ecode_error(IW_ecode, IW_fmt, ...) \ 284 iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt), ##__VA_ARGS__) 285 286 #ifdef _DEBUG 287 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) \ 288 iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 289 #else 290 #define iwlog_ecode_debug2(IW_ecode, IW_fmt) 291 #endif 292 #define iwlog_ecode_info2(IW_ecode, IW_fmt) \ 293 iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 294 #define iwlog_ecode_warn2(IW_ecode, IW_fmt) \ 295 iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 296 #define iwlog_ecode_error2(IW_ecode, IW_fmt) \ 297 iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, (IW_fmt)) 298 299 #ifdef _DEBUG 300 #define iwlog_ecode_debug3(IW_ecode) \ 301 iwlog2(IWLOG_DEBUG, (IW_ecode), __FILE__, __LINE__, "") 302 #else 303 #define iwlog_ecode_debug3(IW_ecode) 304 #endif 305 #define iwlog_ecode_info3(IW_ecode) iwlog2(IWLOG_INFO, (IW_ecode), __FILE__, __LINE__, "")) 306 #define iwlog_ecode_warn3(IW_ecode) \ 307 iwlog2(IWLOG_WARN, (IW_ecode), __FILE__, __LINE__, "") 308 #define iwlog_ecode_error3(IW_ecode) \ 309 iwlog2(IWLOG_ERROR, (IW_ecode), __FILE__, __LINE__, "") 310 311 #define IWRC(IW_act, IW_rc) \ 312 { \ 313 iwrc __iwrc = (IW_act); \ 314 if (__iwrc) { \ 315 if (!(IW_rc)) \ 316 (IW_rc) = __iwrc; \ 317 else \ 318 iwlog2(IWLOG_ERROR, __iwrc, __FILE__, __LINE__, ""); \ 319 } \ 320 } 321 322 #define IWRC2(IW_act, IW_lvl) \ 323 { \ 324 iwrc __iwrc = (IW_act); \ 325 if (__iwrc) { \ 326 iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \ 327 } \ 328 } 329 330 #define IWRC3(IW_act, IW_rc, IW_lvl) \ 331 { \ 332 iwrc __iwrc = (IW_act); \ 333 if (__iwrc) { \ 334 if (!(IW_rc)) \ 335 (IW_rc) = __iwrc; \ 336 else \ 337 iwlog2(IWLOG_##IW_lvl, __iwrc, __FILE__, __LINE__, ""); \ 338 } \ 339 } 340 341 /** 342 * @brief Initiate this submodule. 343 * @return `0` on success or error code. 344 */ 345 IW_EXPORT iwrc iwlog_init(void); 346 347 #ifdef __clang__ 348 #pragma clang diagnostic pop 349 #endif 350 351 IW_EXTERN_C_END 352 #endif 353