/** * 方便打印日志 * 为了保证输出顺序 都使用stdout而不是stderr * * 可配置项(默认都是未定义) * LOG_LINE_END_CRLF 默认是\n结尾 添加此宏将以\r\n结尾 * LOG_FOR_MCU MCU项目可配置此宏 更适用于MCU环境 * LOG_NDEBUG 关闭LOGD的输出 * LOG_SHOW_VERBOSE 显示LOGV的输出 * LOG_NOT_EXIT_ON_FATAL FATAL默认退出程序 添加此宏将不退出 */ #ifndef HW_LIB_LOG_H #define HW_LIB_LOG_H #pragma once #ifdef __cplusplus #include #include #include #else #include #include #include #endif /* 输出日志等级 */ #define LOG_LVL_FATAL 0 #define LOG_LVL_ERROR 1 #define LOG_LVL_WARN 2 #define LOG_LVL_INFO 3 #define LOG_LVL_DEBUG 4 #define LOG_LVL_VERBOSE 5 // 配置 #define LOG_TIMER //#define LOG_FOR_MCU #define LOG_LINE_END_CRLF //#define LOG_WITH_RUN_TIMER #define LOG_OUTPUT_LVL LOG_LVL_INFO //////////////////////// #ifdef LOG_WITH_RUN_TIMER #define LOG_RUN_TIMER_FUN GetTickCount64() #define LOG_RUN_TIMER_FMT "-T(%lums)" #else #define LOG_RUN_TIMER_FUN GetTickCount64() #define LOG_RUN_TIMER_FMT "(%llums)" #endif #ifdef LOG_LINE_END_CRLF #define LOG_LINE_END "\r\n" #else #define LOG_LINE_END "\n" #endif #ifdef LOG_NOT_EXIT_ON_FATAL #define LOG_EXIT_PROGRAM() #else #ifdef LOG_FOR_MCU #define LOG_EXIT_PROGRAM() do{ for(;;); } while(0) #else #define LOG_EXIT_PROGRAM() exit(EXIT_FAILURE) #endif #endif #define LOG_OUT_FUNC printf #define LOG_BASE_FILENAME \ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \ strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define LOG_WITH_COLOR #if defined(_WIN32) || defined(LOG_FOR_MCU) #undef LOG_WITH_COLOR #endif #ifdef LOG_WITH_COLOR #define LOG_COLOR_RED "\033[31m" #define LOG_COLOR_GREEN "\033[32m" #define LOG_COLOR_YELLOW "\033[33m" #define LOG_COLOR_BLUE "\033[34m" #define LOG_COLOR_CARMINE "\033[35m" #define LOG_COLOR_CYAN "\033[36m" #define LOG_COLOR_DEFAULT #define LOG_COLOR_END "\033[m" #else #define LOG_COLOR_RED #define LOG_COLOR_GREEN #define LOG_COLOR_YELLOW #define LOG_COLOR_BLUE #define LOG_COLOR_CARMINE #define LOG_COLOR_CYAN #define LOG_COLOR_DEFAULT #define LOG_COLOR_END #endif #define LOG_END LOG_COLOR_END LOG_LINE_END // 带时钟输出 #if defined(LOG_TIMER) #ifdef LOG_WITH_RUN_TIMER #define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]" LOG_RUN_TIMER_FMT ": " fmt LOG_END,LOG_RUN_TIMER_FUN, ##__VA_ARGS__); } while(0) #else #define LOGT(tag, fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_BLUE "[" tag "]: " fmt LOG_END, ##__VA_ARGS__); } while(0) #endif #else #define LOGT(fmt, ...) ((void)0) #endif // 等级输出 #if LOG_OUTPUT_LVL >= LOG_LVL_FATAL #ifdef LOG_WITH_RUN_TIMER #define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0) #else #define LOGF(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CYAN "[F]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); LOG_EXIT_PROGRAM(); } while(0) #endif #else #define LOGF(fmt, ...) ((void)0) #endif #if LOG_OUTPUT_LVL >= LOG_LVL_ERROR #ifdef LOG_WITH_RUN_TIMER #define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0) #else #define LOGE(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_RED "[E]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0) #endif #else #define LOGE(fmt, ...) ((void)0) #endif #if LOG_OUTPUT_LVL >= LOG_LVL_WARN #ifdef LOG_WITH_RUN_TIMER #define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]" LOG_RUN_TIMER_FMT ": %s: %s: %d: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0) #else #define LOGW(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_CARMINE "[W]: %s: %s: %d: " fmt LOG_END, LOG_BASE_FILENAME, __func__, __LINE__, ##__VA_ARGS__); } while(0) #endif #else #define LOGW(fmt, ...) ((void)0) #endif #if LOG_OUTPUT_LVL >= LOG_LVL_INFO #ifdef LOG_WITH_RUN_TIMER #define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #else #define LOGI(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_YELLOW "[I]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #endif #else #define LOGI(fmt, ...) ((void)0) #endif #if LOG_OUTPUT_LVL >= LOG_LVL_DEBUG #ifdef LOG_WITH_RUN_TIMER #define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #else #define LOGD(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[D]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #endif #else #define LOGD(fmt, ...) ((void)0) #endif #if LOG_OUTPUT_LVL >= LOG_LVL_VERBOSE #ifdef LOG_WITH_RUN_TIMER #define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]" LOG_RUN_TIMER_FMT ": %s: " fmt LOG_END,LOG_RUN_TIMER_FUN, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #else #define LOGV(fmt, ...) do{ LOG_OUT_FUNC(LOG_COLOR_DEFAULT "[V]: %s: " fmt LOG_END, LOG_BASE_FILENAME, ##__VA_ARGS__); } while(0) #endif #else #define LOGV(fmt, ...) ((void)0) #endif #ifndef LOG_RUN_TIME #ifndef __LOG_VA_NUM_ARGS_IMPL # define __LOG_VA_NUM_ARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \ _12, _13, _14, _15, _16, __N, ...) __N #endif #ifndef __LOG_VA_NUM_ARGS #define __LOG_VA_NUM_ARGS(...) \ __LOG_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \ 8,7,6,5,4,3,2,1,0) #endif #ifndef __ticks_sync_barrier__ /* default implementation */ #if defined(__clang__) || __IS_COMPILER_GCC__ # define __ticks_sync_barrier__(...) __sync_synchronize() #else # define __ticks_sync_barrier__(...) #endif #endif #undef __CONNECT2 #undef __CONNECT3 #undef __CONNECT4 #undef __CONNECT5 #undef __CONNECT6 #undef __CONNECT7 #undef __CONNECT8 #undef __CONNECT9 #undef CONNECT2 #undef CONNECT3 #undef CONNECT4 #undef CONNECT5 #undef CONNECT6 #undef CONNECT7 #undef CONNECT8 #undef CONNECT9 #undef CONNECT #undef __MACRO_EXPANDING #define __MACRO_EXPANDING(...) __VA_ARGS__ #define __CONNECT2(__A, __B) __A##__B #define __CONNECT3(__A, __B, __C) __A##__B##__C #define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D #define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E #define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F #define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \ __A##__B##__C##__D##__E##__F##__G #define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \ __A##__B##__C##__D##__E##__F##__G##__H #define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \ __A##__B##__C##__D##__E##__F##__G##__H##__I #define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B) #define CONNECT2(__A, __B) __CONNECT2(__A, __B) #define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C) #define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D) #define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E) #define CONNECT6(__A, __B, __C, __D, __E, __F) \ __CONNECT6(__A, __B, __C, __D, __E, __F) #define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \ __CONNECT7(__A, __B, __C, __D, __E, __F, __G) #define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \ __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) #define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \ __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) #define CONNECT(...) \ ALT_CONNECT2(CONNECT, __LOG_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__) #undef __using1 #undef __using2 #undef __using3 #undef __using4 #undef using #define __using1(__declare) \ for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \ CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \ ) #define __using2(__declare, __on_leave_expr) \ for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \ CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \ (__on_leave_expr) \ ) #define __using3(__declare, __on_enter_expr, __on_leave_expr) \ for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \ CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \ ((__on_enter_expr),1) : 0; \ (__on_leave_expr) \ ) #define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \ for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \ CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \ ((__on_enter_expr),1) : 0; \ (__on_leave_expr) \ ) #define using(...) \ CONNECT2(__using, __LOG_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__) #ifdef LOG_WITH_RUN_TIMER #define LOG_RUN_TIME(__STR, ...) \ using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \ {__ticks_sync_barrier__();}, \ { \ __ticks_sync_barrier__(); \ _ = LOG_RUN_TIMER_FUN - _; \ __time_count__ = _; \ if (__LOG_VA_NUM_ARGS(__VA_ARGS__) == 0) { \ LOG_OUT_FUNC("\r\n"); \ LOG_OUT_FUNC("-[Run Timer]"); \ LOG_OUT_FUNC( \ "------------------------------------\r\n"); \ LOG_OUT_FUNC( \ __STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \ _); \ } else { \ __VA_ARGS__ \ }; \ }) #else #define LOG_RUN_TIME(__STR, ...) \ using(uint64_t _ = LOG_RUN_TIMER_FUN, __time_count__ = _, \ {__ticks_sync_barrier__();}, \ { \ __ticks_sync_barrier__(); \ _ = LOG_RUN_TIMER_FUN - _; \ __time_count__ = _; \ if (__LOG_VA_NUM_ARGS(__VA_ARGS__) == 0) { \ LOG_OUT_FUNC("\r\n"); \ LOG_OUT_FUNC("-[Run Timer]"); \ LOG_OUT_FUNC( \ "------------------------------------\r\n"); \ LOG_OUT_FUNC( \ __STR " total run timer: " LOG_RUN_TIMER_FMT LOG_END, \ _); \ } else { \ __VA_ARGS__ \ }; \ }) #endif #endif #endif //HW_LIB_LOG_H