/* * Copyright (c) 2020 YuQing <384681@qq.com> * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the Lesser GNU General Public License, version 3 * or later ("LGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the Lesser GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "shared_func.h" #include "pthread_func.h" #include "sched_thread.h" #include "logger.h" #ifndef LINE_MAX #define LINE_MAX 2048 #endif #define LOG_BUFF_SIZE 64 * 1024 #define NEED_COMPRESS_LOG(flags) ((flags & LOG_COMPRESS_FLAGS_ENABLED) != 0) #define COMPRESS_IN_NEW_THREAD(flags) ((flags & LOG_COMPRESS_FLAGS_NEW_THREAD) != 0) #define GZIP_EXT_NAME_STR ".gz" #define GZIP_EXT_NAME_LEN (sizeof(GZIP_EXT_NAME_STR) - 1) LogContext g_log_context = {LOG_INFO, STDERR_FILENO, NULL}; static int log_fsync(LogContext *pContext, const bool bNeedLock); static int check_and_mk_log_dir(const char *base_path) { char data_path[MAX_PATH_SIZE]; snprintf(data_path, sizeof(data_path), "%s/logs", base_path); if (!fileExists(data_path)) { if (mkdir(data_path, 0755) != 0) { fprintf(stderr, "mkdir \"%s\" fail, " \ "errno: %d, error info: %s\n", \ data_path, errno, STRERROR(errno)); return errno != 0 ? errno : EPERM; } } return 0; } int log_init() { if (g_log_context.log_buff != NULL) { fprintf(stderr, "file: "__FILE__", line: %d, " "g_log_context already inited\n", __LINE__); return 0; } return log_init_ex(&g_log_context); } int log_init2() { int result; if ((result=log_init()) != 0) { return result; } log_take_over_stderr(); log_take_over_stdout(); return 0; } int log_init_ex(LogContext *pContext) { int result; memset(pContext, 0, sizeof(LogContext)); pContext->log_level = LOG_INFO; pContext->log_fd = STDERR_FILENO; pContext->time_precision = LOG_TIME_PRECISION_SECOND; pContext->compress_log_days_before = 1; strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S"); pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE); if (pContext->log_buff == NULL) { fprintf(stderr, "malloc %d bytes fail, " \ "errno: %d, error info: %s\n", \ LOG_BUFF_SIZE, errno, STRERROR(errno)); return errno != 0 ? errno : ENOMEM; } pContext->pcurrent_buff = pContext->log_buff; if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0) { return result; } return 0; } static int log_print_header(LogContext *pContext) { int result; if (!pContext->use_file_write_lock) { if ((result=file_write_lock(pContext->log_fd)) != 0) { return result; } } pContext->current_size = lseek(pContext->log_fd, 0, SEEK_END); if (pContext->current_size < 0) { result = errno != 0 ? errno : EACCES; fprintf(stderr, "lseek file \"%s\" fail, " \ "errno: %d, error info: %s\n", \ pContext->log_filename, result, STRERROR(result)); } else { result = 0; if (pContext->current_size == 0) { pContext->print_header_callback(pContext); } } if (!pContext->use_file_write_lock) { file_unlock(pContext->log_fd); } return result; } static int log_open(LogContext *pContext) { int result; if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC | pContext->fd_flags, 0644)) < 0) { fprintf(stderr, "open log file \"%s\" to write fail, " \ "errno: %d, error info: %s\n", \ pContext->log_filename, errno, STRERROR(errno)); pContext->log_fd = STDERR_FILENO; return errno != 0 ? errno : EACCES; } if (pContext->use_file_write_lock) { if ((result=file_try_write_lock(pContext->log_fd)) != 0) { close(pContext->log_fd); pContext->log_fd = STDERR_FILENO; return result; } } if (pContext->take_over_stderr) { if (dup2(pContext->log_fd, STDERR_FILENO) < 0) { fprintf(stderr, "file: "__FILE__", line: %d, " "call dup2 fail, errno: %d, error info: %s\n", __LINE__, errno, STRERROR(errno)); } } if (pContext->take_over_stdout) { if (dup2(pContext->log_fd, STDOUT_FILENO) < 0) { fprintf(stderr, "file: "__FILE__", line: %d, " "call dup2 fail, errno: %d, error info: %s\n", __LINE__, errno, STRERROR(errno)); } } pContext->current_size = lseek(pContext->log_fd, 0, SEEK_END); if (pContext->current_size < 0) { fprintf(stderr, "lseek file \"%s\" fail, " \ "errno: %d, error info: %s\n", \ pContext->log_filename, errno, STRERROR(errno)); return errno != 0 ? errno : EACCES; } if (pContext->current_size == 0 && pContext->print_header_callback != NULL) { log_print_header(pContext); } return 0; } int log_reopen_ex(LogContext *pContext) { if (*(pContext->log_filename) == '\0') { return ENOENT; } if (pContext->log_fd >= 0 && pContext->log_fd != STDERR_FILENO) { close(pContext->log_fd); } return log_open(pContext); } int log_set_prefix_ex(LogContext *pContext, const char *base_path, const char *filename_prefix) { int result; char log_filename[MAX_PATH_SIZE]; if ((result=check_and_mk_log_dir(base_path)) != 0) { return result; } snprintf(log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", base_path, filename_prefix); return log_set_filename_ex(pContext, log_filename); } int log_set_filename_ex(LogContext *pContext, const char *log_filename) { if (log_filename == NULL || *log_filename == '\0') { fprintf(stderr, "file: "__FILE__", line: %d, " "log_filename is NULL or empty!\n", __LINE__); return EINVAL; } if (*(pContext->log_filename) == '\0') { snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename); return log_open(pContext); } if (strcmp(log_filename, pContext->log_filename) == 0) { return 0; } snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename); return log_reopen_ex(pContext); } void log_set_cache_ex(LogContext *pContext, const bool bLogCache) { pContext->log_to_cache = bLogCache; } void log_set_use_file_write_lock_ex(LogContext *pContext, const bool use_lock) { pContext->use_file_write_lock = use_lock; } void log_set_time_precision(LogContext *pContext, const int time_precision) { pContext->time_precision = time_precision; } void log_set_rotate_time_format(LogContext *pContext, const char *time_format) { snprintf(pContext->rotate_time_format, sizeof(pContext->rotate_time_format), "%s", time_format); } void log_set_keep_days(LogContext *pContext, const int keep_days) { pContext->keep_days = keep_days; } void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_callback) { pContext->print_header_callback = header_callback; if (pContext->print_header_callback != NULL) { int64_t current_size; pthread_mutex_lock(&(pContext->log_thread_lock)); current_size = pContext->current_size; pthread_mutex_unlock(&(pContext->log_thread_lock)); if (current_size == 0) { log_print_header(pContext); } } } void log_take_over_stderr_ex(LogContext *pContext) { pContext->take_over_stderr = true; } void log_take_over_stdout_ex(LogContext *pContext) { pContext->take_over_stdout = true; } void log_set_compress_log_flags_ex(LogContext *pContext, const short flags) { pContext->compress_log_flags = flags; } void log_set_compress_log_days_before_ex(LogContext *pContext, const int days_before) { if (days_before > 0) { pContext->compress_log_days_before = days_before; } else { pContext->compress_log_days_before = 1; } } void log_set_fd_flags(LogContext *pContext, const int flags) { pContext->fd_flags = flags; } void log_destroy_ex(LogContext *pContext) { if (pContext->log_fd >= 0 && pContext->log_fd != STDERR_FILENO) { log_fsync(pContext, true); close(pContext->log_fd); pContext->log_fd = STDERR_FILENO; pthread_mutex_destroy(&pContext->log_thread_lock); } if (pContext->log_buff != NULL) { free(pContext->log_buff); pContext->log_buff = NULL; pContext->pcurrent_buff = NULL; } } int log_sync_func(void *args) { if (args == NULL) { return EINVAL; } return log_fsync((LogContext *)args, true); } int log_notify_rotate(void *args) { if (args == NULL) { return EINVAL; } ((LogContext *)args)->rotate_immediately = true; return 0; } static int log_delete_old_file(LogContext *pContext, const char *old_filename) { char full_filename[MAX_PATH_SIZE + 128]; if (NEED_COMPRESS_LOG(pContext->compress_log_flags)) { snprintf(full_filename, sizeof(full_filename), "%s%s", old_filename, GZIP_EXT_NAME_STR); } else { snprintf(full_filename, sizeof(full_filename), "%s", old_filename); } if (unlink(full_filename) != 0) { if (errno != ENOENT) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "unlink %s fail, errno: %d, error info: %s\n", \ __LINE__, full_filename, errno, STRERROR(errno)); } else if (NEED_COMPRESS_LOG(pContext->compress_log_flags)) { unlink(old_filename); } return errno != 0 ? errno : EPERM; } return 0; } static int log_get_prefix_len(LogContext *pContext, int *prefix_len) { char *p; if (*(pContext->log_filename) == '\0' || \ *(pContext->rotate_time_format) == '\0') { *prefix_len = 0; return EINVAL; } p = pContext->rotate_time_format + strlen(pContext->rotate_time_format) - 1; while (p > pContext->rotate_time_format) { if (*(p-1) != '%') { break; } if (*p == 'd' || *p == 'm' || *p == 'Y' || *p == 'y') { break; } p -= 2; } *prefix_len = (p - pContext->rotate_time_format) + 1; if (*prefix_len == 0) { return EINVAL; } return 0; } struct log_filename_array { char **filenames; int count; int size; }; static int log_check_filename_array_size(struct log_filename_array * filename_array) { char **new_filenames; int new_size; int bytes; if (filename_array->size > filename_array->count) { return 0; } new_size = filename_array->size == 0 ? 8 : filename_array->size * 2; bytes = sizeof(char *) * new_size; new_filenames = (char **)malloc(bytes); if (new_filenames == NULL) { fprintf(stderr, "file: "__FILE__", line: %d, " "malloc %d bytes fail, errno: %d, error info: %s\n", __LINE__, bytes, errno, STRERROR(errno)); return errno != 0 ? errno : ENOMEM; } if (filename_array->count > 0) { memcpy(new_filenames, filename_array->filenames, sizeof(char *) * filename_array->count); } if (filename_array->filenames != NULL) { free(filename_array->filenames); } filename_array->filenames = new_filenames; filename_array->size = new_size; return 0; } static void log_free_filename_array(struct log_filename_array * filename_array) { int i; if (filename_array->filenames == NULL) { return; } for (i=0; icount; i++) { free(filename_array->filenames[i]); } free(filename_array->filenames); filename_array->filenames = NULL; filename_array->size = 0; filename_array->count = 0; } static void log_get_file_path(LogContext *pContext, char *log_filepath) { char *p; p = strrchr(pContext->log_filename, '/'); if (p == NULL) { *log_filepath = '.'; *(log_filepath + 1) = '/'; *(log_filepath + 2) = '\0'; } else { int path_len; path_len = (p - pContext->log_filename) + 1; memcpy(log_filepath, pContext->log_filename, path_len); *(log_filepath + path_len) = '\0'; } } static int log_get_matched_files(LogContext *pContext, const int prefix_len, const int days_before, struct log_filename_array *filename_array) { char rotate_time_format_prefix[32]; char log_filepath[MAX_PATH_SIZE]; char filename_prefix[MAX_PATH_SIZE + 32]; int prefix_filename_len; int result; int len; char *p; char *log_filename; char *filename; DIR *dir; #ifndef OS_LINUX struct dirent ent; #endif struct dirent *pEntry; time_t the_time; struct tm tm; filename_array->filenames = NULL; filename_array->count = 0; filename_array->size = 0; p = strrchr(pContext->log_filename, '/'); if (p == NULL) { *log_filepath = '.'; *(log_filepath + 1) = '/'; *(log_filepath + 2) = '\0'; log_filename = pContext->log_filename; } else { int path_len; path_len = (p - pContext->log_filename) + 1; memcpy(log_filepath, pContext->log_filename, path_len); *(log_filepath + path_len) = '\0'; log_filename = p + 1; } memcpy(rotate_time_format_prefix, pContext->rotate_time_format, prefix_len); *(rotate_time_format_prefix + prefix_len) = '\0'; dir = opendir(log_filepath); if (dir == NULL) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "opendir %s fail, errno: %d, error info: %s\n", \ __LINE__, log_filepath, errno, STRERROR(errno)); return errno != 0 ? errno : ENOENT; } result = 0; the_time = get_current_time() - days_before * 86400; localtime_r(&the_time, &tm); memset(filename_prefix, 0, sizeof(filename_prefix)); len = sprintf(filename_prefix, "%s.", log_filename); strftime(filename_prefix + len, sizeof(filename_prefix) - len, rotate_time_format_prefix, &tm); prefix_filename_len = strlen(filename_prefix); #ifndef OS_LINUX while (readdir_r(dir, &ent, &pEntry) == 0) #else while ((pEntry=readdir(dir)) != NULL) #endif { if (pEntry == NULL) { break; } if ((int)strlen(pEntry->d_name) >= prefix_filename_len && memcmp(pEntry->d_name, filename_prefix, prefix_filename_len) == 0) { if ((result=log_check_filename_array_size(filename_array)) != 0) { break; } filename = strdup(pEntry->d_name); if (filename == NULL) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "strdup %s fail, errno: %d, error info: %s\n", \ __LINE__, pEntry->d_name, errno, STRERROR(errno)); break; } filename_array->filenames[filename_array->count] = filename; filename_array->count++; } } closedir(dir); return result; } static int log_delete_matched_old_files(LogContext *pContext, const int prefix_len) { struct log_filename_array filename_array; char log_filepath[MAX_PATH_SIZE]; char full_filename[MAX_PATH_SIZE + 32]; int result; int i; if ((result=log_get_matched_files(pContext, prefix_len, pContext->keep_days + 1, &filename_array)) != 0) { return result; } log_get_file_path(pContext, log_filepath); for (i=0; ikeep_days <= 0) { return 0; } if ((result=log_get_prefix_len(pContext, &prefix_len)) != 0) { return result; } if (prefix_len == (int)strlen(pContext->rotate_time_format)) { time_t the_time; the_time = get_current_time() - pContext->keep_days * 86400; while (1) { the_time -= 86400; localtime_r(&the_time, &tm); memset(old_filename, 0, sizeof(old_filename)); len = sprintf(old_filename, "%s.", pContext->log_filename); strftime(old_filename + len, sizeof(old_filename) - len, pContext->rotate_time_format, &tm); if ((result=log_delete_old_file(pContext, old_filename)) != 0) { if (result != ENOENT) { return result; } break; } } return 0; } else { return log_delete_matched_old_files(pContext, prefix_len); } } static void *log_gzip_func(void *args) { LogContext *pContext; char cmd[MAX_PATH_SIZE + 128]; struct log_filename_array filename_array; char log_filepath[MAX_PATH_SIZE]; char full_filename[MAX_PATH_SIZE + 32]; char output[512]; int prefix_len; int result; int i; pContext = (LogContext *)args; if (log_get_prefix_len(pContext, &prefix_len) != 0) { return NULL; } if (log_get_matched_files(pContext, prefix_len, pContext->compress_log_days_before, &filename_array) != 0) { return NULL; } log_get_file_path(pContext, log_filepath); for (i=0; i GZIP_EXT_NAME_LEN) && memcmp(filename_array.filenames[i] + len - GZIP_EXT_NAME_LEN, GZIP_EXT_NAME_STR, GZIP_EXT_NAME_LEN) == 0) { continue; } snprintf(full_filename, sizeof(full_filename), "%s%s", log_filepath, filename_array.filenames[i]); snprintf(cmd, sizeof(cmd), "%s %s", get_gzip_command_filename(), full_filename); result = getExecResult(cmd, output, sizeof(output)); if (result != 0) { fprintf(stderr, "file: "__FILE__", line: %d, " "exec command \"%s\" fail, " "errno: %d, error info: %s", __LINE__, cmd, result, STRERROR(result)); break; } if (*output != '\0') { fprintf(stderr, "file: "__FILE__", line: %d, " "exec command \"%s\", output: %s", __LINE__, cmd, output); } } log_free_filename_array(&filename_array); return NULL; } static void log_gzip(LogContext *pContext) { if (COMPRESS_IN_NEW_THREAD(pContext->compress_log_flags)) { int result; pthread_t tid; pthread_attr_t thread_attr; if ((result=init_pthread_attr(&thread_attr, 0) != 0)) { return; } if ((result=pthread_create(&tid, &thread_attr, log_gzip_func, pContext)) != 0) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "create thread failed, " \ "errno: %d, error info: %s\n", \ __LINE__, result, STRERROR(result)); } pthread_attr_destroy(&thread_attr); } else { log_gzip_func(pContext); } } int log_rotate(LogContext *pContext) { struct tm tm; time_t current_time; int len; int result; char old_filename[MAX_PATH_SIZE + 32]; bool exist; if (*(pContext->log_filename) == '\0') { return ENOENT; } close(pContext->log_fd); current_time = get_current_time(); if (tm.tm_hour == 0 && tm.tm_min <= 1) { if (strstr(pContext->rotate_time_format, "%H") == NULL && strstr(pContext->rotate_time_format, "%M") == NULL && strstr(pContext->rotate_time_format, "%S") == NULL) { current_time -= 120; } } localtime_r(¤t_time, &tm); memset(old_filename, 0, sizeof(old_filename)); len = sprintf(old_filename, "%s.", pContext->log_filename); strftime(old_filename + len, sizeof(old_filename) - len, pContext->rotate_time_format, &tm); if (access(old_filename, F_OK) == 0) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "file: %s already exist, rotate file fail\n", __LINE__, old_filename); exist = true; } else if (rename(pContext->log_filename, old_filename) != 0) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "rename %s to %s fail, errno: %d, error info: %s\n", \ __LINE__, pContext->log_filename, old_filename, \ errno, STRERROR(errno)); exist = false; } else { exist = true; } result = log_open(pContext); if (exist && NEED_COMPRESS_LOG(pContext->compress_log_flags)) { log_gzip(pContext); } return result; } static int log_check_rotate(LogContext *pContext) { if (pContext->log_fd == STDERR_FILENO) { if (pContext->current_size > 0) { pContext->current_size = 0; } return ENOENT; } if (pContext->rotate_immediately) { pContext->rotate_immediately = false; return log_rotate(pContext); } return 0; } static int log_fsync(LogContext *pContext, const bool bNeedLock) { int result; int lock_res; int write_bytes; int written; if (pContext->pcurrent_buff - pContext->log_buff == 0) { if (!pContext->rotate_immediately) { return 0; } else { if (bNeedLock) { pthread_mutex_lock(&(pContext->log_thread_lock)); } result = log_check_rotate(pContext); if (bNeedLock) { pthread_mutex_unlock(&(pContext->log_thread_lock)); } return result; } } if (bNeedLock && ((lock_res=pthread_mutex_lock( \ &(pContext->log_thread_lock))) != 0)) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "call pthread_mutex_lock fail, " \ "errno: %d, error info: %s\n", \ __LINE__, lock_res, STRERROR(lock_res)); } write_bytes = pContext->pcurrent_buff - pContext->log_buff; pContext->current_size += write_bytes; if (pContext->rotate_size > 0) { if (pContext->current_size > pContext->rotate_size) { pContext->rotate_immediately = true; log_check_rotate(pContext); } } result = 0; written = write(pContext->log_fd, pContext->log_buff, write_bytes); pContext->pcurrent_buff = pContext->log_buff; if (written != write_bytes) { result = errno != 0 ? errno : EIO; fprintf(stderr, "file: "__FILE__", line: %d, " "pid: %d, call write fail, fd: %d, errno: %d, error info: %s\n", __LINE__, getpid(), pContext->log_fd, result, STRERROR(result)); } if (pContext->rotate_immediately) { log_check_rotate(pContext); } if (bNeedLock && ((lock_res=pthread_mutex_unlock( \ &(pContext->log_thread_lock))) != 0)) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "call pthread_mutex_unlock fail, " \ "errno: %d, error info: %s\n", \ __LINE__, lock_res, STRERROR(lock_res)); } return result; } static void doLogEx(LogContext *pContext, struct timeval *tv, \ const char *caption, const char *text, const int text_len, \ const bool bNeedSync, const bool bNeedLock) { struct tm tm; int time_fragment; int buff_len; int result; if ((pContext->time_precision == LOG_TIME_PRECISION_SECOND) || (pContext->time_precision == LOG_TIME_PRECISION_NONE)) { time_fragment = 0; } else { if (pContext->time_precision == LOG_TIME_PRECISION_MSECOND) { time_fragment = tv->tv_usec / 1000; } else { time_fragment = tv->tv_usec; } } if (bNeedLock && (result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "call pthread_mutex_lock fail, " \ "errno: %d, error info: %s\n", \ __LINE__, result, STRERROR(result)); } if (text_len + 64 > LOG_BUFF_SIZE) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "log buff size: %d < log text length: %d\n", \ __LINE__, LOG_BUFF_SIZE, text_len + 64); if (bNeedLock) { pthread_mutex_unlock(&(pContext->log_thread_lock)); } return; } if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \ > LOG_BUFF_SIZE) { log_fsync(pContext, false); } if (pContext->time_precision != LOG_TIME_PRECISION_NONE) { localtime_r(&tv->tv_sec, &tm); if (pContext->time_precision == LOG_TIME_PRECISION_SECOND) { buff_len = sprintf(pContext->pcurrent_buff, \ "[%04d-%02d-%02d %02d:%02d:%02d] ", \ tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \ tm.tm_hour, tm.tm_min, tm.tm_sec); } else { buff_len = sprintf(pContext->pcurrent_buff, \ "[%04d-%02d-%02d %02d:%02d:%02d.%03d] ", \ tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \ tm.tm_hour, tm.tm_min, tm.tm_sec, time_fragment); } pContext->pcurrent_buff += buff_len; } if (caption != NULL) { buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption); pContext->pcurrent_buff += buff_len; } memcpy(pContext->pcurrent_buff, text, text_len); pContext->pcurrent_buff += text_len; *pContext->pcurrent_buff++ = '\n'; if (!pContext->log_to_cache || bNeedSync) { log_fsync(pContext, false); } if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0) { fprintf(stderr, "file: "__FILE__", line: %d, " \ "call pthread_mutex_unlock fail, " \ "errno: %d, error info: %s\n", \ __LINE__, result, STRERROR(result)); } } void log_it_ex2(LogContext *pContext, const char *caption, \ const char *text, const int text_len, \ const bool bNeedSync, const bool bNeedLock) { struct timeval tv; if (pContext->time_precision == LOG_TIME_PRECISION_SECOND) { tv.tv_sec = get_current_time(); tv.tv_usec = 0; } else if (pContext->time_precision != LOG_TIME_PRECISION_NONE) { gettimeofday(&tv, NULL); } doLogEx(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock); } void log_it_ex1(LogContext *pContext, const int priority, \ const char *text, const int text_len) { bool bNeedSync; char *caption; if (pContext->log_level < priority) { return; } switch (priority) { case LOG_DEBUG: bNeedSync = true; caption = "DEBUG"; break; case LOG_INFO: bNeedSync = true; caption = "INFO"; break; case LOG_NOTICE: bNeedSync = false; caption = "NOTICE"; break; case LOG_WARNING: bNeedSync = false; caption = "WARNING"; break; case LOG_ERR: bNeedSync = false; caption = "ERROR"; break; case LOG_CRIT: bNeedSync = true; caption = "CRIT"; break; case LOG_ALERT: bNeedSync = true; caption = "ALERT"; break; case LOG_EMERG: bNeedSync = true; caption = "EMERG"; break; default: bNeedSync = false; caption = "UNKOWN"; break; } log_it_ex2(pContext, caption, text, text_len, bNeedSync, true); } void log_it_ex(LogContext *pContext, const int priority, const char *format, ...) { bool bNeedSync; char text[LINE_MAX]; char *caption; int len; va_list ap; if (pContext->log_level < priority) { return; } va_start(ap, format); len = vsnprintf(text, sizeof(text), format, ap); va_end(ap); if (len >= sizeof(text)) { len = sizeof(text) - 1; } switch (priority) { case LOG_DEBUG: bNeedSync = true; caption = "DEBUG"; break; case LOG_INFO: bNeedSync = true; caption = "INFO"; break; case LOG_NOTICE: bNeedSync = false; caption = "NOTICE"; break; case LOG_WARNING: bNeedSync = false; caption = "WARNING"; break; case LOG_ERR: bNeedSync = false; caption = "ERROR"; break; case LOG_CRIT: bNeedSync = true; caption = "CRIT"; break; case LOG_ALERT: bNeedSync = true; caption = "ALERT"; break; case LOG_EMERG: bNeedSync = true; caption = "EMERG"; break; default: bNeedSync = false; caption = "UNKOWN"; break; } log_it_ex2(pContext, caption, text, len, bNeedSync, true); } #define _DO_LOG(pContext, priority, caption, bNeedSync) \ char text[LINE_MAX]; \ int len; \ \ if (pContext->log_level < priority) \ { \ return; \ } \ \ { \ va_list ap; \ va_start(ap, format); \ len = vsnprintf(text, sizeof(text), format, ap); \ va_end(ap); \ if (len >= sizeof(text)) \ { \ len = sizeof(text) - 1; \ } \ } \ \ log_it_ex2(pContext, caption, text, len, bNeedSync, true); void logEmergEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_EMERG, "EMERG", true) } void logAlertEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_ALERT, "ALERT", true) } void logCritEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_CRIT, "CRIT", true) } void logErrorEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_ERR, "ERROR", false) } void logWarningEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_WARNING, "WARNING", false) } void logNoticeEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_NOTICE, "NOTICE", false) } void logInfoEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_INFO, "INFO", false) } void logDebugEx(LogContext *pContext, const char *format, ...) { _DO_LOG(pContext, LOG_DEBUG, "DEBUG", false) } void logAccess(LogContext *pContext, struct timeval *tvStart, \ const char *format, ...) { char text[LINE_MAX]; int len; va_list ap; va_start(ap, format); len = vsnprintf(text, sizeof(text), format, ap); va_end(ap); if (len >= sizeof(text)) { len = sizeof(text) - 1; } doLogEx(pContext, tvStart, NULL, text, len, false, true); } const char *log_get_level_caption_ex(LogContext *pContext) { return get_log_level_caption(pContext->log_level); } #ifndef LOG_FORMAT_CHECK void logEmerg(const char *format, ...) { _DO_LOG((&g_log_context), LOG_EMERG, "EMERG", true) } void logAlert(const char *format, ...) { _DO_LOG((&g_log_context), LOG_ALERT, "ALERT", true) } void logCrit(const char *format, ...) { _DO_LOG((&g_log_context), LOG_CRIT, "CRIT", true) } void logError(const char *format, ...) { _DO_LOG((&g_log_context), LOG_ERR, "ERROR", false) } void logWarning(const char *format, ...) { _DO_LOG((&g_log_context), LOG_WARNING, "WARNING", false) } void logNotice(const char *format, ...) { _DO_LOG((&g_log_context), LOG_NOTICE, "NOTICE", false) } void logInfo(const char *format, ...) { _DO_LOG((&g_log_context), LOG_INFO, "INFO", true) } void logDebug(const char *format, ...) { _DO_LOG((&g_log_context), LOG_DEBUG, "DEBUG", true) } #endif