CLG_log.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * This program is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU General Public License
  4. * as published by the Free Software Foundation; either version 2
  5. * of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software Foundation,
  14. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. */
  16. #ifndef __CLG_LOG_H__
  17. #define __CLG_LOG_H__
  18. /** \file
  19. * \ingroup clog
  20. *
  21. * C Logging Library (clog)
  22. * ========================
  23. *
  24. * Usage
  25. * -----
  26. *
  27. * - `CLG_LOGREF_DECLARE_GLOBAL` macro to declare #CLG_LogRef pointers.
  28. * - `CLOG_` prefixed macros for logging.
  29. *
  30. * Identifiers
  31. * -----------
  32. *
  33. * #CLG_LogRef holds an identifier which defines the category of the logger.
  34. *
  35. * You can define and use identifiers as needed, logging will lazily initialize them.
  36. *
  37. * By convention lower case dot separated identifiers are used, eg:
  38. * `module.sub_module`, this allows filtering by `module.*`,
  39. * see #CLG_type_filter_include, #CLG_type_filter_exclude
  40. *
  41. * There is currently no functionality to remove a category once it's created.
  42. *
  43. * Severity
  44. * --------
  45. *
  46. * - `INFO`: Simply log events, uses verbosity levels to control how much information to show.
  47. * - `WARN`: General warnings (which aren't necessary to show to users).
  48. * - `ERROR`: An error we can recover from, should not happen.
  49. * - `FATAL`: Similar to assert. This logs the message, then a stack trace and abort.
  50. * Verbosity Level
  51. * ---------------
  52. *
  53. * Usage:
  54. *
  55. * - 0: Always show (used for warnings, errors).
  56. * Should never get in the way or become annoying.
  57. *
  58. * - 1: Top level module actions (eg: load a file, create a new window .. etc).
  59. *
  60. * - 2: Actions within a module (steps which compose an action, but don't flood output).
  61. * Running a tool, full data recalculation.
  62. *
  63. * - 3: Detailed actions which may be of interest when debugging internal logic of a module
  64. * These *may* flood the log with details.
  65. *
  66. * - 4+: May be used for more details than 3, should be avoided but not prevented.
  67. */
  68. #ifdef __cplusplus
  69. extern "C" {
  70. #endif /* __cplusplus */
  71. #ifdef __GNUC__
  72. # define _CLOG_ATTR_NONNULL(args...) __attribute__((nonnull(args)))
  73. #else
  74. # define _CLOG_ATTR_NONNULL(...)
  75. #endif
  76. #ifdef __GNUC__
  77. # define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) \
  78. __attribute__((format(printf, format_param, dots_param)))
  79. #else
  80. # define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param)
  81. #endif
  82. #define STRINGIFY_ARG(x) "" #x
  83. #define STRINGIFY_APPEND(a, b) "" a #b
  84. #define STRINGIFY(x) STRINGIFY_APPEND("", x)
  85. struct CLogContext;
  86. /* Don't typedef enums. */
  87. enum CLG_LogFlag {
  88. CLG_FLAG_USE = (1 << 0),
  89. };
  90. enum CLG_Severity {
  91. CLG_SEVERITY_INFO = 0,
  92. CLG_SEVERITY_WARN,
  93. CLG_SEVERITY_ERROR,
  94. CLG_SEVERITY_FATAL,
  95. };
  96. #define CLG_SEVERITY_LEN (CLG_SEVERITY_FATAL + 1)
  97. /* Each logger ID has one of these. */
  98. typedef struct CLG_LogType {
  99. struct CLG_LogType *next;
  100. char identifier[64];
  101. /** FILE output. */
  102. struct CLogContext *ctx;
  103. /** Control behavior. */
  104. int level;
  105. enum CLG_LogFlag flag;
  106. } CLG_LogType;
  107. typedef struct CLG_LogRef {
  108. const char *identifier;
  109. CLG_LogType *type;
  110. } CLG_LogRef;
  111. void CLG_log_str(CLG_LogType *lg,
  112. enum CLG_Severity severity,
  113. const char *file_line,
  114. const char *fn,
  115. const char *message) _CLOG_ATTR_NONNULL(1, 3, 4, 5);
  116. void CLG_logf(CLG_LogType *lg,
  117. enum CLG_Severity severity,
  118. const char *file_line,
  119. const char *fn,
  120. const char *format,
  121. ...) _CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6);
  122. /* Main initializer and distructor (per session, not logger). */
  123. void CLG_init(void);
  124. void CLG_exit(void);
  125. void CLG_output_set(void *file_handle);
  126. void CLG_output_use_basename_set(int value);
  127. void CLG_output_use_timestamp_set(int value);
  128. void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle));
  129. void CLG_backtrace_fn_set(void (*fatal_fn)(void *file_handle));
  130. void CLG_type_filter_include(const char *type_filter, int type_filter_len);
  131. void CLG_type_filter_exclude(const char *type_filter, int type_filter_len);
  132. void CLG_level_set(int level);
  133. void CLG_logref_init(CLG_LogRef *clg_ref);
  134. /** Declare outside function, declare as extern in header. */
  135. #define CLG_LOGREF_DECLARE_GLOBAL(var, id) \
  136. static CLG_LogRef _static_##var = {id}; \
  137. CLG_LogRef *var = &_static_##var
  138. /** Initialize struct once. */
  139. #define CLOG_ENSURE(clg_ref) \
  140. ((clg_ref)->type ? (clg_ref)->type : (CLG_logref_init(clg_ref), (clg_ref)->type))
  141. #define CLOG_CHECK(clg_ref, verbose_level, ...) \
  142. ((void)CLOG_ENSURE(clg_ref), \
  143. ((clg_ref)->type->flag & CLG_FLAG_USE) && ((clg_ref)->type->level >= verbose_level))
  144. #define CLOG_AT_SEVERITY(clg_ref, severity, verbose_level, ...) \
  145. { \
  146. CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
  147. if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \
  148. (severity >= CLG_SEVERITY_WARN)) { \
  149. CLG_logf(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \
  150. } \
  151. } \
  152. ((void)0)
  153. #define CLOG_STR_AT_SEVERITY(clg_ref, severity, verbose_level, str) \
  154. { \
  155. CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
  156. if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \
  157. (severity >= CLG_SEVERITY_WARN)) { \
  158. CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \
  159. } \
  160. } \
  161. ((void)0)
  162. #define CLOG_STR_AT_SEVERITY_N(clg_ref, severity, verbose_level, str) \
  163. { \
  164. CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
  165. if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || \
  166. (severity >= CLG_SEVERITY_WARN)) { \
  167. const char *_str = str; \
  168. CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, _str); \
  169. MEM_freeN((void *)_str); \
  170. } \
  171. } \
  172. ((void)0)
  173. #define CLOG_INFO(clg_ref, level, ...) \
  174. CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
  175. #define CLOG_WARN(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
  176. #define CLOG_ERROR(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
  177. #define CLOG_FATAL(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
  178. #define CLOG_STR_INFO(clg_ref, level, str) \
  179. CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, str)
  180. #define CLOG_STR_WARN(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, str)
  181. #define CLOG_STR_ERROR(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, str)
  182. #define CLOG_STR_FATAL(clg_ref, str) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, str)
  183. /* Allocated string which is immediately freed. */
  184. #define CLOG_STR_INFO_N(clg_ref, level, str) \
  185. CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_INFO, level, str)
  186. #define CLOG_STR_WARN_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_WARN, 0, str)
  187. #define CLOG_STR_ERROR_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_ERROR, 0, str)
  188. #define CLOG_STR_FATAL_N(clg_ref, str) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_FATAL, 0, str)
  189. #ifdef __cplusplus
  190. }
  191. #endif
  192. #endif /* __CLG_LOG_H__ */