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-2021 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_AGAIN, 85 IW_ERROR_NOT_EXISTS, /**< Resource is not exists. */ 86 IW_ERROR_READONLY, /**< Resource is readonly. */ 87 IW_ERROR_ALREADY_OPENED, /**< Resource is already opened. */ 88 IW_ERROR_THREADING, /**< Threading error. */ 89 IW_ERROR_THREADING_ERRNO, /**< Threading error with errno status set. */ 90 IW_ERROR_ASSERTION, /**< Generic assertion error. */ 91 IW_ERROR_INVALID_HANDLE, /**< Invalid HANDLE value. */ 92 IW_ERROR_OUT_OF_BOUNDS, /**< Invalid bounds specified. */ 93 IW_ERROR_NOT_IMPLEMENTED, /**< Method is not implemented. */ 94 IW_ERROR_ALLOC, /**< Memory allocation failed. */ 95 IW_ERROR_INVALID_STATE, /**< Illegal state error. */ 96 IW_ERROR_NOT_ALIGNED, /**< Argument is not aligned properly. */ 97 IW_ERROR_FALSE, /**< Request rejection/false response. */ 98 IW_ERROR_INVALID_ARGS, /**< Invalid function arguments. */ 99 IW_ERROR_OVERFLOW, /**< Overflow. */ 100 IW_ERROR_INVALID_VALUE, /**< Invalid value. */ 101 IW_ERROR_UNEXPECTED_RESPONSE, /**< Unexpected response (IW_ERROR_UNEXPECTED_RESPONSE) */ 102 IW_ERROR_NOT_ALLOWED, /**< Action is not allowed. (IW_ERROR_NOT_ALLOWED) */ 103 IW_ERROR_UNSUPPORTED, /**< Unsupported opration. (IW_ERROR_UNSUPPORTED) */ 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_DEBUG = 3, 115 } iwlog_lvl; 116 117 /** 118 * @brief Options for the default logging function. 119 * @see iwlog_set_logfn_opts(void*) 120 */ 121 typedef struct { 122 FILE *out; /**< Output file stream. Default: `stderr` */ 123 } IWLOG_DEFAULT_OPTS; 124 125 /** 126 * @brief Logging function pointer. 127 * 128 * @param locale Locale used to print error message. 129 * @param lvl Log level. 130 * @param ecode Error code specified. 131 * @param errno_code Optional errno code. Set it to 0 if errno not used. 132 * @param file File name. Can be `NULL` 133 * @param line Line number in the file. 134 * @param ts Message time-stamp 135 * @param fmt `printf` style message format 136 * @return Not zero error code in the case of error. 137 * 138 * @see iwlog_set_logfn(IWLOG_FN) 139 */ 140 typedef iwrc (*IWLOG_FN)( 141 FILE *out, locale_t locale, iwlog_lvl lvl, iwrc ecode, 142 int errno_code, int werror_code, const char *file, 143 int line, uint64_t ts, void *opts, const char *fmt, 144 va_list argp); 145 146 /** 147 * @brief Return the locale aware error code explanation message. 148 * 149 * @param locale Locale used. Can be `NULL` 150 * @param ecode Error code 151 * @return Message string describes a given error code or `NULL` if 152 * no message found. 153 */ 154 typedef const char* (*IWLOG_ECODE_FN)(locale_t locale, uint32_t ecode); 155 156 /** 157 * @brief Attach the specified @a errno_code code into @a rc code 158 * @param rc IOWOW error code 159 * @param errno_code Error code will be embedded into. 160 * @return Updated rc code 161 */ 162 IW_EXPORT iwrc iwrc_set_errno(iwrc rc, int errno_code); 163 164 /** 165 * @brief Strip the attached `errno` code from the specified @a rc and 166 * return errno code. 167 * 168 * @param rc `errno` code or `0` 169 */ 170 IW_EXPORT uint32_t iwrc_strip_errno(iwrc *rc); 171 172 #ifdef _WIN32 173 174 /** 175 * @brief Attach the specified windows @a werror code into @a rc code 176 * @param rc IOWOW error code 177 * @param errno_code Error code will be embedded into. 178 * @return Updated rc code 179 */ 180 IW_EXPORT iwrc iwrc_set_werror(iwrc rc, uint32_t werror); 181 182 /** 183 * @brief Strip the attached windows `werror` code from the specified @a rc and 184 * return this errno code. 185 * 186 * @param rc `errno` code or `0` 187 */ 188 IW_EXPORT uint32_t iwrc_strip_werror(iwrc *rc); 189 190 #endif 191 192 /** 193 * @brief Remove embedded @a errno code from the passed @a rc 194 * @param [in,out] rc 195 */ 196 IW_EXPORT void iwrc_strip_code(iwrc *rc); 197 198 /** 199 * @brief Sets current logging function. 200 * @warning Not thread safe. 201 * 202 * @param fp Logging function pointer. 203 * @return Not zero if error occured. 204 */ 205 IW_EXPORT void iwlog_set_logfn(IWLOG_FN fp, void *opts); 206 207 /** 208 * @brief Get a default logging function. 209 * 210 */ 211 IW_EXPORT IWLOG_FN iwlog_get_logfn(void); 212 213 /** 214 * @brief Returns string representation of a given error code. 215 * @param ecode Error code 216 * @return 217 */ 218 IW_EXPORT const char *iwlog_ecode_explained(iwrc ecode); 219 220 /** 221 * @brief Register error code explanation function. 222 * @note Up to `128` @a fp functions can be registered. 223 * @param fp 224 * @return `0` on success or error code. 225 */ 226 IW_EXPORT iwrc iwlog_register_ecodefn(IWLOG_ECODE_FN fp); 227 228 /** 229 * @brief Logs a message. 230 * @param lvl Logging level. 231 * @param ecode Error code or zero. 232 * @param file Module file, can be `NULL` 233 * @param line Line in module. 234 * @param fmt Printf like message format. 235 * @return 236 */ 237 IW_EXPORT iwrc iwlog( 238 iwlog_lvl lvl, iwrc ecode, const char *file, int line, 239 const char *fmt, ...); 240 241 IW_EXPORT void iwlog2( 242 iwlog_lvl lvl, iwrc ecode, const char *file, int line, 243 const char *fmt, ...); 244 245 IW_EXPORT iwrc iwlog_va( 246 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