log.h (3244B)
1 #pragma once 2 3 #include <stdarg.h> 4 #include <stdbool.h> 5 6 /* This module provides formatted logging to stderr. All logging functions are 7 * thread-safe and preserve errno. 8 * 9 * The r_{,v}logf_generic functions accept an arbitrary integer log level to 10 * filter by (see r_log_init) and an associated name (e.g., "info" or "error"), 11 * color (for when terminal color is enabled via r_log_init), and exit code (to 12 * terminate the process with if nonzero). This allows users to create their 13 * own log levels. 14 * 15 * The r_{,v}log_basic functions have four fixed log levels (info, warn, error, 16 * and fatal), with corresponding helper macros. Consult the implementation of 17 * these macros to see how the main logging functions work. */ 18 19 /* TODO: Support optionally logging __func__ */ 20 21 #define R_LOG_LEVEL_INFO 0 22 #define R_LOG_LEVEL_WARN 1 23 #define R_LOG_LEVEL_ERROR 2 24 #define R_LOG_LEVEL_FATAL 3 25 26 #define r_logf(level, ...) r_logf_basic(__FILE__, __LINE__, level, __VA_ARGS__) 27 #define r_infof(...) r_logf(R_LOG_LEVEL_INFO, __VA_ARGS__) 28 #define r_warnf(...) r_logf(R_LOG_LEVEL_WARN, __VA_ARGS__) 29 #define r_errorf(...) r_logf(R_LOG_LEVEL_ERROR, __VA_ARGS__) 30 #define r_fatalf(...) r_logf(R_LOG_LEVEL_FATAL, __VA_ARGS__) 31 32 /* Set global logging settings. 33 * color: <0 force disables color, 0 detects if color should be used, 34 * and >0 force enables color 35 * log_time: enable/disable timestamps in log messages 36 * log_loc: enable/disable source location in log messages 37 * min_level: output log messages iff their level is at least this value 38 * The color detection happens when r_log_init is called, not on each 39 * subsequent invocation of a logging function. 40 * 41 * r_log_init can be called multiple times, but it is not thread-safe. 42 * Typically, you should call r_log_init just once and before starting 43 * multiple threads. 44 * 45 * Calling r_log_init is optional. By default, color is off, time and source 46 * location are not logged, and the minimum log level is set to 0 (so all basic 47 * logs are printed). */ 48 void r_log_init(int color, bool log_time, bool log_loc, int min_level); 49 50 void r_vlogf_generic(char *file, int line, int level, char *name, char *color, int code, char *fmt, va_list args); 51 52 static inline void 53 r_logf_generic(char *file, int line, int level, char *name, char *color, int code, char *fmt, ...) { 54 va_list args; 55 va_start(args, fmt); 56 r_vlogf_generic(file, line, level, name, color, code, fmt, args); 57 va_end(args); 58 } 59 60 static inline void 61 r_vlogf_basic(char *file, int line, int level, char *fmt, va_list args) { 62 static char *names[] = { "INFO", "WARN", "ERROR", "FATAL" }; 63 64 #define RED "\x1b[31m" 65 #define GREEN "\x1b[32m" 66 #define YELLOW "\x1b[33m" 67 static char *colors[] = { GREEN, YELLOW, RED, RED }; 68 #undef YELLOW 69 #undef GREEN 70 #undef RED 71 72 static int codes[] = { 0, 0, 0, 1 }; 73 74 /* Clamp level */ 75 if (level < R_LOG_LEVEL_INFO) level = R_LOG_LEVEL_INFO; 76 if (level > R_LOG_LEVEL_FATAL) level = R_LOG_LEVEL_FATAL; 77 78 r_vlogf_generic(file, line, level, names[level], colors[level], codes[level], fmt, args); 79 } 80 81 static inline void 82 r_logf_basic(char *file, int line, int level, char *fmt, ...) { 83 va_list args; 84 va_start(args, fmt); 85 r_vlogf_basic(file, line, level, fmt, args); 86 va_end(args); 87 }