/*! * @file zlog_api.c * library of syslog-ng * * @author CP Wang * @date 2017-12-12 18:38:46 * @copyright Copyright 2017 Zyxel Communications Corp. All Rights Reserved. */ //============================================================================== #include #include #include #include #include #include #include #include #define _GNU_SOURCE /* See feature_test_macros(7) */ #include // for syscall() #include // for syscall() #include "zlog_api.h" #include // for program_invocation_short_name extern char *program_invocation_short_name; //============================================================================== /* 0 - printf() 1 - syslog-ng */ #ifdef CONFIG_ZLOG_USE_DEBUG #define _USE_SYSLOG 1 #else #define _USE_SYSLOG 0 #endif /* --- IMPORTANT --- this macro is to break the circular dependency with zos this should always be the same as zos_pid_get() */ #define _pid_get() (uint32_t)(syscall(__NR_gettid)) #define _dbg_printf(_fmt_, ...) \ fprintf(stderr, "[PID %u] %s line %d, %s(), " _fmt_, _pid_get(), __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__) //============================================================================== static zlog_level_t _log_level = ZLOG_LEVEL_INFO; static zlog_faci_t _facility = ZLOG_FACI_USER; //============================================================================== #if 0 static const char *_faci_str( zlog_faci_t facility ) { switch (facility) { case ZLOG_FACI_USER: return "user"; case ZLOG_FACI_KERNEL: return "kernel"; default: return "unknown"; } } #endif static const char *_level_str( zlog_level_t level ) { switch (level) { case ZLOG_LEVEL_EMERG: return "EMERG"; case ZLOG_LEVEL_ALERT: return "ALERT"; case ZLOG_LEVEL_CRITICAL: return "CRITICAL"; case ZLOG_LEVEL_ERROR: return "ERROR"; case ZLOG_LEVEL_WARNING: return "WARNING"; case ZLOG_LEVEL_NOTICE: return "NOTICE"; case ZLOG_LEVEL_INFO: return "INFO"; case ZLOG_LEVEL_DEBUG: return "DEBUG"; default: return "UNKNOWN"; } } /*! * get string of date time * * @param [out] str string buffer to get date time. * The buffer size must be >= 20. * * @return true - successful * false - failed */ static bool _datetime_str( char *str ) { int r; time_t now = time(0); struct tm result; struct tm* ltm = localtime_r(&now, &result); if (ltm == NULL) { return false; } r = sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec); if (r <= 0) { return false; } return true; } //============================================================================== /*! * opens a connection to the system logger for a program * * @param [in] module_name module name. If NULL, the program name is used. * @param [in] facility log facility * * @return true - successful * false - failed */ bool zlog_open( char *module, zlog_faci_t facility ) { int ng_facility; switch (facility) { case ZLOG_FACI_USER: ng_facility = LOG_USER; break; case ZLOG_FACI_KERNEL: ng_facility = LOG_KERN; break; default: _dbg_printf("ERROR : invalid facility %d\n", facility); return false; } _facility = facility; #if 1 openlog(module, LOG_NOWAIT | LOG_NDELAY, ng_facility); #else /* output to console */ openlog(module, LOG_NOWAIT | LOG_NDELAY | LOG_PERROR, ng_facility); #endif return true; } /*! * generates a log message * * @param [in] level log level * @param [in] file C file name * @param [in] line line of the code * @param [in] func API name * @param [in] format string format of log message * @param [in] ... any arguments required by the format * * @note no return value, reasons are * 1. nothing can do it fail * 2. if fail, the error message will pop up automatically */ void zlog_log_f( const zlog_level_t level, const char *file, const int line, const char *func, const char *format, ... ) { #define _STR_MAX_LEN 2048 #define _MSG_MAX_LEN (_STR_MAX_LEN * 2) char str[_STR_MAX_LEN + 1] = {0}; char msg[_MSG_MAX_LEN + 1] = {0}; char date[20] = {0}; int r; va_list ap; memset(str, 0, sizeof(str)); memset(msg, 0, sizeof(msg)); memset(date, 0, sizeof(date)); #if _USE_SYSLOG int priority; switch (level) { case ZLOG_LEVEL_EMERG: priority = LOG_EMERG; break; case ZLOG_LEVEL_ALERT: priority = LOG_ALERT; break; case ZLOG_LEVEL_CRITICAL: priority = LOG_CRIT; break; case ZLOG_LEVEL_ERROR: priority = LOG_ERR; break; case ZLOG_LEVEL_WARNING: priority = LOG_WARNING; break; case ZLOG_LEVEL_NOTICE: priority = LOG_NOTICE; break; case ZLOG_LEVEL_INFO: priority = LOG_INFO; break; case ZLOG_LEVEL_DEBUG: priority = LOG_DEBUG; break; default: _dbg_printf("ERROR : invalid level %d\n", level); return ; } #else // _USE_SYSLOG if (level < 0 || level > ZLOG_LEVEL_DEBUG) { _dbg_printf("ERROR : invalid level %d\n", level); return; } #endif // _USE_SYSLOG if (_datetime_str(date) == false) { _dbg_printf("fail to get date time\n"); return; } if (format == NULL) { _dbg_printf("format == NULL\n"); return; } va_start(ap, format); r = vsnprintf(str, _STR_MAX_LEN, format, ap); va_end(ap); if (r < 0 || r > _STR_MAX_LEN) { _dbg_printf("fail to vsnprintf()\n"); return; } // remove tailing '\n' r = strlen(str); if (r > 0 && r <= _STR_MAX_LEN) { if (str[r - 1] == '\n' || str[r - 1] == '\r') { str[r - 1] = 0; } } if (file) { /*