From 49822347cb81f3c7fa624c7fa7d8cf75d61da3d8 Mon Sep 17 00:00:00 2001 From: yangwei Date: Sat, 31 Aug 2019 23:35:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=94=B9=E4=B8=BAzlog?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + CMakeLists.txt | 7 + demo/test_handle_logger.c | 2 +- src/MESA_handle_logger.c | 217 ++++---- src/version.map | 4 + zlog/CMakeLists.txt | 11 + zlog/buf.c | 649 +++++++++++++++++++++++ zlog/buf.h | 56 ++ zlog/category.c | 233 ++++++++ zlog/category.h | 38 ++ zlog/category_table.c | 129 +++++ zlog/category_table.h | 28 + zlog/conf.c | 504 ++++++++++++++++++ zlog/conf.h | 46 ++ zlog/event.c | 182 +++++++ zlog/event.h | 90 ++++ zlog/fmacros.h | 24 + zlog/format.c | 164 ++++++ zlog/format.h | 32 ++ zlog/level.c | 141 +++++ zlog/level.h | 26 + zlog/level_list.c | 145 +++++ zlog/level_list.h | 33 ++ zlog/makefile | 204 +++++++ zlog/mdc.c | 145 +++++ zlog/mdc.h | 36 ++ zlog/record.c | 53 ++ zlog/record.h | 32 ++ zlog/record_table.c | 56 ++ zlog/record_table.h | 19 + zlog/rotater.c | 575 ++++++++++++++++++++ zlog/rotater.h | 45 ++ zlog/rule.c | 1058 +++++++++++++++++++++++++++++++++++++ zlog/rule.h | 88 +++ zlog/spec.c | 659 +++++++++++++++++++++++ zlog/spec.h | 60 +++ zlog/thread.c | 184 +++++++ zlog/thread.h | 38 ++ zlog/version.h | 1 + zlog/zc_arraylist.c | 132 +++++ zlog/zc_arraylist.h | 41 ++ zlog/zc_defs.h | 18 + zlog/zc_hashtable.c | 330 ++++++++++++ zlog/zc_hashtable.h | 49 ++ zlog/zc_profile.c | 86 +++ zlog/zc_profile.h | 53 ++ zlog/zc_util.c | 147 ++++++ zlog/zc_util.h | 17 + zlog/zc_xplatform.h | 61 +++ zlog/zlog-chk-conf.c | 70 +++ zlog/zlog.c | 1024 +++++++++++++++++++++++++++++++++++ zlog/zlog.h | 279 ++++++++++ 52 files changed, 8198 insertions(+), 127 deletions(-) create mode 100644 src/version.map create mode 100644 zlog/CMakeLists.txt create mode 100644 zlog/buf.c create mode 100644 zlog/buf.h create mode 100644 zlog/category.c create mode 100644 zlog/category.h create mode 100644 zlog/category_table.c create mode 100644 zlog/category_table.h create mode 100644 zlog/conf.c create mode 100644 zlog/conf.h create mode 100644 zlog/event.c create mode 100644 zlog/event.h create mode 100644 zlog/fmacros.h create mode 100644 zlog/format.c create mode 100644 zlog/format.h create mode 100644 zlog/level.c create mode 100644 zlog/level.h create mode 100644 zlog/level_list.c create mode 100644 zlog/level_list.h create mode 100644 zlog/makefile create mode 100644 zlog/mdc.c create mode 100644 zlog/mdc.h create mode 100644 zlog/record.c create mode 100644 zlog/record.h create mode 100644 zlog/record_table.c create mode 100644 zlog/record_table.h create mode 100644 zlog/rotater.c create mode 100644 zlog/rotater.h create mode 100644 zlog/rule.c create mode 100644 zlog/rule.h create mode 100644 zlog/spec.c create mode 100644 zlog/spec.h create mode 100644 zlog/thread.c create mode 100644 zlog/thread.h create mode 100644 zlog/version.h create mode 100644 zlog/zc_arraylist.c create mode 100644 zlog/zc_arraylist.h create mode 100644 zlog/zc_defs.h create mode 100644 zlog/zc_hashtable.c create mode 100644 zlog/zc_hashtable.h create mode 100644 zlog/zc_profile.c create mode 100644 zlog/zc_profile.h create mode 100644 zlog/zc_util.c create mode 100644 zlog/zc_util.h create mode 100644 zlog/zc_xplatform.h create mode 100644 zlog/zlog-chk-conf.c create mode 100644 zlog/zlog.c create mode 100644 zlog/zlog.h diff --git a/.gitignore b/.gitignore index 0433f2f..647907e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ build/ core.* version.txt demo/test_handle_logger +cmake-build-debug +GPATH +GRTAGS +GTAGS diff --git a/CMakeLists.txt b/CMakeLists.txt index 234c12a..0d6886a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,9 @@ endif() # end of for ASAN include_directories(${PROJECT_SOURCE_DIR}/inc/) +include_directories(${PROJECT_SOURCE_DIR}/zlog/src/) + +add_subdirectory(zlog) file(GLOB SRC "src/*.c" @@ -37,6 +40,9 @@ file(GLOB SRC # Shared Library Output add_library(${lib_name}_shared SHARED ${SRC}) +target_link_libraries(${lib_name}_shared -Wl,--whole-archive zlog_static -Wl,--no-whole-archive) +set_target_properties(${lib_name}_shared PROPERTIES LINK_FLAGS + "-Wl,--version-script=${PROJECT_SOURCE_DIR}/src/version.map") if(DEFINED MESA_SHARED_INSTALL_DIR) set_target_properties(${lib_name}_shared PROPERTIES OUTPUT_NAME ${lib_name} LIBRARY_OUTPUT_DIRECTORY ${MESA_SHARED_INSTALL_DIR}) else() @@ -45,6 +51,7 @@ endif() # static Library Output add_library(${lib_name}_static STATIC ${SRC}) +target_link_libraries(${lib_name}_static -Wl,--whole-archive zlog_static -Wl,--no-whole-archive) set_target_properties(${lib_name}_static PROPERTIES OUTPUT_NAME ${lib_name}) set(CMAKE_INSTALL_PREFIX /opt/MESA) diff --git a/demo/test_handle_logger.c b/demo/test_handle_logger.c index 816d11c..448c14b 100644 --- a/demo/test_handle_logger.c +++ b/demo/test_handle_logger.c @@ -39,7 +39,7 @@ void call_logger(int log_num, int thread_num) { MESA_handle_runtime_log(sample_handle, RLOG_LV_INFO, "sample", "sample_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num); //sleep(1); - //MESA_handle_runtime_log(test_handle, RLOG_LV_INFO, "test", "test_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num); + MESA_handle_runtime_log(test_handle, RLOG_LV_INFO, "test", "test_handle MESA_handle_runtime_log, i = %d, thread_num = %d", i, thread_num); //MESA_HANDLE_RUNTIME_LOG(sample_handle, RLOG_LV_FATAL, "sample", "sample_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num); ////sleep(1); //MESA_HANDLE_RUNTIME_LOG(test_handle, RLOG_LV_FATAL, "test", "test_handle RUNTIEM_LOG test, i = %d, thread_num = %d", i, thread_num); diff --git a/src/MESA_handle_logger.c b/src/MESA_handle_logger.c index 7e7724c..35a73a4 100644 --- a/src/MESA_handle_logger.c +++ b/src/MESA_handle_logger.c @@ -1,22 +1,20 @@ #include "MESA_handle_logger.h" +#include "zlog.h" -#include -#include #include +#include #include -#include #include -#include -#define LOGMSG_MAX_LEN 4096 -#define FLUSH_LOG_NUM 4096 +#define MAX_HANDLE_LOG_PATH 4096 +#define GLOB_ZLOG_CONF "GLOB_ZLOG_CONF" + typedef struct log_handle_t { int runtime_log_level; - int flush_log_count; - FILE *fp; - char runtime_log_file[1200]; - char cur_log_file[LOGMSG_MAX_LEN]; + zlog_category_t *zc; + const char *global_conf_path; + char runtime_log_file[MAX_HANDLE_LOG_PATH]; } log_handle_t; @@ -45,12 +43,6 @@ static __attribute__((__used__)) const char * GIT_VERSION_UNKNOWN = NULL; #endif -static unsigned char weekday_str[7][4] = -{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - -static unsigned char month_str[12][4] = {"Jan", "Feb", "Mar", "Apr", - "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - static int create_dir(const char *dir_path, int path_len) { if(dir_path == NULL) @@ -93,35 +85,94 @@ static int create_path(const char *path, int path_len) return 0; } +static zlog_category_t *init_zlog(const char *conf_path, const char *category) +{ + zlog_category_t *zc = NULL; + if (access(conf_path, R_OK) != -1) + { + + int rc = zlog_init(conf_path); + if (rc) + { + rc = zlog_reload(conf_path); + if(rc) + { + printf("init zlog by %s failed\n", conf_path); + return NULL; + } + } + + zc = zlog_get_category(category); + if (!zc) + { + printf("get zlog category %s in %s fail\n", category, conf_path); + zlog_fini(); + return NULL; + } + } + return zc; +} + void *MESA_create_runtime_log_handle(const char *file_path, int level) { if(file_path == NULL) return NULL; + int rc; + zlog_category_t *zc; FILE *fp = NULL; log_handle_t *p_handle = NULL; - //creating file_path failed, return NULL - char *p_path = rindex(file_path, '/'); - if(p_path != 0) - { - if(create_path(file_path, p_path - file_path) < 0) - return NULL; - } - if(NULL == (fp = fopen(file_path, "w"))) - return NULL; + const char *p_conf_path = NULL; + const char *p_name = NULL; + char *p_path_end = rindex(file_path, '/'); + int path_len = 0; + if (p_path_end != NULL) + { + path_len = p_path_end - file_path; + if(path_len == 0)return NULL; + p_name = p_path_end+1; + } + else + { + p_name = file_path; + } + char *pathvar = getenv(GLOB_ZLOG_CONF); - //fclose(fp); - //remove(file_path); + if (pathvar == NULL) + { + //creating file_path failed, return NULL + if (path_len > 0 && create_path(file_path, path_len) < 0)return NULL; + char default_zlog_conf_path[MAX_HANDLE_LOG_PATH + 5]; + snprintf(default_zlog_conf_path, sizeof(default_zlog_conf_path), "%s.conf", file_path); + if (access(default_zlog_conf_path, R_OK) != 0) + { + fp = fopen(default_zlog_conf_path, "w"); + if(fp == NULL)return NULL; + char zlog_rule_conf_content[MAX_HANDLE_LOG_PATH + 1]; + snprintf(zlog_rule_conf_content, sizeof(zlog_rule_conf_content), + "[global] \n default format = \"%%d(%%c), %%V, %%m%%n\" \n[levels]\n DEBUG=10\n INFO=20\n FATAL=30\n[rules]\n %s.* \"%s.%%d(%%F)\"", + p_name, file_path); + fwrite(zlog_rule_conf_content, strlen(zlog_rule_conf_content), 1, fp); + fclose(fp); + } + p_conf_path = default_zlog_conf_path; + } + else + { + if (access(pathvar, R_OK) != 0) + { + return NULL; + } + p_conf_path = pathvar; + } + zc = init_zlog(p_conf_path, p_name); + if (zc == NULL)return NULL; p_handle = (log_handle_t *)calloc(sizeof(log_handle_t), 1); - - if(p_handle == NULL) - return NULL; - - strncpy(p_handle->runtime_log_file, file_path, 1024); - p_handle->runtime_log_file[1024] = '\0'; + strncpy(p_handle->runtime_log_file, file_path, sizeof(p_handle->runtime_log_file) - 1); p_handle->runtime_log_level = level; - //p_handle->fp = fp; + p_handle->zc = zc; + p_handle->global_conf_path = pathvar; return (void *)p_handle; } @@ -130,12 +181,7 @@ void MESA_destroy_runtime_log_handle(void *handle) if(handle != NULL) { log_handle_t *p_handle = (log_handle_t *)handle; - if (p_handle->fp != NULL) - { - fclose(p_handle->fp); - p_handle->fp = NULL; - } - free(handle); + free(handle); handle = NULL; } @@ -144,98 +190,17 @@ void MESA_destroy_runtime_log_handle(void *handle) void MESA_handle_runtime_log(void *handle, int level, const char *module, const char *fmt, ...) { - char buf[LOGMSG_MAX_LEN + 1]; - time_t t; - int len; - va_list ap; - FILE *fp; - struct tm local_time; - char tmp_log_file_name[1400]; + log_handle_t *p_handle = (log_handle_t *)handle; if(p_handle == NULL || p_handle->runtime_log_file == NULL)return; if(level < p_handle->runtime_log_level) return; - - time(&t); - if(NULL == (localtime_r(&t, &local_time))) return; - len = snprintf(buf, sizeof(buf), "%s %s %d %02d:%02d:%02d %d", weekday_str[local_time.tm_wday], - month_str[local_time.tm_mon], local_time.tm_mday, local_time.tm_hour, local_time.tm_min, local_time.tm_sec, local_time.tm_year+1900); - //len = strlen(buf); - - switch(level) - { - case RLOG_LV_DEBUG: - len += snprintf(buf + len, - LOGMSG_MAX_LEN - len, ", %s, ", "DEBUG"); - break; - - case RLOG_LV_INFO: - len += snprintf(buf + len, - LOGMSG_MAX_LEN - len, ", %s, ", "INFO"); - break; - - case RLOG_LV_FATAL: - len += snprintf(buf + len, - LOGMSG_MAX_LEN - len, ", %s, ", "FATAL"); - break; - - default: - len += snprintf(buf + len, - LOGMSG_MAX_LEN - len, ", %s, ", "UNKNOWN"); - break; - } - - if(0 >= LOGMSG_MAX_LEN - len) return; - - len += snprintf(buf + len, LOGMSG_MAX_LEN - len, "%s, ", module); - - if(0 >= LOGMSG_MAX_LEN - len) return; - + + va_list ap; va_start(ap, fmt); - len += vsnprintf(buf + len, LOGMSG_MAX_LEN - len, fmt, ap); + vzlog(p_handle->zc, __FILE__, sizeof(__FILE__) - 1, __func__, sizeof(__func__) - 1, __LINE__, level, fmt, ap); va_end(ap); - - if(0 >= LOGMSG_MAX_LEN - len) return; - - len += snprintf(buf + len, LOGMSG_MAX_LEN - len, "\n"); - - - sprintf(tmp_log_file_name, "%s.%04d-%02d-%02d", p_handle->runtime_log_file, - local_time.tm_year + 1900, local_time.tm_mon + 1, - local_time.tm_mday); - -OPEN_LOG_FILE: - if(p_handle->fp == NULL) - { - if(NULL == (fp = fopen(tmp_log_file_name, "a"))) return; - p_handle->fp = fp; - p_handle->flush_log_count = 0; - memcpy(p_handle->cur_log_file, tmp_log_file_name, strlen(tmp_log_file_name)); - } - - if (0 != memcmp(tmp_log_file_name, p_handle->cur_log_file, strlen(tmp_log_file_name))) - { - fclose(p_handle->fp); - p_handle->fp = NULL; - goto OPEN_LOG_FILE; - } - - if (0 > fprintf(p_handle->fp, "%s", buf)) - { - fclose(p_handle->fp); - p_handle->fp = NULL; - } - else - { - p_handle->flush_log_count+=1; - if (p_handle->flush_log_count >= FLUSH_LOG_NUM) - { - fflush(p_handle->fp); - p_handle->flush_log_count = 0; - } - } - - return; + return ; } diff --git a/src/version.map b/src/version.map new file mode 100644 index 0000000..c0a9783 --- /dev/null +++ b/src/version.map @@ -0,0 +1,4 @@ +{ + global: MESA*runtime_log*; + local: *; +}; \ No newline at end of file diff --git a/zlog/CMakeLists.txt b/zlog/CMakeLists.txt new file mode 100644 index 0000000..fd8f607 --- /dev/null +++ b/zlog/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required (VERSION 2.8) + +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +set(CMAKE_MACOSX_RPATH 0) + +add_compile_options(-fPIC) + +# static Library Output +add_library(zlog_static STATIC buf.c category.c category_table.c conf.c event.c format.c level.c level_list.c mdc.c record.c record_table.c rotater.c rule.c spec.c thread.c zc_arraylist.c zc_hashtable.c zc_profile.c zc_util.c zlog.c) +set_target_properties(zlog_static PROPERTIES OUTPUT_NAME zlog) diff --git a/zlog/buf.c b/zlog/buf.c new file mode 100644 index 0000000..662b2eb --- /dev/null +++ b/zlog/buf.c @@ -0,0 +1,649 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include +#include + +#include "zc_defs.h" +#include "buf.h" +/*******************************************************************************/ +/* Author's Note + * This buf.c is base on C99, that is, if buffer size is not enough, + * the return value of vsnprintf(3) is a number tell how many character should + * be output. vsnprintf in glibc 2.1 conforms to C99 , but glibc 2.0 doesn't. + * see manpage of vsnprintf(3) on you platform for more detail. + + * So, what should you do if you want to using zlog on the platform that doesn't + * conform C99? My Answer is, crack zlog with a portable C99-vsnprintf, like this + * http://sourceforge.net/projects/ctrio/ + * http://www.jhweiss.de/software/snprintf.html + * If you can see this note, you can fix it yourself? Aren't you? ^_^ + + * Oh, I put the snprintf in C99 standard here, + * vsnprintf is the same on return value. + + 7.19.6.5 The snprintf function + + Synopsis + + [#1] + + #include + int snprintf(char * restrict s, size_t n, + const char * restrict format, ...); + + Description + + [#2] The snprintf function is equivalent to fprintf, except + that the output is written into an array (specified by + argument s) rather than to a stream. If n is zero, nothing + is written, and s may be a null pointer. Otherwise, output + characters beyond the n-1st are discarded rather than being + written to the array, and a null character is written at the + end of the characters actually written into the array. If + copying takes place between objects that overlap, the + behavior is undefined. + + Returns + + [#3] The snprintf function returns the number of characters + that would have been written had n been sufficiently large, + not counting the terminating null character, or a negative + value if an encoding error occurred. Thus, the null- + terminated output has been completely written if and only if + the returned value is nonnegative and less than n. + */ + +/*******************************************************************************/ +void zlog_buf_profile(zlog_buf_t * a_buf, int flag) +{ + //zc_assert(a_buf,); + zc_profile(flag, "---buf[%p][%ld-%ld][%ld][%s][%p:%ld]---", + a_buf, + a_buf->size_min, a_buf->size_max, + a_buf->size_real, + a_buf->truncate_str, + a_buf->start, a_buf->tail - a_buf->start); + return; +} +/*******************************************************************************/ +void zlog_buf_del(zlog_buf_t * a_buf) +{ + //zc_assert(a_buf,); + if (a_buf->start) free(a_buf->start); + zc_debug("zlog_buf_del[%p]", a_buf); + free(a_buf); + return; +} + +zlog_buf_t *zlog_buf_new(size_t buf_size_min, size_t buf_size_max, const char *truncate_str) +{ + zlog_buf_t *a_buf; + + if (buf_size_min == 0) { + zc_error("buf_size_min == 0, not allowed"); + return NULL; + } + + if (buf_size_max != 0 && buf_size_max < buf_size_min) { + zc_error("buf_size_max[%lu] < buf_size_min[%lu] && buf_size_max != 0", + (unsigned long)buf_size_max, (unsigned long)buf_size_min); + return NULL; + } + + a_buf = calloc(1, sizeof(*a_buf)); + if (!a_buf) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + if (truncate_str) { + if (strlen(truncate_str) > sizeof(a_buf->truncate_str) - 1) { + zc_error("truncate_str[%s] overflow", truncate_str); + goto err; + } else { + strcpy(a_buf->truncate_str, truncate_str); + } + a_buf->truncate_str_len = strlen(truncate_str); + } + + a_buf->size_min = buf_size_min; + a_buf->size_max = buf_size_max; + a_buf->size_real = a_buf->size_min; + + a_buf->start = calloc(1, a_buf->size_real); + if (!a_buf->start) { + zc_error("calloc fail, errno[%d]", errno); + goto err; + } + + a_buf->tail = a_buf->start; + a_buf->end_plus_1 = a_buf->start + a_buf->size_real; + a_buf->end = a_buf->end_plus_1 - 1; + + //zlog_buf_profile(a_buf, ZC_DEBUG); + return a_buf; + +err: + zlog_buf_del(a_buf); + return NULL; +} + +/*******************************************************************************/ +static void zlog_buf_truncate(zlog_buf_t * a_buf) +{ + char *p; + size_t len; + + if ((a_buf->truncate_str)[0] == '\0') return; + p = (a_buf->tail - a_buf->truncate_str_len); + if (p < a_buf->start) p = a_buf->start; + len = a_buf->tail - p; + memcpy(p, a_buf->truncate_str, len); + return; +} + +/*******************************************************************************/ +/* return 0: success + * return <0: fail, set size_real to -1; + * return >0: by conf limit, can't extend size + * increment must > 0 + */ +static int zlog_buf_resize(zlog_buf_t * a_buf, size_t increment) +{ + int rc = 0; + size_t new_size = 0; + size_t len = 0; + char *p = NULL; + + if (a_buf->size_max != 0 && a_buf->size_real >= a_buf->size_max) { + zc_error("a_buf->size_real[%ld] >= a_buf->size_max[%ld]", + a_buf->size_real, a_buf->size_max); + return 1; + } + + if (a_buf->size_max == 0) { + /* unlimit */ + new_size = a_buf->size_real + 1.5 * increment; + } else { + /* limited */ + if (a_buf->size_real + increment <= a_buf->size_max) { + new_size = a_buf->size_real + increment; + } else { + new_size = a_buf->size_max; + rc = 1; + } + } + + len = a_buf->tail - a_buf->start; + p = realloc(a_buf->start, new_size); + if (!p) { + zc_error("realloc fail, errno[%d]", errno); + free(a_buf->start); + a_buf->start = NULL; + a_buf->tail = NULL; + a_buf->end = NULL; + a_buf->end_plus_1 = NULL; + return -1; + } else { + a_buf->start = p; + a_buf->tail = p + len; + a_buf->size_real = new_size; + a_buf->end_plus_1 = a_buf->start + new_size; + a_buf->end = a_buf->end_plus_1 - 1; + } + + return rc; +} + +int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args) +{ + va_list ap; + size_t size_left; + int nwrite; + + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } + + va_copy(ap, args); + size_left = a_buf->end_plus_1 - a_buf->tail; + nwrite = vsnprintf(a_buf->tail, size_left, format, ap); + if (nwrite >= 0 && nwrite < size_left) { + a_buf->tail += nwrite; + //*(a_buf->tail) = '\0'; + return 0; + } else if (nwrite < 0) { + zc_error("vsnprintf fail, errno[%d]", errno); + zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format); + return -1; + } else if (nwrite >= size_left) { + int rc; + //zc_debug("nwrite[%d]>=size_left[%ld],format[%s],resize", nwrite, size_left, format); + rc = zlog_buf_resize(a_buf, nwrite - size_left + 1); + if (rc > 0) { + zc_error("conf limit to %ld, can't extend, so truncate", a_buf->size_max); + va_copy(ap, args); + size_left = a_buf->end_plus_1 - a_buf->tail; + vsnprintf(a_buf->tail, size_left, format, ap); + a_buf->tail += size_left - 1; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + + va_copy(ap, args); + size_left = a_buf->end_plus_1 - a_buf->tail; + nwrite = vsnprintf(a_buf->tail, size_left, format, ap); + if (nwrite < 0) { + zc_error("vsnprintf fail, errno[%d]", errno); + zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format); + return -1; + } else { + a_buf->tail += nwrite; + //*(a_buf->tail) = '\0'; + return 0; + } + } + } + + return 0; +} + +/*******************************************************************************/ +/* if width > num_len, 0 padding, else output num */ +int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width) +{ + unsigned char *p; + char *q; + unsigned char tmp[ZLOG_INT32_LEN + 1]; + size_t num_len, zero_len, out_len; + + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } + + p = tmp + ZLOG_INT32_LEN; + do { + *--p = (unsigned char) (ui32 % 10 + '0'); + } while (ui32 /= 10); + + /* zero or space padding */ + num_len = (tmp + ZLOG_INT32_LEN) - p; + + if (width > num_len) { + zero_len = width - num_len; + out_len = width; + } else { + zero_len = 0; + out_len = num_len; + } + + if ((q = a_buf->tail + out_len) > a_buf->end) { + int rc; + //zc_debug("size_left not enough, resize"); + rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail)); + if (rc > 0) { + size_t len_left; + zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max); + len_left = a_buf->end - a_buf->tail; + if (len_left <= zero_len) { + zero_len = len_left; + num_len = 0; + } else if (len_left > zero_len) { + /* zero_len not changed */ + num_len = len_left - zero_len; + } + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail += len_left; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + q = a_buf->tail + out_len; /* re-calculate p*/ + } + } + + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail = q; + //*(a_buf->tail) = '\0'; + return 0; +} +/*******************************************************************************/ +int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width) +{ + unsigned char *p; + char *q; + unsigned char tmp[ZLOG_INT64_LEN + 1]; + size_t num_len, zero_len, out_len; + uint32_t ui32; + + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } + + p = tmp + ZLOG_INT64_LEN; + if (ui64 <= ZLOG_MAX_UINT32_VALUE) { + /* + * To divide 64-bit numbers and to find remainders + * on the x86 platform gcc and icc call the libc functions + * [u]divdi3() and [u]moddi3(), they call another function + * in its turn. On FreeBSD it is the qdivrem() function, + * its source code is about 170 lines of the code. + * The glibc counterpart is about 150 lines of the code. + * + * For 32-bit numbers and some divisors gcc and icc use + * a inlined multiplication and shifts. For example, + * unsigned "i32 / 10" is compiled to + * + * (i32 * 0xCCCCCCCD) >> 35 + */ + + ui32 = (uint32_t) ui64; + + do { + *--p = (unsigned char) (ui32 % 10 + '0'); + } while (ui32 /= 10); + + } else { + do { + *--p = (unsigned char) (ui64 % 10 + '0'); + } while (ui64 /= 10); + } + + + /* zero or space padding */ + num_len = (tmp + ZLOG_INT64_LEN) - p; + + if (width > num_len) { + zero_len = width - num_len; + out_len = width; + } else { + zero_len = 0; + out_len = num_len; + } + + if ((q = a_buf->tail + out_len) > a_buf->end) { + int rc; + //zc_debug("size_left not enough, resize"); + rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail)); + if (rc > 0) { + size_t len_left; + zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max); + len_left = a_buf->end - a_buf->tail; + if (len_left <= zero_len) { + zero_len = len_left; + num_len = 0; + } else if (len_left > zero_len) { + /* zero_len not changed */ + num_len = len_left - zero_len; + } + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail += len_left; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + q = a_buf->tail + out_len; /* re-calculate p*/ + } + } + + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail = q; + //*(a_buf->tail) = '\0'; + return 0; +} +/*******************************************************************************/ +int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width) +{ + unsigned char *p; + char *q; + unsigned char tmp[ZLOG_INT32_LEN + 1]; + size_t num_len, zero_len, out_len; + static unsigned char hex[] = "0123456789abcdef"; + //static unsigned char HEX[] = "0123456789ABCDEF"; + + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } + + + p = tmp + ZLOG_INT32_LEN; + do { + /* the "(uint32_t)" cast disables the BCC's warning */ + *--p = hex[(uint32_t) (ui32 & 0xf)]; + } while (ui32 >>= 4); + +#if 0 + } else { /* is_hex == 2 */ + + do { + /* the "(uint32_t)" cast disables the BCC's warning */ + *--p = HEX[(uint32_t) (ui64 & 0xf)]; + + } while (ui64 >>= 4); + } +#endif + + /* zero or space padding */ + num_len = (tmp + ZLOG_INT32_LEN) - p; + + if (width > num_len) { + zero_len = width - num_len; + out_len = width; + } else { + zero_len = 0; + out_len = num_len; + } + + if ((q = a_buf->tail + out_len) > a_buf->end) { + int rc; + //zc_debug("size_left not enough, resize"); + rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail)); + if (rc > 0) { + size_t len_left; + zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max); + len_left = a_buf->end - a_buf->tail; + if (len_left <= zero_len) { + zero_len = len_left; + num_len = 0; + } else if (len_left > zero_len) { + /* zero_len not changed */ + num_len = len_left - zero_len; + } + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail += len_left; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + q = a_buf->tail + out_len; /* re-calculate p*/ + } + } + + if (zero_len) memset(a_buf->tail, '0', zero_len); + memcpy(a_buf->tail + zero_len, p, num_len); + a_buf->tail = q; + //*(a_buf->tail) = '\0'; + return 0; +} + +/*******************************************************************************/ +int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len) +{ + char *p; +#if 0 + if (str_len <= 0 || str == NULL) { + return 0; + } + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } +#endif + + if ((p = a_buf->tail + str_len) > a_buf->end) { + int rc; + //zc_debug("size_left not enough, resize"); + rc = zlog_buf_resize(a_buf, str_len - (a_buf->end - a_buf->tail)); + if (rc > 0) { + size_t len_left; + zc_error("conf limit to %ld, can't extend, so output", + a_buf->size_max); + len_left = a_buf->end - a_buf->tail; + memcpy(a_buf->tail, str, len_left); + a_buf->tail += len_left; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + p = a_buf->tail + str_len; /* re-calculate p*/ + } + } + + memcpy(a_buf->tail, str, str_len); + a_buf->tail = p; + // *(a_buf->tail) = '\0'; + return 0; +} + +/*******************************************************************************/ +int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len, + int left_adjust, int zero_pad, size_t in_width, size_t out_width) +{ + size_t append_len = 0; + size_t source_len = 0; + size_t space_len = 0; + +#if 0 + if (str_len <= 0 || str == NULL) { + return 0; + } +#endif + + if (!a_buf->start) { + zc_error("pre-use of zlog_buf_resize fail, so can't convert"); + return -1; + } + + /* calculate how many character will be got from str */ + if (out_width == 0 || str_len < out_width) { + source_len = str_len; + } else { + source_len = out_width; + } + + /* calculate how many character will be output */ + if (in_width == 0 || source_len >= in_width ) { + append_len = source_len; + space_len = 0; + } else { + append_len = in_width; + space_len = in_width - source_len; + } + + /* |-----append_len-----------| */ + /* |-source_len---|-space_len-| left_adjust */ + /* |-space_len---|-source_len-| right_adjust */ + /* |-(size_real-1)---| size not enough */ + + if (append_len > a_buf->end - a_buf->tail) { + int rc = 0; + //zc_debug("size_left not enough, resize"); + rc = zlog_buf_resize(a_buf, append_len - (a_buf->end -a_buf->tail)); + if (rc > 0) { + zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max); + append_len = (a_buf->end - a_buf->tail); + if (left_adjust) { + if (source_len < append_len) { + space_len = append_len - source_len; + } else { + source_len = append_len; + space_len = 0; + } + if (space_len) memset(a_buf->tail + source_len, ' ', space_len); + memcpy(a_buf->tail, str, source_len); + } else { + if (space_len < append_len) { + source_len = append_len - space_len; + } else { + space_len = append_len; + source_len = 0; + } + if (space_len) { + if (zero_pad) { + memset(a_buf->tail, '0', space_len); + } else { + memset(a_buf->tail, ' ', space_len); + } + } + memcpy(a_buf->tail + space_len, str, source_len); + } + a_buf->tail += append_len; + //*(a_buf->tail) = '\0'; + zlog_buf_truncate(a_buf); + return 1; + } else if (rc < 0) { + zc_error("zlog_buf_resize fail"); + return -1; + } else { + //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real); + } + } + + if (left_adjust) { + if (space_len) memset(a_buf->tail + source_len, ' ', space_len); + memcpy(a_buf->tail, str, source_len); + } else { + if (space_len) { + if (zero_pad) { + memset(a_buf->tail, '0', space_len); + } else { + memset(a_buf->tail, ' ', space_len); + } + } + memcpy(a_buf->tail + space_len, str, source_len); + } + a_buf->tail += append_len; + //*(a_buf->tail) = '\0'; + return 0; +} +/*******************************************************************************/ + diff --git a/zlog/buf.h b/zlog/buf.h new file mode 100644 index 0000000..ffa720e --- /dev/null +++ b/zlog/buf.h @@ -0,0 +1,56 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_buf_h +#define __zlog_buf_h + +/* buf, is a dynamic expand buffer for one single log, + * as one single log will interlace if use multiple write() to file. + * and buf is always keep in a thread, to make each thread has its + * own buffer to avoid lock. + */ + +#include +#include + +typedef struct zlog_buf_s { + char *start; + char *tail; + char *end; + char *end_plus_1; + + size_t size_min; + size_t size_max; + size_t size_real; + + char truncate_str[MAXLEN_PATH + 1]; + size_t truncate_str_len; +} zlog_buf_t; + + +zlog_buf_t *zlog_buf_new(size_t min, size_t max, const char *truncate_str); +void zlog_buf_del(zlog_buf_t * a_buf); +void zlog_buf_profile(zlog_buf_t * a_buf, int flag); + +int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args); +int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len); +int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len, + int left_adjust, int zero_pad, size_t in_width, size_t out_width); +int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width); +int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width); +int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width); + +#define zlog_buf_restart(a_buf) do { \ + a_buf->tail = a_buf->start; \ +} while(0) + +#define zlog_buf_len(a_buf) (a_buf->tail - a_buf->start) +#define zlog_buf_str(a_buf) (a_buf->start) +#define zlog_buf_seal(a_buf) do {*(a_buf)->tail = '\0';} while (0) + +#endif diff --git a/zlog/category.c b/zlog/category.c new file mode 100644 index 0000000..8a91c3b --- /dev/null +++ b/zlog/category.c @@ -0,0 +1,233 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ +#include "fmacros.h" +#include +#include +#include + +#include "category.h" +#include "rule.h" +#include "zc_defs.h" + +void zlog_category_profile(zlog_category_t *a_category, int flag) +{ + int i; + zlog_rule_t *a_rule; + + zc_assert(a_category,); + zc_profile(flag, "--category[%p][%s][%p]--", + a_category, + a_category->name, + a_category->fit_rules); + if (a_category->fit_rules) { + zc_arraylist_foreach(a_category->fit_rules, i, a_rule) { + zlog_rule_profile(a_rule, flag); + } + } + return; +} + +/*******************************************************************************/ +void zlog_category_del(zlog_category_t * a_category) +{ + zc_assert(a_category,); + if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules); + zc_debug("zlog_category_del[%p]", a_category); + free(a_category); + return; +} + +/* overlap one rule's level bitmap to cateogry, + * so category can judge whether a log level will be output by itself + * It is safe when configure is reloaded, when rule will be released an recreated + */ +static void zlog_cateogry_overlap_bitmap(zlog_category_t * a_category, zlog_rule_t *a_rule) +{ + int i; + for(i = 0; i < sizeof(a_rule->level_bitmap); i++) { + a_category->level_bitmap[i] |= a_rule->level_bitmap[i]; + } +} + +static int zlog_category_obtain_rules(zlog_category_t * a_category, zc_arraylist_t * rules) +{ + int i; + int count = 0; + int fit = 0; + zlog_rule_t *a_rule; + zlog_rule_t *wastebin_rule = NULL; + + /* before set, clean last fit rules first */ + if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules); + + memset(a_category->level_bitmap, 0x00, sizeof(a_category->level_bitmap)); + + a_category->fit_rules = zc_arraylist_new(NULL); + if (!(a_category->fit_rules)) { + zc_error("zc_arraylist_new fail"); + return -1; + } + + /* get match rules from all rules */ + zc_arraylist_foreach(rules, i, a_rule) { + fit = zlog_rule_match_category(a_rule, a_category->name); + if (fit) { + if (zc_arraylist_add(a_category->fit_rules, a_rule)) { + zc_error("zc_arrylist_add fail"); + goto err; + } + zlog_cateogry_overlap_bitmap(a_category, a_rule); + count++; + } + + if (zlog_rule_is_wastebin(a_rule)) { + wastebin_rule = a_rule; + } + } + + if (count == 0) { + if (wastebin_rule) { + zc_debug("category[%s], no match rules, use wastebin_rule", a_category->name); + if (zc_arraylist_add(a_category->fit_rules, wastebin_rule)) { + zc_error("zc_arrylist_add fail"); + goto err; + } + zlog_cateogry_overlap_bitmap(a_category, wastebin_rule); + count++; + } else { + zc_debug("category[%s], no match rules & no wastebin_rule", a_category->name); + } + } + + return 0; +err: + zc_arraylist_del(a_category->fit_rules); + a_category->fit_rules = NULL; + return -1; +} + +zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules) +{ + size_t len; + zlog_category_t *a_category; + + zc_assert(name, NULL); + zc_assert(rules, NULL); + + len = strlen(name); + if (len > sizeof(a_category->name) - 1) { + zc_error("name[%s] too long", name); + return NULL; + } + a_category = calloc(1, sizeof(zlog_category_t)); + if (!a_category) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + strcpy(a_category->name, name); + a_category->name_len = len; + if (zlog_category_obtain_rules(a_category, rules)) { + zc_error("zlog_category_fit_rules fail"); + goto err; + } + + zlog_category_profile(a_category, ZC_DEBUG); + return a_category; +err: + zlog_category_del(a_category); + return NULL; +} +/*******************************************************************************/ +/* update success: fit_rules 1, fit_rules_backup 1 */ +/* update fail: fit_rules 0, fit_rules_backup 1 */ +int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules) +{ + zc_assert(a_category, -1); + zc_assert(new_rules, -1); + + /* 1st, mv fit_rules fit_rules_backup */ + if (a_category->fit_rules_backup) zc_arraylist_del(a_category->fit_rules_backup); + a_category->fit_rules_backup = a_category->fit_rules; + a_category->fit_rules = NULL; + + memcpy(a_category->level_bitmap_backup, a_category->level_bitmap, + sizeof(a_category->level_bitmap)); + + /* 2nd, obtain new_rules to fit_rules */ + if (zlog_category_obtain_rules(a_category, new_rules)) { + zc_error("zlog_category_obtain_rules fail"); + a_category->fit_rules = NULL; + return -1; + } + + /* keep the fit_rules_backup not change, return */ + return 0; +} + +/* commit fail: fit_rules_backup != 0 */ +/* commit success: fit_rules 1, fit_rules_backup 0 */ +void zlog_category_commit_rules(zlog_category_t * a_category) +{ + zc_assert(a_category,); + if (!a_category->fit_rules_backup) { + zc_warn("a_category->fit_rules_backup is NULL, never update before"); + return; + } + + zc_arraylist_del(a_category->fit_rules_backup); + a_category->fit_rules_backup = NULL; + memset(a_category->level_bitmap_backup, 0x00, + sizeof(a_category->level_bitmap_backup)); + return; +} + +/* rollback fail: fit_rules_backup != 0 */ +/* rollback success: fit_rules 1, fit_rules_backup 0 */ +/* so whether update succes or not, make things back to old */ +void zlog_category_rollback_rules(zlog_category_t * a_category) +{ + zc_assert(a_category,); + if (!a_category->fit_rules_backup) { + zc_warn("a_category->fit_rules_backup in NULL, never update before"); + return; + } + + if (a_category->fit_rules) { + /* update success, rm new and backup */ + zc_arraylist_del(a_category->fit_rules); + a_category->fit_rules = a_category->fit_rules_backup; + a_category->fit_rules_backup = NULL; + } else { + /* update fail, just backup */ + a_category->fit_rules = a_category->fit_rules_backup; + a_category->fit_rules_backup = NULL; + } + + memcpy(a_category->level_bitmap, a_category->level_bitmap_backup, + sizeof(a_category->level_bitmap)); + memset(a_category->level_bitmap_backup, 0x00, + sizeof(a_category->level_bitmap_backup)); + + return; /* always success */ +} + +/*******************************************************************************/ + +int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread) +{ + int i; + int rc = 0; + zlog_rule_t *a_rule; + + /* go through all match rules to output */ + zc_arraylist_foreach(a_category->fit_rules, i, a_rule) { + rc = zlog_rule_output(a_rule, a_thread); + } + + return rc; +} diff --git a/zlog/category.h b/zlog/category.h new file mode 100644 index 0000000..c86c6d9 --- /dev/null +++ b/zlog/category.h @@ -0,0 +1,38 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_category_h +#define __zlog_category_h + +#include "zc_defs.h" +#include "thread.h" + +typedef struct zlog_category_s { + char name[MAXLEN_PATH + 1]; + size_t name_len; + unsigned char level_bitmap[32]; + unsigned char level_bitmap_backup[32]; + zc_arraylist_t *fit_rules; + zc_arraylist_t *fit_rules_backup; +} zlog_category_t; + +zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules); +void zlog_category_del(zlog_category_t * a_category); +void zlog_category_profile(zlog_category_t *a_category, int flag); + +int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules); +void zlog_category_commit_rules(zlog_category_t * a_category); +void zlog_category_rollback_rules(zlog_category_t * a_category); + +int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread); + +#define zlog_category_needless_level(a_category, lv) \ + !((a_category->level_bitmap[lv/8] >> (7 - lv % 8)) & 0x01) + + +#endif diff --git a/zlog/category_table.c b/zlog/category_table.c new file mode 100644 index 0000000..9e2975b --- /dev/null +++ b/zlog/category_table.c @@ -0,0 +1,129 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include + +#include "zc_defs.h" +#include "category_table.h" + +void zlog_category_table_profile(zc_hashtable_t * categories, int flag) +{ + zc_hashtable_entry_t *a_entry; + zlog_category_t *a_category; + + zc_assert(categories,); + zc_profile(flag, "-category_table[%p]-", categories); + zc_hashtable_foreach(categories, a_entry) { + a_category = (zlog_category_t *) a_entry->value; + zlog_category_profile(a_category, flag); + } + return; +} + +/*******************************************************************************/ + +void zlog_category_table_del(zc_hashtable_t * categories) +{ + zc_assert(categories,); + zc_hashtable_del(categories); + zc_debug("zlog_category_table_del[%p]", categories); + return; +} + +zc_hashtable_t *zlog_category_table_new(void) +{ + zc_hashtable_t *categories; + + categories = zc_hashtable_new(20, + (zc_hashtable_hash_fn) zc_hashtable_str_hash, + (zc_hashtable_equal_fn) zc_hashtable_str_equal, + NULL, (zc_hashtable_del_fn) zlog_category_del); + if (!categories) { + zc_error("zc_hashtable_new fail"); + return NULL; + } else { + zlog_category_table_profile(categories, ZC_DEBUG); + return categories; + } +} +/*******************************************************************************/ +int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules) +{ + zc_hashtable_entry_t *a_entry; + zlog_category_t *a_category; + + zc_assert(categories, -1); + zc_hashtable_foreach(categories, a_entry) { + a_category = (zlog_category_t *) a_entry->value; + if (zlog_category_update_rules(a_category, new_rules)) { + zc_error("zlog_category_update_rules fail, try rollback"); + return -1; + } + } + return 0; +} + +void zlog_category_table_commit_rules(zc_hashtable_t * categories) +{ + zc_hashtable_entry_t *a_entry; + zlog_category_t *a_category; + + zc_assert(categories,); + zc_hashtable_foreach(categories, a_entry) { + a_category = (zlog_category_t *) a_entry->value; + zlog_category_commit_rules(a_category); + } + return; +} + +void zlog_category_table_rollback_rules(zc_hashtable_t * categories) +{ + zc_hashtable_entry_t *a_entry; + zlog_category_t *a_category; + + zc_assert(categories,); + zc_hashtable_foreach(categories, a_entry) { + a_category = (zlog_category_t *) a_entry->value; + zlog_category_rollback_rules(a_category); + } + return; +} + +/*******************************************************************************/ +zlog_category_t *zlog_category_table_fetch_category(zc_hashtable_t * categories, + const char *category_name, zc_arraylist_t * rules) +{ + zlog_category_t *a_category; + + zc_assert(categories, NULL); + + /* 1st find category in global category map */ + a_category = zc_hashtable_get(categories, category_name); + if (a_category) return a_category; + + /* else not found, create one */ + a_category = zlog_category_new(category_name, rules); + if (!a_category) { + zc_error("zc_category_new fail"); + return NULL; + } + + if(zc_hashtable_put(categories, a_category->name, a_category)) { + zc_error("zc_hashtable_put fail"); + goto err; + } + + return a_category; +err: + zlog_category_del(a_category); + return NULL; +} + +/*******************************************************************************/ diff --git a/zlog/category_table.h b/zlog/category_table.h new file mode 100644 index 0000000..34a2249 --- /dev/null +++ b/zlog/category_table.h @@ -0,0 +1,28 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_category_table_h +#define __zlog_category_table_h + +#include "zc_defs.h" +#include "category.h" + +zc_hashtable_t *zlog_category_table_new(void); +void zlog_category_table_del(zc_hashtable_t * categories); +void zlog_category_table_profile(zc_hashtable_t * categories, int flag); + +/* if none, create new and return */ +zlog_category_t *zlog_category_table_fetch_category( + zc_hashtable_t * categories, + const char *category_name, zc_arraylist_t * rules); + +int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules); +void zlog_category_table_commit_rules(zc_hashtable_t * categories); +void zlog_category_table_rollback_rules(zc_hashtable_t * categories); + +#endif diff --git a/zlog/conf.c b/zlog/conf.c new file mode 100644 index 0000000..a921984 --- /dev/null +++ b/zlog/conf.c @@ -0,0 +1,504 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conf.h" +#include "rule.h" +#include "format.h" +#include "level_list.h" +#include "rotater.h" +#include "zc_defs.h" + +/*******************************************************************************/ +#define ZLOG_CONF_DEFAULT_FORMAT "default = \"%D %V [%p:%F:%L] %m%n\"" +#define ZLOG_CONF_DEFAULT_RULE "*.* >stdout" +#define ZLOG_CONF_DEFAULT_BUF_SIZE_MIN 1024 +#define ZLOG_CONF_DEFAULT_BUF_SIZE_MAX (2 * 1024 * 1024) +#define ZLOG_CONF_DEFAULT_FILE_PERMS 0600 +#define ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD 0 +#define ZLOG_CONF_DEFAULT_FSYNC_PERIOD 0 +#define ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE "/tmp/zlog.lock" +/*******************************************************************************/ + +void zlog_conf_profile(zlog_conf_t * a_conf, int flag) +{ + int i; + zlog_rule_t *a_rule; + zlog_format_t *a_format; + + zc_assert(a_conf,); + zc_profile(flag, "-conf[%p]-", a_conf); + zc_profile(flag, "--global--"); + zc_profile(flag, "---file[%s],mtime[%s]---", a_conf->file, a_conf->mtime); + zc_profile(flag, "---strict init[%d]---", a_conf->strict_init); + zc_profile(flag, "---buffer min[%ld]---", a_conf->buf_size_min); + zc_profile(flag, "---buffer max[%ld]---", a_conf->buf_size_max); + if (a_conf->default_format) { + zc_profile(flag, "---default_format---"); + zlog_format_profile(a_conf->default_format, flag); + } + zc_profile(flag, "---file perms[0%o]---", a_conf->file_perms); + zc_profile(flag, "---reload conf period[%ld]---", a_conf->reload_conf_period); + zc_profile(flag, "---fsync period[%ld]---", a_conf->fsync_period); + + zc_profile(flag, "---rotate lock file[%s]---", a_conf->rotate_lock_file); + if (a_conf->rotater) zlog_rotater_profile(a_conf->rotater, flag); + + if (a_conf->levels) zlog_level_list_profile(a_conf->levels, flag); + + if (a_conf->formats) { + zc_profile(flag, "--format list[%p]--", a_conf->formats); + zc_arraylist_foreach(a_conf->formats, i, a_format) { + zlog_format_profile(a_format, flag); + } + } + + if (a_conf->rules) { + zc_profile(flag, "--rule_list[%p]--", a_conf->rules); + zc_arraylist_foreach(a_conf->rules, i, a_rule) { + zlog_rule_profile(a_rule, flag); + } + } + + return; +} +/*******************************************************************************/ +void zlog_conf_del(zlog_conf_t * a_conf) +{ + zc_assert(a_conf,); + if (a_conf->rotater) zlog_rotater_del(a_conf->rotater); + if (a_conf->levels) zlog_level_list_del(a_conf->levels); + if (a_conf->default_format) zlog_format_del(a_conf->default_format); + if (a_conf->formats) zc_arraylist_del(a_conf->formats); + if (a_conf->rules) zc_arraylist_del(a_conf->rules); + free(a_conf); + zc_debug("zlog_conf_del[%p]"); + return; +} + +static int zlog_conf_build_without_file(zlog_conf_t * a_conf); +static int zlog_conf_build_with_file(zlog_conf_t * a_conf); + +zlog_conf_t *zlog_conf_new(const char *confpath) +{ + int nwrite = 0; + int has_conf_file = 0; + zlog_conf_t *a_conf = NULL; + + a_conf = calloc(1, sizeof(zlog_conf_t)); + if (!a_conf) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + if (confpath && confpath[0] != '\0') { + nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", confpath); + has_conf_file = 1; + } else if (getenv("ZLOG_CONF_PATH") != NULL) { + nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", getenv("ZLOG_CONF_PATH")); + has_conf_file = 1; + } else { + memset(a_conf->file, 0x00, sizeof(a_conf->file)); + has_conf_file = 0; + } + if (nwrite < 0 || nwrite >= sizeof(a_conf->file)) { + zc_error("not enough space for path name, nwrite=[%d], errno[%d]", nwrite, errno); + goto err; + } + + /* set default configuration start */ + a_conf->strict_init = 1; + a_conf->buf_size_min = ZLOG_CONF_DEFAULT_BUF_SIZE_MIN; + a_conf->buf_size_max = ZLOG_CONF_DEFAULT_BUF_SIZE_MAX; + if (has_conf_file) { + /* configure file as default lock file */ + strcpy(a_conf->rotate_lock_file, a_conf->file); + } else { + strcpy(a_conf->rotate_lock_file, ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE); + } + strcpy(a_conf->default_format_line, ZLOG_CONF_DEFAULT_FORMAT); + a_conf->file_perms = ZLOG_CONF_DEFAULT_FILE_PERMS; + a_conf->reload_conf_period = ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD; + a_conf->fsync_period = ZLOG_CONF_DEFAULT_FSYNC_PERIOD; + /* set default configuration end */ + + a_conf->levels = zlog_level_list_new(); + if (!a_conf->levels) { + zc_error("zlog_level_list_new fail"); + goto err; + } + + a_conf->formats = zc_arraylist_new((zc_arraylist_del_fn) zlog_format_del); + if (!a_conf->formats) { + zc_error("zc_arraylist_new fail"); + goto err; + } + + a_conf->rules = zc_arraylist_new((zc_arraylist_del_fn) zlog_rule_del); + if (!a_conf->rules) { + zc_error("init rule_list fail"); + goto err; + } + + if (has_conf_file) { + if (zlog_conf_build_with_file(a_conf)) { + zc_error("zlog_conf_build_with_file fail"); + goto err; + } + } else { + if (zlog_conf_build_without_file(a_conf)) { + zc_error("zlog_conf_build_without_file fail"); + goto err; + } + } + + zlog_conf_profile(a_conf, ZC_DEBUG); + return a_conf; +err: + zlog_conf_del(a_conf); + return NULL; +} +/*******************************************************************************/ +static int zlog_conf_build_without_file(zlog_conf_t * a_conf) +{ + zlog_rule_t *default_rule; + + a_conf->default_format = zlog_format_new(a_conf->default_format_line, &(a_conf->time_cache_count)); + if (!a_conf->default_format) { + zc_error("zlog_format_new fail"); + return -1; + } + + a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file); + if (!a_conf->rotater) { + zc_error("zlog_rotater_new fail"); + return -1; + } + + default_rule = zlog_rule_new( + ZLOG_CONF_DEFAULT_RULE, + a_conf->levels, + a_conf->default_format, + a_conf->formats, + a_conf->file_perms, + a_conf->fsync_period, + &(a_conf->time_cache_count)); + if (!default_rule) { + zc_error("zlog_rule_new fail"); + return -1; + } + + /* add default rule */ + if (zc_arraylist_add(a_conf->rules, default_rule)) { + zlog_rule_del(default_rule); + zc_error("zc_arraylist_add fail"); + return -1; + } + + return 0; +} +/*******************************************************************************/ +static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section); + +static int zlog_conf_build_with_file(zlog_conf_t * a_conf) +{ + int rc = 0; + struct zlog_stat a_stat; + struct tm local_time; + FILE *fp = NULL; + + char line[MAXLEN_CFG_LINE + 1]; + size_t line_len; + char *pline = NULL; + char *p = NULL; + int line_no = 0; + int i = 0; + int in_quotation = 0; + + int section = 0; + /* [global:1] [levels:2] [formats:3] [rules:4] */ + + if (lstat(a_conf->file, &a_stat)) { + zc_error("lstat conf file[%s] fail, errno[%d]", a_conf->file, + errno); + return -1; + } + localtime_r(&(a_stat.st_mtime), &local_time); + strftime(a_conf->mtime, sizeof(a_conf->mtime), "%F %T", &local_time); + + if ((fp = fopen(a_conf->file, "r")) == NULL) { + zc_error("open configure file[%s] fail", a_conf->file); + return -1; + } + + /* Now process the file. + */ + pline = line; + memset(&line, 0x00, sizeof(line)); + while (fgets((char *)pline, sizeof(line) - (pline - line), fp) != NULL) { + ++line_no; + line_len = strlen(pline); + if (pline[line_len - 1] == '\n') { + pline[line_len - 1] = '\0'; + } + + /* check for end-of-section, comments, strip off trailing + * spaces and newline character. + */ + p = pline; + while (*p && isspace((int)*p)) + ++p; + if (*p == '\0' || *p == '#') + continue; + + for (i = 0; p[i] != '\0'; ++i) { + pline[i] = p[i]; + } + pline[i] = '\0'; + + for (p = pline + strlen(pline) - 1; isspace((int)*p); --p) + /*EMPTY*/; + + if (*p == '\\') { + if ((p - line) > MAXLEN_CFG_LINE - 30) { + /* Oops the buffer is full - what now? */ + pline = line; + } else { + for (p--; isspace((int)*p); --p) + /*EMPTY*/; + p++; + *p = 0; + pline = p; + continue; + } + } else + pline = line; + + *++p = '\0'; + + /* clean the tail comments start from # and not in quotation */ + in_quotation = 0; + for (p = line; *p != '\0'; p++) { + if (*p == '"') { + in_quotation ^= 1; + continue; + } + + if (*p == '#' && !in_quotation) { + *p = '\0'; + break; + } + } + + /* we now have the complete line, + * and are positioned at the first non-whitespace + * character. So let's process it + */ + rc = zlog_conf_parse_line(a_conf, line, §ion); + if (rc < 0) { + zc_error("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no); + zc_error("line[%s]", line); + goto exit; + } else if (rc > 0) { + zc_warn("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no); + zc_warn("line[%s]", line); + zc_warn("as strict init is set to false, ignore and go on"); + rc = 0; + continue; + } + } + +exit: + fclose(fp); + return rc; +} + +/* section [global:1] [levels:2] [formats:3] [rules:4] */ +static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section) +{ + int nscan; + int nread; + char name[MAXLEN_CFG_LINE + 1]; + char word_1[MAXLEN_CFG_LINE + 1]; + char word_2[MAXLEN_CFG_LINE + 1]; + char word_3[MAXLEN_CFG_LINE + 1]; + char value[MAXLEN_CFG_LINE + 1]; + zlog_format_t *a_format = NULL; + zlog_rule_t *a_rule = NULL; + + if (strlen(line) > MAXLEN_CFG_LINE) { + zc_error ("line_len[%ld] > MAXLEN_CFG_LINE[%ld], may cause overflow", + strlen(line), MAXLEN_CFG_LINE); + return -1; + } + + /* get and set outer section flag, so it is a closure? haha */ + if (line[0] == '[') { + int last_section = *section; + nscan = sscanf(line, "[ %[^] \t]", name); + if (STRCMP(name, ==, "global")) { + *section = 1; + } else if (STRCMP(name, ==, "levels")) { + *section = 2; + } else if (STRCMP(name, ==, "formats")) { + *section = 3; + } else if (STRCMP(name, ==, "rules")) { + *section = 4; + } else { + zc_error("wrong section name[%s]", name); + return -1; + } + /* check the sequence of section, must increase */ + if (last_section >= *section) { + zc_error("wrong sequence of section, must follow global->levels->formats->rules"); + return -1; + } + + if (*section == 4) { + if (a_conf->reload_conf_period != 0 + && a_conf->fsync_period >= a_conf->reload_conf_period) { + /* as all rule will be rebuilt when conf is reload, + * so fsync_period > reload_conf_period will never + * cause rule to fsync it's file. + * fsync_period will be meaningless and down speed, + * so make it zero. + */ + zc_warn("fsync_period[%ld] >= reload_conf_period[%ld]," + "set fsync_period to zero"); + a_conf->fsync_period = 0; + } + + /* now build rotater and default_format + * from the unchanging global setting, + * for zlog_rule_new() */ + a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file); + if (!a_conf->rotater) { + zc_error("zlog_rotater_new fail"); + return -1; + } + + a_conf->default_format = zlog_format_new(a_conf->default_format_line, + &(a_conf->time_cache_count)); + if (!a_conf->default_format) { + zc_error("zlog_format_new fail"); + return -1; + } + } + return 0; + } + + /* process detail */ + switch (*section) { + case 1: + memset(name, 0x00, sizeof(name)); + memset(value, 0x00, sizeof(value)); + nscan = sscanf(line, " %[^=]= %s ", name, value); + if (nscan != 2) { + zc_error("sscanf [%s] fail, name or value is null", line); + return -1; + } + + memset(word_1, 0x00, sizeof(word_1)); + memset(word_2, 0x00, sizeof(word_2)); + memset(word_3, 0x00, sizeof(word_3)); + nread = 0; + nscan = sscanf(name, "%s%n%s%s", word_1, &nread, word_2, word_3); + + if (STRCMP(word_1, ==, "strict") && STRCMP(word_2, ==, "init")) { + /* if environment variable ZLOG_STRICT_INIT is set + * then always make it strict + */ + if (STRICMP(value, ==, "false") && !getenv("ZLOG_STRICT_INIT")) { + a_conf->strict_init = 0; + } else { + a_conf->strict_init = 1; + } + } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "min")) { + a_conf->buf_size_min = zc_parse_byte_size(value); + } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "max")) { + a_conf->buf_size_max = zc_parse_byte_size(value); + } else if (STRCMP(word_1, ==, "file") && STRCMP(word_2, ==, "perms")) { + sscanf(value, "%o", &(a_conf->file_perms)); + } else if (STRCMP(word_1, ==, "rotate") && + STRCMP(word_2, ==, "lock") && STRCMP(word_3, ==, "file")) { + /* may overwrite the inner default value, or last value */ + if (STRCMP(value, ==, "self")) { + strcpy(a_conf->rotate_lock_file, a_conf->file); + } else { + strcpy(a_conf->rotate_lock_file, value); + } + } else if (STRCMP(word_1, ==, "default") && STRCMP(word_2, ==, "format")) { + /* so the input now is [format = "xxyy"], fit format's style */ + strcpy(a_conf->default_format_line, line + nread); + } else if (STRCMP(word_1, ==, "reload") && + STRCMP(word_2, ==, "conf") && STRCMP(word_3, ==, "period")) { + a_conf->reload_conf_period = zc_parse_byte_size(value); + } else if (STRCMP(word_1, ==, "fsync") && STRCMP(word_2, ==, "period")) { + a_conf->fsync_period = zc_parse_byte_size(value); + } else { + zc_error("name[%s] is not any one of global options", name); + if (a_conf->strict_init) return -1; + } + break; + case 2: + if (zlog_level_list_set(a_conf->levels, line)) { + zc_error("zlog_level_list_set fail"); + if (a_conf->strict_init) return -1; + } + break; + case 3: + a_format = zlog_format_new(line, &(a_conf->time_cache_count)); + if (!a_format) { + zc_error("zlog_format_new fail [%s]", line); + if (a_conf->strict_init) return -1; + else break; + } + if (zc_arraylist_add(a_conf->formats, a_format)) { + zlog_format_del(a_format); + zc_error("zc_arraylist_add fail"); + return -1; + } + break; + case 4: + a_rule = zlog_rule_new(line, + a_conf->levels, + a_conf->default_format, + a_conf->formats, + a_conf->file_perms, + a_conf->fsync_period, + &(a_conf->time_cache_count)); + + if (!a_rule) { + zc_error("zlog_rule_new fail [%s]", line); + if (a_conf->strict_init) return -1; + else break; + } + if (zc_arraylist_add(a_conf->rules, a_rule)) { + zlog_rule_del(a_rule); + zc_error("zc_arraylist_add fail"); + return -1; + } + break; + default: + zc_error("not in any section"); + return -1; + } + + return 0; +} +/*******************************************************************************/ diff --git a/zlog/conf.h b/zlog/conf.h new file mode 100644 index 0000000..39a04e7 --- /dev/null +++ b/zlog/conf.h @@ -0,0 +1,46 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_conf_h +#define __zlog_conf_h + +#include "zc_defs.h" +#include "format.h" +#include "rotater.h" + +typedef struct zlog_conf_s { + char file[MAXLEN_PATH + 1]; + char mtime[20 + 1]; + + int strict_init; + size_t buf_size_min; + size_t buf_size_max; + + char rotate_lock_file[MAXLEN_CFG_LINE + 1]; + zlog_rotater_t *rotater; + + char default_format_line[MAXLEN_CFG_LINE + 1]; + zlog_format_t *default_format; + + unsigned int file_perms; + size_t fsync_period; + size_t reload_conf_period; + + zc_arraylist_t *levels; + zc_arraylist_t *formats; + zc_arraylist_t *rules; + int time_cache_count; +} zlog_conf_t; + +extern zlog_conf_t * zlog_env_conf; + +zlog_conf_t *zlog_conf_new(const char *confpath); +void zlog_conf_del(zlog_conf_t * a_conf); +void zlog_conf_profile(zlog_conf_t * a_conf, int flag); + +#endif diff --git a/zlog/event.c b/zlog/event.c new file mode 100644 index 0000000..b62590f --- /dev/null +++ b/zlog/event.c @@ -0,0 +1,182 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#define _GNU_SOURCE // For distros like Centos for syscall interface + +#include "fmacros.h" +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "zc_defs.h" +#include "event.h" + +void zlog_event_profile(zlog_event_t * a_event, int flag) +{ + zc_assert(a_event,); + zc_profile(flag, "---event[%p][%s,%s][%s(%ld),%s(%ld),%ld,%d][%p,%s][%ld,%ld][%ld,%ld][%d]---", + a_event, + a_event->category_name, a_event->host_name, + a_event->file, a_event->file_len, + a_event->func, a_event->func_len, + a_event->line, a_event->level, + a_event->hex_buf, a_event->str_format, + a_event->time_stamp.tv_sec, a_event->time_stamp.tv_usec, + (long)a_event->pid, (long)a_event->tid, + a_event->time_cache_count); + return; +} + +/*******************************************************************************/ + +void zlog_event_del(zlog_event_t * a_event) +{ + zc_assert(a_event,); + if (a_event->time_caches) free(a_event->time_caches); + zc_debug("zlog_event_del[%p]", a_event); + free(a_event); + return; +} + +zlog_event_t *zlog_event_new(int time_cache_count) +{ + zlog_event_t *a_event; + + a_event = calloc(1, sizeof(zlog_event_t)); + if (!a_event) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_event->time_caches = calloc(time_cache_count, sizeof(zlog_time_cache_t)); + if (!a_event->time_caches) { + zc_error("calloc fail, errno[%d]", errno); + free(a_event); + return NULL; + } + a_event->time_cache_count = time_cache_count; + + /* + * at the zlog_init we gethostname, + * u don't always change your hostname, eh? + */ + if (gethostname(a_event->host_name, sizeof(a_event->host_name) - 1)) { + zc_error("gethostname fail, errno[%d]", errno); + goto err; + } + + a_event->host_name_len = strlen(a_event->host_name); + + /* tid is bound to a_event + * as in whole lifecycle event persists + * even fork to oth pid, tid not change + */ + a_event->tid = pthread_self(); + + a_event->tid_str_len = sprintf(a_event->tid_str, "%lu", (unsigned long)a_event->tid); + a_event->tid_hex_str_len = sprintf(a_event->tid_hex_str, "%x", (unsigned int)a_event->tid); + +#ifdef __linux__ + a_event->ktid = syscall(SYS_gettid); +#elif __APPLE__ + uint64_t tid64; + pthread_threadid_np(NULL, &tid64); + a_event->tid = (pid_t)tid64; +#endif + +#if defined __linux__ || __APPLE__ + a_event->ktid_str_len = sprintf(a_event->ktid_str, "%u", (unsigned int)a_event->ktid); +#endif + + //zlog_event_profile(a_event, ZC_DEBUG); + return a_event; +err: + zlog_event_del(a_event); + return NULL; +} + +/*******************************************************************************/ +void zlog_event_set_fmt(zlog_event_t * a_event, + char *category_name, size_t category_name_len, + const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, + const char *str_format, va_list str_args) +{ + /* + * category_name point to zlog_category_output's category.name + */ + a_event->category_name = category_name; + a_event->category_name_len = category_name_len; + + a_event->file = (char *) file; + a_event->file_len = file_len; + a_event->func = (char *) func; + a_event->func_len = func_len; + a_event->line = line; + a_event->level = level; + + a_event->generate_cmd = ZLOG_FMT; + a_event->str_format = str_format; + va_copy(a_event->str_args, str_args); + + /* pid should fetch eveytime, as no one knows, + * when does user fork his process + * so clean here, and fetch at spec.c + */ + a_event->pid = (pid_t) 0; + + /* in a event's life cycle, time will be get when spec need, + * and keep unchange though all event's life cycle + * zlog_spec_write_time gettimeofday + */ + a_event->time_stamp.tv_sec = 0; + return; +} + +void zlog_event_set_hex(zlog_event_t * a_event, + char *category_name, size_t category_name_len, + const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, + const void *hex_buf, size_t hex_buf_len) +{ + /* + * category_name point to zlog_category_output's category.name + */ + a_event->category_name = category_name; + a_event->category_name_len = category_name_len; + + a_event->file = (char *) file; + a_event->file_len = file_len; + a_event->func = (char *) func; + a_event->func_len = func_len; + a_event->line = line; + a_event->level = level; + + a_event->generate_cmd = ZLOG_HEX; + a_event->hex_buf = hex_buf; + a_event->hex_buf_len = hex_buf_len; + + /* pid should fetch eveytime, as no one knows, + * when does user fork his process + * so clean here, and fetch at spec.c + */ + a_event->pid = (pid_t) 0; + + /* in a event's life cycle, time will be get when spec need, + * and keep unchange though all event's life cycle + */ + a_event->time_stamp.tv_sec = 0; + return; +} diff --git a/zlog/event.h b/zlog/event.h new file mode 100644 index 0000000..a375daa --- /dev/null +++ b/zlog/event.h @@ -0,0 +1,90 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_event_h +#define __zlog_event_h + +#include /* for pid_t */ +#include /* for struct timeval */ +#include /* for pthread_t */ +#include /* for va_list */ +#include "zc_defs.h" + +typedef enum { + ZLOG_FMT = 0, + ZLOG_HEX = 1, +} zlog_event_cmd; + +typedef struct zlog_time_cache_s { + char str[MAXLEN_CFG_LINE + 1]; + size_t len; + time_t sec; +} zlog_time_cache_t; + +typedef struct { + char *category_name; + size_t category_name_len; + char host_name[256 + 1]; + size_t host_name_len; + + const char *file; + size_t file_len; + const char *func; + size_t func_len; + long line; + int level; + + const void *hex_buf; + size_t hex_buf_len; + const char *str_format; + va_list str_args; + zlog_event_cmd generate_cmd; + + struct timeval time_stamp; + + time_t time_local_sec; + struct tm time_local; + + zlog_time_cache_t *time_caches; + int time_cache_count; + + pid_t pid; + pid_t last_pid; + char pid_str[30 + 1]; + size_t pid_str_len; + + pthread_t tid; + char tid_str[30 + 1]; + size_t tid_str_len; + + char tid_hex_str[30 + 1]; + size_t tid_hex_str_len; + +#if defined __linux__ || __APPLE__ + pid_t ktid; + char ktid_str[30+1]; + size_t ktid_str_len; +#endif +} zlog_event_t; + + +zlog_event_t *zlog_event_new(int time_cache_count); +void zlog_event_del(zlog_event_t * a_event); +void zlog_event_profile(zlog_event_t * a_event, int flag); + +void zlog_event_set_fmt(zlog_event_t * a_event, + char *category_name, size_t category_name_len, + const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, + const char *str_format, va_list str_args); + +void zlog_event_set_hex(zlog_event_t * a_event, + char *category_name, size_t category_name_len, + const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, + const void *hex_buf, size_t hex_buf_len); + +#endif diff --git a/zlog/fmacros.h b/zlog/fmacros.h new file mode 100644 index 0000000..b92bae1 --- /dev/null +++ b/zlog/fmacros.h @@ -0,0 +1,24 @@ +#ifndef __zlog_fmacro_h +#define __zlog_fmacro_h + +#define _DEFAULT_SOURCE + +#if defined(__linux__) || defined(__OpenBSD__) || defined(_AIX) +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 +#endif +#ifndef _XOPEN_SOURCE_EXTENDED +#define _XOPEN_SOURCE_EXTENDED +#endif +#else +#define _XOPEN_SOURCE +#endif + +#ifndef _LARGEFILE_SOURCE +#define _LARGEFILE_SOURCE +#endif +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif + +#endif diff --git a/zlog/format.c b/zlog/format.c new file mode 100644 index 0000000..0712ede --- /dev/null +++ b/zlog/format.c @@ -0,0 +1,164 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include +#include +#include + +#include "zc_defs.h" +#include "thread.h" +#include "spec.h" +#include "format.h" + +void zlog_format_profile(zlog_format_t * a_format, int flag) +{ + + zc_assert(a_format,); + zc_profile(flag, "---format[%p][%s = %s(%p)]---", + a_format, + a_format->name, + a_format->pattern, + a_format->pattern_specs); + +#if 0 + int i; + zlog_spec_t *a_spec; + zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) { + zlog_spec_profile(a_spec, flag); + } +#endif + + return; +} + +/*******************************************************************************/ +void zlog_format_del(zlog_format_t * a_format) +{ + zc_assert(a_format,); + if (a_format->pattern_specs) { + zc_arraylist_del(a_format->pattern_specs); + } + zc_debug("zlog_format_del[%p]", a_format); + free(a_format); + return; +} + +zlog_format_t *zlog_format_new(char *line, int * time_cache_count) +{ + int nscan = 0; + zlog_format_t *a_format = NULL; + int nread = 0; + const char *p_start; + const char *p_end; + char *p; + char *q; + zlog_spec_t *a_spec; + + zc_assert(line, NULL); + + a_format = calloc(1, sizeof(zlog_format_t)); + if (!a_format) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + /* line default = "%d(%F %X.%l) %-6V (%c:%F:%L) - %m%n" + * name default + * pattern %d(%F %X.%l) %-6V (%c:%F:%L) - %m%n + */ + memset(a_format->name, 0x00, sizeof(a_format->name)); + nread = 0; + nscan = sscanf(line, " %[^= \t] = %n", a_format->name, &nread); + if (nscan != 1) { + zc_error("format[%s], syntax wrong", line); + goto err; + } + + if (*(line + nread) != '"') { + zc_error("the 1st char of pattern is not \", line+nread[%s]", line+nread); + goto err; + } + + for (p = a_format->name; *p != '\0'; p++) { + if ((!isalnum(*p)) && (*p != '_')) { + zc_error("a_format->name[%s] character is not in [a-Z][0-9][_]", a_format->name); + goto err; + } + } + + p_start = line + nread + 1; + p_end = strrchr(p_start, '"'); + if (!p_end) { + zc_error("there is no \" at end of pattern, line[%s]", line); + goto err; + } + + if (p_end - p_start > sizeof(a_format->pattern) - 1) { + zc_error("pattern is too long"); + goto err; + } + memset(a_format->pattern, 0x00, sizeof(a_format->pattern)); + memcpy(a_format->pattern, p_start, p_end - p_start); + + if (zc_str_replace_env(a_format->pattern, sizeof(a_format->pattern))) { + zc_error("zc_str_replace_env fail"); + goto err; + } + + a_format->pattern_specs = + zc_arraylist_new((zc_arraylist_del_fn) zlog_spec_del); + if (!(a_format->pattern_specs)) { + zc_error("zc_arraylist_new fail"); + goto err; + } + + for (p = a_format->pattern; *p != '\0'; p = q) { + a_spec = zlog_spec_new(p, &q, time_cache_count); + if (!a_spec) { + zc_error("zlog_spec_new fail"); + goto err; + } + + if (zc_arraylist_add(a_format->pattern_specs, a_spec)) { + zlog_spec_del(a_spec); + zc_error("zc_arraylist_add fail"); + goto err; + } + } + + zlog_format_profile(a_format, ZC_DEBUG); + return a_format; +err: + zlog_format_del(a_format); + return NULL; +} + +/*******************************************************************************/ +/* return 0 success, or buf is full + * return -1 fail + */ +int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread) +{ + int i; + zlog_spec_t *a_spec; + + zlog_buf_restart(a_thread->msg_buf); + + zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) { + if (zlog_spec_gen_msg(a_spec, a_thread) == 0) { + continue; + } else { + return -1; + } + } + + return 0; +} diff --git a/zlog/format.h b/zlog/format.h new file mode 100644 index 0000000..604bf94 --- /dev/null +++ b/zlog/format.h @@ -0,0 +1,32 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_format_h +#define __zlog_format_h + +#include "thread.h" +#include "zc_defs.h" + +typedef struct zlog_format_s zlog_format_t; + +struct zlog_format_s { + char name[MAXLEN_CFG_LINE + 1]; + char pattern[MAXLEN_CFG_LINE + 1]; + zc_arraylist_t *pattern_specs; +}; + +zlog_format_t *zlog_format_new(char *line, int * time_cache_count); +void zlog_format_del(zlog_format_t * a_format); +void zlog_format_profile(zlog_format_t * a_format, int flag); + +int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread); + +#define zlog_format_has_name(a_format, fname) \ + STRCMP(a_format->name, ==, fname) + +#endif diff --git a/zlog/level.c b/zlog/level.c new file mode 100644 index 0000000..0d39a3a --- /dev/null +++ b/zlog/level.c @@ -0,0 +1,141 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include "syslog.h" + +#include "zc_defs.h" +#include "level.h" + +void zlog_level_profile(zlog_level_t *a_level, int flag) +{ + zc_assert(a_level,); + zc_profile(flag, "---level[%p][%d,%s,%s,%d,%d]---", + a_level, + a_level->int_level, + a_level->str_uppercase, + a_level->str_lowercase, + (int) a_level->str_len, + a_level->syslog_level); + return; +} + +/*******************************************************************************/ +void zlog_level_del(zlog_level_t *a_level) +{ + zc_assert(a_level,); + zc_debug("zlog_level_del[%p]", a_level); + free(a_level); + return; +} + +static int syslog_level_atoi(char *str) +{ + /* guess no unix system will choose -187 + * as its syslog level, so it is a safe return value + */ + zc_assert(str, -187); + + if (STRICMP(str, ==, "LOG_EMERG")) + return LOG_EMERG; + if (STRICMP(str, ==, "LOG_ALERT")) + return LOG_ALERT; + if (STRICMP(str, ==, "LOG_CRIT")) + return LOG_CRIT; + if (STRICMP(str, ==, "LOG_ERR")) + return LOG_ERR; + if (STRICMP(str, ==, "LOG_WARNING")) + return LOG_WARNING; + if (STRICMP(str, ==, "LOG_NOTICE")) + return LOG_NOTICE; + if (STRICMP(str, ==, "LOG_INFO")) + return LOG_INFO; + if (STRICMP(str, ==, "LOG_DEBUG")) + return LOG_DEBUG; + + zc_error("wrong syslog level[%s]", str); + return -187; +} + +/* line: TRACE = 10, LOG_ERR */ +zlog_level_t *zlog_level_new(char *line) +{ + zlog_level_t *a_level = NULL; + int i; + int nscan; + char str[MAXLEN_CFG_LINE + 1]; + int l = 0; + char sl[MAXLEN_CFG_LINE + 1]; + + zc_assert(line, NULL); + + memset(str, 0x00, sizeof(str)); + memset(sl, 0x00, sizeof(sl)); + + nscan = sscanf(line, " %[^= \t] = %d ,%s", str, &l, sl); + if (nscan < 2) { + zc_error("level[%s], syntax wrong", line); + return NULL; + } + + /* check level and str */ + if ((l < 0) || (l > 255)) { + zc_error("l[%d] not in [0,255], wrong", l); + return NULL; + } + + if (str[0] == '\0') { + zc_error("str[0] = 0"); + return NULL; + } + + a_level = calloc(1, sizeof(zlog_level_t)); + if (!a_level) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_level->int_level = l; + + /* fill syslog level */ + if (sl[0] == '\0') { + a_level->syslog_level = LOG_DEBUG; + } else { + a_level->syslog_level = syslog_level_atoi(sl); + if (a_level->syslog_level == -187) { + zc_error("syslog_level_atoi fail"); + goto err; + } + } + + /* strncpy and toupper(str) */ + for (i = 0; (i < sizeof(a_level->str_uppercase) - 1) && str[i] != '\0'; i++) { + (a_level->str_uppercase)[i] = toupper(str[i]); + (a_level->str_lowercase)[i] = tolower(str[i]); + } + + if (str[i] != '\0') { + /* overflow */ + zc_error("not enough space for str, str[%s] > %d", str, i); + goto err; + } else { + (a_level->str_uppercase)[i] = '\0'; + (a_level->str_lowercase)[i] = '\0'; + } + + a_level->str_len = i; + + //zlog_level_profile(a_level, ZC_DEBUG); + return a_level; +err: + zc_error("line[%s]", line); + zlog_level_del(a_level); + return NULL; +} diff --git a/zlog/level.h b/zlog/level.h new file mode 100644 index 0000000..7077fc7 --- /dev/null +++ b/zlog/level.h @@ -0,0 +1,26 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_level_h +#define __zlog_level_h + +#include "zc_defs.h" + +typedef struct zlog_level_s { + int int_level; + char str_uppercase[MAXLEN_PATH + 1]; + char str_lowercase[MAXLEN_PATH + 1]; + size_t str_len; + int syslog_level; +} zlog_level_t; + +zlog_level_t *zlog_level_new(char *line); +void zlog_level_del(zlog_level_t *a_level); +void zlog_level_profile(zlog_level_t *a_level, int flag); + +#endif diff --git a/zlog/level_list.c b/zlog/level_list.c new file mode 100644 index 0000000..ee47a85 --- /dev/null +++ b/zlog/level_list.c @@ -0,0 +1,145 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include "syslog.h" + +#include "zc_defs.h" +#include "level.h" +#include "level_list.h" + +/* zlog_level_list == zc_arraylist_t */ + +void zlog_level_list_profile(zc_arraylist_t *levels, int flag) +{ + int i; + zlog_level_t *a_level; + + zc_assert(levels,); + zc_profile(flag, "--level_list[%p]--", levels); + zc_arraylist_foreach(levels, i, a_level) { + /* skip empty slots */ + if (a_level) zlog_level_profile(a_level, flag); + } + return; +} + +/*******************************************************************************/ +void zlog_level_list_del(zc_arraylist_t *levels) +{ + zc_assert(levels,); + zc_arraylist_del(levels); + zc_debug("zc_level_list_del[%p]", levels); + return; +} + +static int zlog_level_list_set_default(zc_arraylist_t *levels) +{ + return zlog_level_list_set(levels, "* = 0, LOG_INFO") + || zlog_level_list_set(levels, "DEBUG = 20, LOG_DEBUG") + || zlog_level_list_set(levels, "INFO = 40, LOG_INFO") + || zlog_level_list_set(levels, "NOTICE = 60, LOG_NOTICE") + || zlog_level_list_set(levels, "WARN = 80, LOG_WARNING") + || zlog_level_list_set(levels, "ERROR = 100, LOG_ERR") + || zlog_level_list_set(levels, "FATAL = 120, LOG_ALERT") + || zlog_level_list_set(levels, "UNKNOWN = 254, LOG_ERR") + || zlog_level_list_set(levels, "! = 255, LOG_INFO"); +} + +zc_arraylist_t *zlog_level_list_new(void) +{ + zc_arraylist_t *levels; + + levels = zc_arraylist_new((zc_arraylist_del_fn)zlog_level_del); + if (!levels) { + zc_error("zc_arraylist_new fail"); + return NULL; + } + + if (zlog_level_list_set_default(levels)) { + zc_error("zlog_level_set_default fail"); + goto err; + } + + //zlog_level_list_profile(levels, ZC_DEBUG); + return levels; +err: + zc_arraylist_del(levels); + return NULL; +} + +/*******************************************************************************/ +int zlog_level_list_set(zc_arraylist_t *levels, char *line) +{ + zlog_level_t *a_level; + + a_level = zlog_level_new(line); + if (!a_level) { + zc_error("zlog_level_new fail"); + return -1; + } + + if (zc_arraylist_set(levels, a_level->int_level, a_level)) { + zc_error("zc_arraylist_set fail"); + goto err; + } + + return 0; +err: + zc_error("line[%s]", line); + zlog_level_del(a_level); + return -1; +} + +zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l) +{ + zlog_level_t *a_level; + +#if 0 + if ((l <= 0) || (l > 254)) { + /* illegal input from zlog() */ + zc_error("l[%d] not in (0,254), set to UNKOWN", l); + l = 254; + } +#endif + + a_level = zc_arraylist_get(levels, l); + if (a_level) { + return a_level; + } else { + /* empty slot */ + zc_error("l[%d] not in (0,254), or has no level defined," + "see configure file define, set to UNKOWN", l); + return zc_arraylist_get(levels, 254); + } +} + +/*******************************************************************************/ + +int zlog_level_list_atoi(zc_arraylist_t *levels, char *str) +{ + int i; + zlog_level_t *a_level; + + if (str == NULL || *str == '\0') { + zc_error("str is [%s], can't find level", str); + return -1; + } + + zc_arraylist_foreach(levels, i, a_level) { + if (a_level && STRICMP(str, ==, a_level->str_uppercase)) { + return i; + } + } + + zc_error("str[%s] can't found in level list", str); + return -1; +} + diff --git a/zlog/level_list.h b/zlog/level_list.h new file mode 100644 index 0000000..9c5332c --- /dev/null +++ b/zlog/level_list.h @@ -0,0 +1,33 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_level_list_h +#define __zlog_level_list_h + +#include "zc_defs.h" +#include "level.h" + +zc_arraylist_t *zlog_level_list_new(void); +void zlog_level_list_del(zc_arraylist_t *levels); +void zlog_level_list_profile(zc_arraylist_t *levels, int flag); + +/* conf init use, slow */ +/* if l is wrong or str=="", return -1 */ +int zlog_level_list_set(zc_arraylist_t *levels, char *line); + +/* spec ouput use, fast */ +/* rule output use, fast */ +/* if not found, return levels[254] */ +zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l); + +/* rule init use, slow */ +/* if not found, return -1 */ +int zlog_level_list_atoi(zc_arraylist_t *levels, char *str); + + +#endif diff --git a/zlog/makefile b/zlog/makefile new file mode 100644 index 0000000..4ece5b1 --- /dev/null +++ b/zlog/makefile @@ -0,0 +1,204 @@ +# zlog makefile +# Copyright (C) 2010-2012 Hardy Simpson +# This file is released under the LGPL 2.1 license, see the COPYING file + +OBJ= \ + buf.o \ + category.o \ + category_table.o \ + conf.o \ + event.o \ + format.o \ + level.o \ + level_list.o \ + mdc.o \ + record.o \ + record_table.o \ + rotater.o \ + rule.o \ + spec.o \ + thread.o \ + zc_arraylist.o \ + zc_hashtable.o \ + zc_profile.o \ + zc_util.o \ + zlog.o +BINS=zlog-chk-conf +LIBNAME=libzlog + +ZLOG_MAJOR=1 +ZLOG_MINOR=2 + +# Fallback to gcc when $CC is not in $PATH. +CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') +OPTIMIZATION?=-O2 +WARNINGS=-Wall -Wstrict-prototypes -fwrapv +DEBUG?= -g -ggdb +REAL_CFLAGS=$(OPTIMIZATION) -fPIC -pthread $(CFLAGS) $(WARNINGS) $(DEBUG) +REAL_LDFLAGS=$(LDFLAGS) -pthread + +DYLIBSUFFIX=so +STLIBSUFFIX=a +DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR).$(ZLOG_MINOR) +DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR) +DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) +DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) +STLIB_MAKE_CMD=ar rcs $(STLIBNAME) + +# Installation related variables +PREFIX?=/usr/local +INCLUDE_PATH=include +LIBRARY_PATH=lib +BINARY_PATH=bin +INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH) +INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH) +INSTALL_BINARY_PATH= $(PREFIX)/$(BINARY_PATH) + +# Platform-specific overrides +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +compiler_platform := $(shell sh -c '$(CC) --version|grep -i apple') + +ifeq ($(uname_S),SunOS) +# REAL_LDFLAGS+= -ldl -lnsl -lsocket + DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) + INSTALL= cp -r +endif + +# For Darwin builds, check the compiler platform above is not empty. The covers cross compilation on Linux +ifneq ($(compiler_platform),) + DYLIBSUFFIX=dylib + DYLIB_MINOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(ZLOG_MINOR).$(DYLIBSUFFIX) + DYLIB_MAJOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(DYLIBSUFFIX) + DYLIB_MAKE_CMD=$(CC) -dynamiclib -install_name $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) +endif + +ifeq ($(uname_S),AIX) + # this logic of minor major is not relevant on AIX or at least not widely used + # not to mention dynamic linker .a preference... + DYLIB_MAKE_CMD=$(CC) -shared -Wl,-G,-b64 -maix64 -pthread -o $(DYLIBNAME) $(LDFLAGS) + REAL_CFLAGS+= -maix64 + STLIB_MAKE_CMD=OBJECT_MODE=64 ar rcs $(STLIBNAME) $(DYLIB_MAJOR_NAME) +endif + +all: $(DYLIBNAME) $(BINS) + +# Deps (use make dep to generate this) +buf.o: buf.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h buf.h +category.o: category.c fmacros.h category.h zc_defs.h zc_profile.h \ + zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h thread.h event.h \ + buf.h mdc.h rule.h format.h rotater.h record.h +category_table.o: category_table.c zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h category_table.h category.h \ + thread.h event.h buf.h mdc.h +conf.o: conf.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ + mdc.h rotater.h rule.h record.h level_list.h level.h +event.o: event.c fmacros.h zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h event.h +format.o: format.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h thread.h event.h buf.h mdc.h spec.h format.h +level.o: level.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h level.h +level_list.o: level_list.c zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h level.h level_list.h +mdc.o: mdc.c mdc.h zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h +record.o: record.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h record.h +record_table.o: record_table.c zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h record_table.h record.h +rotater.o: rotater.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h rotater.h +rule.o: rule.c fmacros.h rule.h zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ + mdc.h rotater.h record.h level_list.h level.h spec.h +spec.o: spec.c fmacros.h spec.h event.h zc_defs.h zc_profile.h \ + zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h buf.h thread.h \ + mdc.h level_list.h level.h +thread.o: thread.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h event.h buf.h thread.h mdc.h +zc_arraylist.o: zc_arraylist.c zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h +zc_hashtable.o: zc_hashtable.c zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h +zc_profile.o: zc_profile.c fmacros.h zc_profile.h zc_xplatform.h +zc_util.o: zc_util.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ + zc_xplatform.h zc_util.h +zlog-chk-conf.o: zlog-chk-conf.c fmacros.h zlog.h +zlog.o: zlog.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ + zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ + mdc.h rotater.h category_table.h category.h record_table.h \ + record.h rule.h + +$(DYLIBNAME): $(OBJ) + $(DYLIB_MAKE_CMD) $(OBJ) $(REAL_LDFLAGS) + # for use in test folder - linux and requirement for aix runtime + # resolving + cp -f $(DYLIBNAME) $(DYLIB_MAJOR_NAME) + cp -f $(DYLIBNAME) $(DYLIB_MINOR_NAME) + +$(STLIBNAME): $(OBJ) + $(STLIB_MAKE_CMD) $(OBJ) + +dynamic: $(DYLIBNAME) +static: $(STLIBNAME) + +# Binaries: +zlog-chk-conf: zlog-chk-conf.o $(STLIBNAME) $(DYLIBNAME) + $(CC) -o $@ zlog-chk-conf.o -L. -lzlog $(REAL_LDFLAGS) + +.c.o: + $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< + +clean: + rm -rf $(DYLIBNAME) $(STLIBNAME) $(BINS) *.o *.gcda *.gcno *.gcov $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) + +dep: + $(CC) -MM *.c + +# Installation target + +ifeq ($(uname_S),SunOS) + INSTALL?= cp -r +endif + +ifeq ($(uname_S),AIX) + INSTALL?= cp -r +endif + + +INSTALL?= cp -a + +install: $(DYLIBNAME) $(STLIBNAME) + mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) $(INSTALL_BINARY_PATH) + $(INSTALL) zlog.h $(INSTALL_INCLUDE_PATH) + $(INSTALL) zlog-chk-conf $(INSTALL_BINARY_PATH) + $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) + cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) + $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) + +32bit: + @echo "" + @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" + @echo "" + $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" + +gprof: + $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" + +gcov: + $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" + +coverage: gcov + make check + mkdir -p tmp/lcov + lcov -d . -c -o tmp/lcov/hiredis.info + genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info + +noopt: + $(MAKE) OPTIMIZATION="" + +.PHONY: all clean dep install 32bit gprof gcov noopt diff --git a/zlog/mdc.c b/zlog/mdc.c new file mode 100644 index 0000000..41df8e7 --- /dev/null +++ b/zlog/mdc.c @@ -0,0 +1,145 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include + +#include "mdc.h" +#include "zc_defs.h" + +void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag) +{ + zc_hashtable_entry_t *a_entry; + zlog_mdc_kv_t *a_mdc_kv; + + zc_assert(a_mdc,); + zc_profile(flag, "---mdc[%p]---", a_mdc); + + zc_hashtable_foreach(a_mdc->tab, a_entry) { + a_mdc_kv = a_entry->value; + zc_profile(flag, "----mdc_kv[%p][%s]-[%s]----", + a_mdc_kv, + a_mdc_kv->key, a_mdc_kv->value); + } + return; +} +/*******************************************************************************/ +void zlog_mdc_del(zlog_mdc_t * a_mdc) +{ + zc_assert(a_mdc,); + if (a_mdc->tab) zc_hashtable_del(a_mdc->tab); + zc_debug("zlog_mdc_del[%p]", a_mdc); + free(a_mdc); + return; +} + +static void zlog_mdc_kv_del(zlog_mdc_kv_t * a_mdc_kv) +{ + zc_debug("zlog_mdc_kv_del[%p]", a_mdc_kv); + free(a_mdc_kv); +} + +static zlog_mdc_kv_t *zlog_mdc_kv_new(const char *key, const char *value) +{ + zlog_mdc_kv_t *a_mdc_kv; + + a_mdc_kv = calloc(1, sizeof(zlog_mdc_kv_t)); + if (!a_mdc_kv) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + snprintf(a_mdc_kv->key, sizeof(a_mdc_kv->key), "%s", key); + a_mdc_kv->value_len = snprintf(a_mdc_kv->value, sizeof(a_mdc_kv->value), "%s", value); + return a_mdc_kv; +} + +zlog_mdc_t *zlog_mdc_new(void) +{ + zlog_mdc_t *a_mdc; + + a_mdc = calloc(1, sizeof(zlog_mdc_t)); + if (!a_mdc) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_mdc->tab = zc_hashtable_new(20, + zc_hashtable_str_hash, + zc_hashtable_str_equal, NULL, + (zc_hashtable_del_fn) zlog_mdc_kv_del); + if (!a_mdc->tab) { + zc_error("zc_hashtable_new fail"); + goto err; + } + + //zlog_mdc_profile(a_mdc, ZC_DEBUG); + return a_mdc; +err: + zlog_mdc_del(a_mdc); + return NULL; +} + +/*******************************************************************************/ +int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value) +{ + zlog_mdc_kv_t *a_mdc_kv; + + a_mdc_kv = zlog_mdc_kv_new(key, value); + if (!a_mdc_kv) { + zc_error("zlog_mdc_kv_new failed"); + return -1; + } + + if (zc_hashtable_put(a_mdc->tab, a_mdc_kv->key, a_mdc_kv)) { + zc_error("zc_hashtable_put fail"); + zlog_mdc_kv_del(a_mdc_kv); + return -1; + } + + return 0; +} + +void zlog_mdc_clean(zlog_mdc_t * a_mdc) +{ + zc_hashtable_clean(a_mdc->tab); + return; +} + +char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key) +{ + zlog_mdc_kv_t *a_mdc_kv; + + a_mdc_kv = zc_hashtable_get(a_mdc->tab, key); + if (!a_mdc_kv) { + zc_error("zc_hashtable_get fail"); + return NULL; + } else { + return a_mdc_kv->value; + } +} + +zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key) +{ + zlog_mdc_kv_t *a_mdc_kv; + + a_mdc_kv = zc_hashtable_get(a_mdc->tab, key); + if (!a_mdc_kv) { + zc_error("zc_hashtable_get fail"); + return NULL; + } else { + return a_mdc_kv; + } +} + +void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key) +{ + zc_hashtable_remove(a_mdc->tab, key); + return; +} diff --git a/zlog/mdc.h b/zlog/mdc.h new file mode 100644 index 0000000..07ba5ae --- /dev/null +++ b/zlog/mdc.h @@ -0,0 +1,36 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_mdc_h +#define __zlog_mdc_h + +#include "zc_defs.h" + +typedef struct zlog_mdc_s zlog_mdc_t; +struct zlog_mdc_s { + zc_hashtable_t *tab; +}; + +zlog_mdc_t *zlog_mdc_new(void); +void zlog_mdc_del(zlog_mdc_t * a_mdc); +void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag); + +void zlog_mdc_clean(zlog_mdc_t * a_mdc); +int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value); +char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key); +void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key); + +typedef struct zlog_mdc_kv_s { + char key[MAXLEN_PATH + 1]; + char value[MAXLEN_PATH + 1]; + size_t value_len; +} zlog_mdc_kv_t; + +zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key); + +#endif diff --git a/zlog/record.c b/zlog/record.c new file mode 100644 index 0000000..a245e06 --- /dev/null +++ b/zlog/record.c @@ -0,0 +1,53 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ +#include "errno.h" +#include "zc_defs.h" +#include "record.h" + +void zlog_record_profile(zlog_record_t *a_record, int flag) +{ + zc_assert(a_record,); + zc_profile(flag, "--record:[%p][%s:%p]--", a_record, a_record->name, a_record->output); + return; +} + +void zlog_record_del(zlog_record_t *a_record) +{ + zc_assert(a_record,); + zc_debug("zlog_record_del[%p]", a_record); + free(a_record); + return; +} + +zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output) +{ + zlog_record_t *a_record; + + zc_assert(name, NULL); + zc_assert(output, NULL); + + a_record = calloc(1, sizeof(zlog_record_t)); + if (!a_record) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + if (strlen(name) > sizeof(a_record->name) - 1) { + zc_error("name[%s] is too long", name); + goto err; + } + + strcpy(a_record->name, name); + a_record->output = output; + + zlog_record_profile(a_record, ZC_DEBUG); + return a_record; +err: + zlog_record_del(a_record); + return NULL; +} diff --git a/zlog/record.h b/zlog/record.h new file mode 100644 index 0000000..4b67353 --- /dev/null +++ b/zlog/record.h @@ -0,0 +1,32 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_record_h +#define __zlog_record_h + +#include "zc_defs.h" + +/* record is user-defined output function and it's name from configure file */ +typedef struct zlog_msg_s { + char *buf; + size_t len; + char *path; +} zlog_msg_t; /* 3 of this first, see need thread or not later */ + +typedef int (*zlog_record_fn)(zlog_msg_t * msg); + +typedef struct zlog_record_s { + char name[MAXLEN_PATH + 1]; + zlog_record_fn output; +} zlog_record_t; + +zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output); +void zlog_record_del(zlog_record_t *a_record); +void zlog_record_profile(zlog_record_t *a_record, int flag); + +#endif diff --git a/zlog/record_table.c b/zlog/record_table.c new file mode 100644 index 0000000..df45a37 --- /dev/null +++ b/zlog/record_table.c @@ -0,0 +1,56 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include + +#include "zc_defs.h" +#include "record_table.h" + +void zlog_record_table_profile(zc_hashtable_t * records, int flag) +{ + zc_hashtable_entry_t *a_entry; + zlog_record_t *a_record; + + zc_assert(records,); + zc_profile(flag, "-record_table[%p]-", records); + zc_hashtable_foreach(records, a_entry) { + a_record = (zlog_record_t *) a_entry->value; + zlog_record_profile(a_record, flag); + } + return; +} + +/*******************************************************************************/ + +void zlog_record_table_del(zc_hashtable_t * records) +{ + zc_assert(records,); + zc_hashtable_del(records); + zc_debug("zlog_record_table_del[%p]", records); + return; +} + +zc_hashtable_t *zlog_record_table_new(void) +{ + zc_hashtable_t *records; + + records = zc_hashtable_new(20, + (zc_hashtable_hash_fn) zc_hashtable_str_hash, + (zc_hashtable_equal_fn) zc_hashtable_str_equal, + NULL, (zc_hashtable_del_fn) zlog_record_del); + if (!records) { + zc_error("zc_hashtable_new fail"); + return NULL; + } else { + zlog_record_table_profile(records, ZC_DEBUG); + return records; + } +} +/*******************************************************************************/ diff --git a/zlog/record_table.h b/zlog/record_table.h new file mode 100644 index 0000000..d1ab3e1 --- /dev/null +++ b/zlog/record_table.h @@ -0,0 +1,19 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_record_table_h +#define __zlog_record_table_h + +#include "zc_defs.h" +#include "record.h" + +zc_hashtable_t *zlog_record_table_new(void); +void zlog_record_table_del(zc_hashtable_t * records); +void zlog_record_table_profile(zc_hashtable_t * records, int flag); + +#endif diff --git a/zlog/rotater.c b/zlog/rotater.c new file mode 100644 index 0000000..ca6ca2b --- /dev/null +++ b/zlog/rotater.c @@ -0,0 +1,575 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "zc_defs.h" +#include "rotater.h" + +#define ROLLING 1 /* aa.02->aa.03, aa.01->aa.02, aa->aa.01 */ +#define SEQUENCE 2 /* aa->aa.03 */ + +typedef struct { + int index; + char path[MAXLEN_PATH + 1]; +} zlog_file_t; + +void zlog_rotater_profile(zlog_rotater_t * a_rotater, int flag) +{ + zc_assert(a_rotater,); + zc_profile(flag, "--rotater[%p][%p,%s,%d][%s,%s,%s,%ld,%ld,%d,%d,%d]--", + a_rotater, + + &(a_rotater->lock_mutex), + a_rotater->lock_file, + a_rotater->lock_fd, + + a_rotater->base_path, + a_rotater->archive_path, + a_rotater->glob_path, + (long)a_rotater->num_start_len, + (long)a_rotater->num_end_len, + a_rotater->num_width, + a_rotater->mv_type, + a_rotater->max_count + ); + if (a_rotater->files) { + int i; + zlog_file_t *a_file; + zc_arraylist_foreach(a_rotater->files, i, a_file) { + zc_profile(flag, "[%s,%d]->", a_file->path, a_file->index); + } + } + return; +} + +/*******************************************************************************/ +void zlog_rotater_del(zlog_rotater_t *a_rotater) +{ + zc_assert(a_rotater,); + + if (a_rotater->lock_fd) { + if (close(a_rotater->lock_fd)) { + zc_error("close fail, errno[%d]", errno); + } + } + + if (pthread_mutex_destroy(&(a_rotater->lock_mutex))) { + zc_error("pthread_mutex_destroy fail, errno[%d]", errno); + } + + zc_debug("zlog_rotater_del[%p]", a_rotater); + free(a_rotater); + return; +} + +zlog_rotater_t *zlog_rotater_new(char *lock_file) +{ + int fd = 0; + zlog_rotater_t *a_rotater; + + zc_assert(lock_file, NULL); + + a_rotater = calloc(1, sizeof(zlog_rotater_t)); + if (!a_rotater) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + if (pthread_mutex_init(&(a_rotater->lock_mutex), NULL)) { + zc_error("pthread_mutex_init fail, errno[%d]", errno); + free(a_rotater); + return NULL; + } + + /* depends on umask of the user here + * if user A create /tmp/zlog.lock 0600 + * user B is unable to read /tmp/zlog.lock + * B has to choose another lock file except /tmp/zlog.lock + */ + fd = open(lock_file, O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd < 0) { + zc_error("open file[%s] fail, errno[%d]", lock_file, errno); + goto err; + } + + a_rotater->lock_fd = fd; + a_rotater->lock_file = lock_file; + + //zlog_rotater_profile(a_rotater, ZC_DEBUG); + return a_rotater; +err: + zlog_rotater_del(a_rotater); + return NULL; +} + +/*******************************************************************************/ + +static void zlog_file_del(zlog_file_t * a_file) +{ + zc_debug("del onefile[%p]", a_file); + zc_debug("a_file->path[%s]", a_file->path); + free(a_file); +} + +static zlog_file_t *zlog_file_check_new(zlog_rotater_t * a_rotater, const char *path) +{ + int nwrite; + int nread; + zlog_file_t *a_file; + + /* base_path will not be in list */ + if (STRCMP(a_rotater->base_path, ==, path)) { + return NULL; + } + + /* omit dirs */ + if ((path)[strlen(path) - 1] == '/') { + return NULL; + } + + a_file = calloc(1, sizeof(zlog_file_t)); + if (!a_file) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + nwrite = snprintf(a_file->path, sizeof(a_file->path), "%s", path); + if (nwrite < 0 || nwrite >= sizeof(a_file->path)) { + zc_error("snprintf fail or overflow, nwrite=[%d], errno[%d]", nwrite, errno); + goto err; + } + + nread = 0; + sscanf(a_file->path + a_rotater->num_start_len, "%d%n", &(a_file->index), &(nread)); + + if (a_rotater->num_width != 0) { + if (nread < a_rotater->num_width) { + zc_warn("aa.1.log is not expect, need aa.01.log"); + goto err; + } + } /* else all file is ok */ + + return a_file; +err: + free(a_file); + return NULL; +} + + +static int zlog_file_cmp(zlog_file_t * a_file_1, zlog_file_t * a_file_2) +{ + return (a_file_1->index > a_file_2->index); +} + +static int zlog_rotater_add_archive_files(zlog_rotater_t * a_rotater) +{ + int rc = 0; + glob_t glob_buf; + size_t pathc; + char **pathv; + zlog_file_t *a_file; + + a_rotater->files = zc_arraylist_new((zc_arraylist_del_fn)zlog_file_del); + if (!a_rotater->files) { + zc_error("zc_arraylist_new fail"); + return -1; + } + + /* scan file which is aa.*.log and aa */ + rc = glob(a_rotater->glob_path, GLOB_ERR | GLOB_MARK | GLOB_NOSORT, NULL, &glob_buf); + if (rc == GLOB_NOMATCH) { + goto exit; + } else if (rc) { + zc_error("glob err, rc=[%d], errno[%d]", rc, errno); + return -1; + } + + pathv = glob_buf.gl_pathv; + pathc = glob_buf.gl_pathc; + + /* check and find match aa.[0-9]*.log, depend on num_width */ + for (; pathc-- > 0; pathv++) { + a_file = zlog_file_check_new(a_rotater, *pathv); + if (!a_file) { + zc_warn("not the expect pattern file"); + continue; + } + + /* file in list aa.00, aa.01, aa.02... */ + rc = zc_arraylist_sortadd(a_rotater->files, + (zc_arraylist_cmp_fn)zlog_file_cmp, a_file); + if (rc) { + zc_error("zc_arraylist_sortadd fail"); + goto err; + } + } + +exit: + globfree(&glob_buf); + return 0; +err: + globfree(&glob_buf); + return -1; +} + +static int zlog_rotater_seq_files(zlog_rotater_t * a_rotater) +{ + int rc = 0; + int nwrite = 0; + int i, j; + zlog_file_t *a_file; + char new_path[MAXLEN_PATH + 1]; + + zc_arraylist_foreach(a_rotater->files, i, a_file) { + if (a_rotater->max_count > 0 + && i < zc_arraylist_len(a_rotater->files) - a_rotater->max_count) { + /* unlink aa.0 aa.1 .. aa.(n-c) */ + rc = unlink(a_file->path); + if (rc) { + zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno); + return -1; + } + continue; + } + } + + if (zc_arraylist_len(a_rotater->files) > 0) { /* list is not empty */ + a_file = zc_arraylist_get(a_rotater->files, zc_arraylist_len(a_rotater->files)-1); + if (!a_file) { + zc_error("zc_arraylist_get fail"); + return -1; + } + + j = zc_max(zc_arraylist_len(a_rotater->files)-1, a_file->index) + 1; + } else { + j = 0; + } + + /* do the base_path mv */ + memset(new_path, 0x00, sizeof(new_path)); + nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", + (int) a_rotater->num_start_len, a_rotater->glob_path, + a_rotater->num_width, j, + a_rotater->glob_path + a_rotater->num_end_len); + if (nwrite < 0 || nwrite >= sizeof(new_path)) { + zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); + return -1; + } + + if (rename(a_rotater->base_path, new_path)) { + zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno); + return -1; + } + + return 0; +} + + +static int zlog_rotater_roll_files(zlog_rotater_t * a_rotater) +{ + int i; + int rc = 0; + int nwrite; + char new_path[MAXLEN_PATH + 1]; + zlog_file_t *a_file; + + /* now in the list, aa.0 aa.1 aa.2 aa.02... */ + for (i = zc_arraylist_len(a_rotater->files) - 1; i > -1; i--) { + a_file = zc_arraylist_get(a_rotater->files, i); + if (!a_file) { + zc_error("zc_arraylist_get fail"); + return -1; + } + + if (a_rotater->max_count > 0 && i >= a_rotater->max_count - 1) { + /* remove file.3 >= 3*/ + rc = unlink(a_file->path); + if (rc) { + zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno); + return -1; + } + continue; + } + + /* begin rename aa.01.log -> aa.02.log , using i, as index in list maybe repeat */ + memset(new_path, 0x00, sizeof(new_path)); + nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", + (int) a_rotater->num_start_len, a_rotater->glob_path, + a_rotater->num_width, i + 1, + a_rotater->glob_path + a_rotater->num_end_len); + if (nwrite < 0 || nwrite >= sizeof(new_path)) { + zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); + return -1; + } + + if (rename(a_file->path, new_path)) { + zc_error("rename[%s]->[%s] fail, errno[%d]", a_file->path, new_path, errno); + return -1; + } + } + + /* do the base_path mv */ + memset(new_path, 0x00, sizeof(new_path)); + nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", + (int) a_rotater->num_start_len, a_rotater->glob_path, + a_rotater->num_width, 0, + a_rotater->glob_path + a_rotater->num_end_len); + if (nwrite < 0 || nwrite >= sizeof(new_path)) { + zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); + return -1; + } + + if (rename(a_rotater->base_path, new_path)) { + zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno); + return -1; + } + + return 0; +} + + +static int zlog_rotater_parse_archive_path(zlog_rotater_t * a_rotater) +{ + int nwrite; + int nread; + char *p; + size_t len; + + /* no archive path is set */ + if (a_rotater->archive_path[0] == '\0') { + nwrite = snprintf(a_rotater->glob_path, sizeof(a_rotater->glob_path), + "%s.*", a_rotater->base_path); + if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path)) { + zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); + return -1; + } + + a_rotater->mv_type = ROLLING; + a_rotater->num_width = 0; + a_rotater->num_start_len = strlen(a_rotater->base_path) + 1; + a_rotater->num_end_len = strlen(a_rotater->base_path) + 2; + return 0; + } else { + + /* find the 1st # */ + p = strchr(a_rotater->archive_path, '#'); + if (!p) { + zc_error("no # in archive_path[%s]", a_rotater->archive_path); + return -1; + } + + nread = 0; + sscanf(p, "#%d%n", &(a_rotater->num_width), &nread); + if (nread == 0) nread = 1; + if (*(p+nread) == 'r') { + a_rotater->mv_type = ROLLING; + } else if (*(p+nread) == 's') { + a_rotater->mv_type = SEQUENCE; + } else { + zc_error("#r or #s not found"); + return -1; + } + + /* copy and substitue #i to * in glob_path*/ + len = p - a_rotater->archive_path; + if (len > sizeof(a_rotater->glob_path) - 1) { + zc_error("sizeof glob_path not enough,len[%ld]", (long) len); + return -1; + } + memcpy(a_rotater->glob_path, a_rotater->archive_path, len); + + nwrite = snprintf(a_rotater->glob_path + len, sizeof(a_rotater->glob_path) - len, + "*%s", p + nread + 1); + if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path) - len) { + zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); + return -1; + } + + a_rotater->num_start_len = len; + a_rotater->num_end_len = len + 1; + } + + return 0; +} + +static void zlog_rotater_clean(zlog_rotater_t *a_rotater) +{ + a_rotater->base_path = NULL; + a_rotater->archive_path = NULL; + a_rotater->max_count = 0; + a_rotater->mv_type = 0; + a_rotater->num_width = 0; + a_rotater->num_start_len = 0; + a_rotater->num_end_len = 0; + memset(a_rotater->glob_path, 0x00, sizeof(a_rotater->glob_path)); + + if (a_rotater->files) zc_arraylist_del(a_rotater->files); + a_rotater->files = NULL; +} + +static int zlog_rotater_lsmv(zlog_rotater_t *a_rotater, + char *base_path, char *archive_path, int archive_max_count) +{ + int rc = 0; + + a_rotater->base_path = base_path; + a_rotater->archive_path = archive_path; + a_rotater->max_count = archive_max_count; + rc = zlog_rotater_parse_archive_path(a_rotater); + if (rc) { + zc_error("zlog_rotater_parse_archive_path fail"); + goto err; + } + + rc = zlog_rotater_add_archive_files(a_rotater); + if (rc) { + zc_error("zlog_rotater_add_archive_files fail"); + goto err; + } + + if (a_rotater->mv_type == ROLLING) { + rc = zlog_rotater_roll_files(a_rotater); + if (rc) { + zc_error("zlog_rotater_roll_files fail"); + goto err; + } + } else if (a_rotater->mv_type == SEQUENCE) { + rc = zlog_rotater_seq_files(a_rotater); + if (rc) { + zc_error("zlog_rotater_seq_files fail"); + goto err; + } + } + + zlog_rotater_clean(a_rotater); + return 0; +err: + zlog_rotater_clean(a_rotater); + return -1; +} +/*******************************************************************************/ + +static int zlog_rotater_trylock(zlog_rotater_t *a_rotater) +{ + int rc; + struct flock fl; + + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + + rc = pthread_mutex_trylock(&(a_rotater->lock_mutex)); + if (rc == EBUSY) { + zc_warn("pthread_mutex_trylock fail, as lock_mutex is locked by other threads"); + return -1; + } else if (rc != 0) { + zc_error("pthread_mutex_trylock fail, rc[%d]", rc); + return -1; + } + + if (fcntl(a_rotater->lock_fd, F_SETLK, &fl)) { + if (errno == EAGAIN || errno == EACCES) { + /* lock by other process, that's right, go on */ + /* EAGAIN on linux */ + /* EACCES on AIX */ + zc_warn("fcntl lock fail, as file is lock by other process"); + } else { + zc_error("lock fd[%d] fail, errno[%d]", a_rotater->lock_fd, errno); + } + if (pthread_mutex_unlock(&(a_rotater->lock_mutex))) { + zc_error("pthread_mutex_unlock fail, errno[%d]", errno); + } + return -1; + } + + return 0; +} + +static int zlog_rotater_unlock(zlog_rotater_t *a_rotater) +{ + int rc = 0; + struct flock fl; + + fl.l_type = F_UNLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + + if (fcntl(a_rotater->lock_fd, F_SETLK, &fl)) { + rc = -1; + zc_error("unlock fd[%s] fail, errno[%d]", a_rotater->lock_fd, errno); + } + + if (pthread_mutex_unlock(&(a_rotater->lock_mutex))) { + rc = -1; + zc_error("pthread_mutext_unlock fail, errno[%d]", errno); + } + + return rc; +} + +int zlog_rotater_rotate(zlog_rotater_t *a_rotater, + char *base_path, size_t msg_len, + char *archive_path, long archive_max_size, int archive_max_count) +{ + int rc = 0; + struct zlog_stat info; + + zc_assert(base_path, -1); + + if (zlog_rotater_trylock(a_rotater)) { + zc_warn("zlog_rotater_trylock fail, maybe lock by other process or threads"); + return 0; + } + + if (stat(base_path, &info)) { + rc = -1; + zc_error("stat [%s] fail, errno[%d]", base_path, errno); + goto exit; + } + + if (info.st_size + msg_len <= archive_max_size) { + /* file not so big, + * may alread rotate by oth process or thread, + * return */ + rc = 0; + goto exit; + } + + /* begin list and move files */ + rc = zlog_rotater_lsmv(a_rotater, base_path, archive_path, archive_max_count); + if (rc) { + zc_error("zlog_rotater_lsmv [%s] fail, return", base_path); + rc = -1; + } /* else if (rc == 0) */ + + //zc_debug("zlog_rotater_file_ls_mv success"); + +exit: + /* unlock file */ + if (zlog_rotater_unlock(a_rotater)) { + zc_error("zlog_rotater_unlock fail"); + } + + return rc; +} + +/*******************************************************************************/ diff --git a/zlog/rotater.h b/zlog/rotater.h new file mode 100644 index 0000000..2a8bf97 --- /dev/null +++ b/zlog/rotater.h @@ -0,0 +1,45 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_rotater_h +#define __zlog_rotater_h + +#include "zc_defs.h" + +typedef struct zlog_rotater_s { + pthread_mutex_t lock_mutex; + char *lock_file; + int lock_fd; + + /* single-use members */ + char *base_path; /* aa.log */ + char *archive_path; /* aa.#5i.log */ + char glob_path[MAXLEN_PATH + 1]; /* aa.*.log */ + size_t num_start_len; /* 3, offset to glob_path */ + size_t num_end_len; /* 6, offset to glob_path */ + int num_width; /* 5 */ + int mv_type; /* ROLLING or SEQUENCE */ + int max_count; + zc_arraylist_t *files; +} zlog_rotater_t; + +zlog_rotater_t *zlog_rotater_new(char *lock_file); +void zlog_rotater_del(zlog_rotater_t *a_rotater); + +/* + * return + * -1 fail + * 0 no rotate, or rotate and success + */ +int zlog_rotater_rotate(zlog_rotater_t *a_rotater, + char *base_path, size_t msg_len, + char *archive_path, long archive_max_size, int archive_max_count); + +void zlog_rotater_profile(zlog_rotater_t *a_rotater, int flag); + +#endif diff --git a/zlog/rule.c b/zlog/rule.c new file mode 100644 index 0000000..a9b2700 --- /dev/null +++ b/zlog/rule.c @@ -0,0 +1,1058 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rule.h" +#include "format.h" +#include "buf.h" +#include "thread.h" +#include "level_list.h" +#include "rotater.h" +#include "spec.h" +#include "conf.h" + +#include "zc_defs.h" + + +void zlog_rule_profile(zlog_rule_t * a_rule, int flag) +{ + int i; + zlog_spec_t *a_spec; + + zc_assert(a_rule,); + zc_profile(flag, "---rule:[%p][%s%c%d]-[%d,%d][%s,%p,%d:%ld*%d~%s][%d][%d][%s:%s:%p];[%p]---", + a_rule, + + a_rule->category, + a_rule->compare_char, + a_rule->level, + + a_rule->file_perms, + a_rule->file_open_flags, + + a_rule->file_path, + a_rule->dynamic_specs, + a_rule->static_fd, + + a_rule->archive_max_size, + a_rule->archive_max_count, + a_rule->archive_path, + + a_rule->pipe_fd, + + a_rule->syslog_facility, + + a_rule->record_name, + a_rule->record_path, + a_rule->record_func, + a_rule->format); + + if (a_rule->dynamic_specs) { + zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { + zlog_spec_profile(a_spec, flag); + } + } + return; +} + +/*******************************************************************************/ + +static int zlog_rule_output_static_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + struct stat stb; + int do_file_reload = 0; + int redo_inode_stat = 0; + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + /* check if the output file was changed by an external tool by comparing the inode to our saved off one */ + if (stat(a_rule->file_path, &stb)) { + if (errno != ENOENT) { + zc_error("stat fail on [%s], errno[%d]", a_rule->file_path, errno); + return -1; + } else { + do_file_reload = 1; + redo_inode_stat = 1; /* we'll have to restat the newly created file to get the inode info */ + } + } else { + do_file_reload = (stb.st_ino != a_rule->static_ino || stb.st_dev != a_rule->static_dev); + } + + if (do_file_reload) { + close(a_rule->static_fd); + a_rule->static_fd = open(a_rule->file_path, + O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags, + a_rule->file_perms); + if (a_rule->static_fd < 0) { + zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); + return -1; + } + + /* save off the new dev/inode info from the stat call we already did */ + if (redo_inode_stat) { + if (stat(a_rule->file_path, &stb)) { + zc_error("stat fail on new file[%s], errno[%d]", a_rule->file_path, errno); + return -1; + } + } + a_rule->static_dev = stb.st_dev; + a_rule->static_ino = stb.st_ino; + } + + if (write(a_rule->static_fd, + zlog_buf_str(a_thread->msg_buf), + zlog_buf_len(a_thread->msg_buf)) < 0) { + zc_error("write fail, errno[%d]", errno); + return -1; + } + + /* not so thread safe here, as multiple thread may ++fsync_count at the same time */ + if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { + a_rule->fsync_count = 0; + if (fsync(a_rule->static_fd)) { + zc_error("fsync[%d] fail, errno[%d]", a_rule->static_fd, errno); + } + } + + return 0; +} + +static char * zlog_rule_gen_archive_path(zlog_rule_t *a_rule, zlog_thread_t *a_thread) +{ + int i; + zlog_spec_t *a_spec; + + if (!a_rule->archive_specs) return a_rule->archive_path; + + zlog_buf_restart(a_thread->archive_path_buf); + + zc_arraylist_foreach(a_rule->archive_specs, i, a_spec) { + if (zlog_spec_gen_archive_path(a_spec, a_thread)) { + zc_error("zlog_spec_gen_path fail"); + return NULL; + } + } + + zlog_buf_seal(a_thread->archive_path_buf); + return zlog_buf_str(a_thread->archive_path_buf); +} + +static int zlog_rule_output_static_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + size_t len; + struct zlog_stat info; + int fd; + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + fd = open(a_rule->file_path, + a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); + if (fd < 0) { + zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); + return -1; + } + + len = zlog_buf_len(a_thread->msg_buf); + if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) { + zc_error("write fail, errno[%d]", errno); + close(fd); + return -1; + } + + if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { + a_rule->fsync_count = 0; + if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); + } + + if (close(fd) < 0) { + zc_error("close fail, maybe cause by write, errno[%d]", errno); + return -1; + } + + if (len > a_rule->archive_max_size) { + zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate", + (long)len, (long)a_rule->archive_max_size); + return 0; + } + + if (stat(a_rule->file_path, &info)) { + zc_warn("stat [%s] fail, errno[%d], maybe in rotating", a_rule->file_path, errno); + return 0; + } + + /* file not so big, return */ + if (info.st_size + len < a_rule->archive_max_size) return 0; + + if (zlog_rotater_rotate(zlog_env_conf->rotater, + a_rule->file_path, len, + zlog_rule_gen_archive_path(a_rule, a_thread), + a_rule->archive_max_size, a_rule->archive_max_count) + ) { + zc_error("zlog_rotater_rotate fail"); + return -1; + } /* success or no rotation do nothing */ + + return 0; +} + +/* return path success + * return NULL fail + */ +#define zlog_rule_gen_path(a_rule, a_thread) do { \ + int i; \ + zlog_spec_t *a_spec; \ + \ + zlog_buf_restart(a_thread->path_buf); \ + \ + zc_arraylist_foreach(a_rule->dynamic_specs, i, a_spec) { \ + if (zlog_spec_gen_path(a_spec, a_thread)) { \ + zc_error("zlog_spec_gen_path fail"); \ + return -1; \ + } \ + } \ + \ + zlog_buf_seal(a_thread->path_buf); \ +} while(0) + + +static int zlog_rule_output_dynamic_file_single(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + int fd; + + zlog_rule_gen_path(a_rule, a_thread); + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_output fail"); + return -1; + } + + fd = open(zlog_buf_str(a_thread->path_buf), + a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); + if (fd < 0) { + zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno); + return -1; + } + + if (write(fd, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { + zc_error("write fail, errno[%d]", errno); + close(fd); + return -1; + } + + if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { + a_rule->fsync_count = 0; + if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); + } + + if (close(fd) < 0) { + zc_error("close fail, maybe cause by write, errno[%d]", errno); + return -1; + } + + return 0; +} + +static int zlog_rule_output_dynamic_file_rotate(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + int fd; + char *path; + size_t len; + struct zlog_stat info; + + zlog_rule_gen_path(a_rule, a_thread); + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_output fail"); + return -1; + } + + path = zlog_buf_str(a_thread->path_buf); + fd = open(path, a_rule->file_open_flags | O_WRONLY | O_APPEND | O_CREAT, a_rule->file_perms); + if (fd < 0) { + zc_error("open file[%s] fail, errno[%d]", zlog_buf_str(a_thread->path_buf), errno); + return -1; + } + + len = zlog_buf_len(a_thread->msg_buf); + if (write(fd, zlog_buf_str(a_thread->msg_buf), len) < 0) { + zc_error("write fail, errno[%d]", errno); + close(fd); + return -1; + } + + if (a_rule->fsync_period && ++a_rule->fsync_count >= a_rule->fsync_period) { + a_rule->fsync_count = 0; + if (fsync(fd)) zc_error("fsync[%d] fail, errno[%d]", fd, errno); + } + + if (close(fd) < 0) { + zc_error("write fail, maybe cause by write, errno[%d]", errno); + return -1; + } + + if (len > a_rule->archive_max_size) { + zc_debug("one msg's len[%ld] > archive_max_size[%ld], no rotate", + (long)len, (long) a_rule->archive_max_size); + return 0; + } + + if (stat(path, &info)) { + zc_warn("stat [%s] fail, errno[%d], maybe in rotating", path, errno); + return 0; + } + + /* file not so big, return */ + if (info.st_size + len < a_rule->archive_max_size) return 0; + + if (zlog_rotater_rotate(zlog_env_conf->rotater, + path, len, + zlog_rule_gen_archive_path(a_rule, a_thread), + a_rule->archive_max_size, a_rule->archive_max_count) + ) { + zc_error("zlog_rotater_rotate fail"); + return -1; + } /* success or no rotation do nothing */ + + return 0; +} + +static int zlog_rule_output_pipe(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + if (write(a_rule->pipe_fd, + zlog_buf_str(a_thread->msg_buf), + zlog_buf_len(a_thread->msg_buf)) < 0) { + zc_error("write fail, errno[%d]", errno); + return -1; + } + + return 0; +} + +static int zlog_rule_output_syslog(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + zlog_level_t *a_level; + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + /* + msg = a_thread->msg_buf->start; + msg_len = a_thread->msg_buf->end - a_thread->msg_buf->start; + */ + + a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level); + zlog_buf_seal(a_thread->msg_buf); + syslog(a_rule->syslog_facility | a_level->syslog_level, + "%s", zlog_buf_str(a_thread->msg_buf)); + return 0; +} + +static int zlog_rule_output_static_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + zlog_msg_t msg; + + if (!a_rule->record_func) { + zc_error("user defined record funcion for [%s] not set, no output", + a_rule->record_name); + return -1; + } + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + zlog_buf_seal(a_thread->msg_buf); + + msg.buf = zlog_buf_str(a_thread->msg_buf); + msg.len = zlog_buf_len(a_thread->msg_buf); + msg.path = a_rule->record_path; + + if (a_rule->record_func(&msg)) { + zc_error("a_rule->record fail"); + return -1; + } + return 0; +} + +static int zlog_rule_output_dynamic_record(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + zlog_msg_t msg; + + if (!a_rule->record_func) { + zc_error("user defined record funcion for [%s] not set, no output", + a_rule->record_name); + return -1; + } + + zlog_rule_gen_path(a_rule, a_thread); + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + zlog_buf_seal(a_thread->msg_buf); + + msg.buf = zlog_buf_str(a_thread->msg_buf); + msg.len = zlog_buf_len(a_thread->msg_buf); + msg.path = zlog_buf_str(a_thread->path_buf); + + if (a_rule->record_func(&msg)) { + zc_error("a_rule->record fail"); + return -1; + } + return 0; +} + +static int zlog_rule_output_stdout(zlog_rule_t * a_rule, + zlog_thread_t * a_thread) +{ + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + if (write(STDOUT_FILENO, + zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { + zc_error("write fail, errno[%d]", errno); + return -1; + } + + return 0; +} + +static int zlog_rule_output_stderr(zlog_rule_t * a_rule, + zlog_thread_t * a_thread) +{ + + if (zlog_format_gen_msg(a_rule->format, a_thread)) { + zc_error("zlog_format_gen_msg fail"); + return -1; + } + + if (write(STDERR_FILENO, + zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg_buf)) < 0) { + zc_error("write fail, errno[%d]", errno); + return -1; + } + + return 0; +} +/*******************************************************************************/ +static int syslog_facility_atoi(char *facility) +{ + /* guess no unix system will choose -187 + * as its syslog facility, so it is a safe return value + */ + zc_assert(facility, -187); + + if (STRICMP(facility, ==, "LOG_LOCAL0")) return LOG_LOCAL0; + if (STRICMP(facility, ==, "LOG_LOCAL1")) return LOG_LOCAL1; + if (STRICMP(facility, ==, "LOG_LOCAL2")) return LOG_LOCAL2; + if (STRICMP(facility, ==, "LOG_LOCAL3")) return LOG_LOCAL3; + if (STRICMP(facility, ==, "LOG_LOCAL4")) return LOG_LOCAL4; + if (STRICMP(facility, ==, "LOG_LOCAL5")) return LOG_LOCAL5; + if (STRICMP(facility, ==, "LOG_LOCAL6")) return LOG_LOCAL6; + if (STRICMP(facility, ==, "LOG_LOCAL7")) return LOG_LOCAL7; + if (STRICMP(facility, ==, "LOG_USER")) return LOG_USER; + if (STRICMP(facility, ==, "LOG_AUTHPRIV")) return LOG_AUTHPRIV; + if (STRICMP(facility, ==, "LOG_CRON")) return LOG_CRON; + if (STRICMP(facility, ==, "LOG_DAEMON")) return LOG_DAEMON; + if (STRICMP(facility, ==, "LOG_FTP")) return LOG_FTP; + if (STRICMP(facility, ==, "LOG_KERN")) return LOG_KERN; + if (STRICMP(facility, ==, "LOG_LPR")) return LOG_LPR; + if (STRICMP(facility, ==, "LOG_MAIL")) return LOG_MAIL; + if (STRICMP(facility, ==, "LOG_NEWS")) return LOG_NEWS; + if (STRICMP(facility, ==, "LOG_SYSLOG")) return LOG_SYSLOG; + return LOG_AUTHPRIV; + + zc_error("wrong syslog facility[%s], must in LOG_LOCAL[0-7] or LOG_USER", facility); + return -187; +} + +static int zlog_rule_parse_path(char *path_start, /* start with a " */ + char *path_str, size_t path_size, zc_arraylist_t **path_specs, + int *time_cache_count) +{ + char *p, *q; + size_t len; + zlog_spec_t *a_spec; + zc_arraylist_t *specs; + + p = path_start + 1; + + q = strrchr(p, '"'); + if (!q) { + zc_error("matching \" not found in conf line[%s]", path_start); + return -1; + } + len = q - p; + if (len > path_size - 1) { + zc_error("file_path too long %ld > %ld", len, path_size - 1); + return -1; + } + memcpy(path_str, p, len); + + /* replace any environment variables like %E(HOME) */ + if (zc_str_replace_env(path_str, path_size)) { + zc_error("zc_str_replace_env fail"); + return -1; + } + + if (strchr(path_str, '%') == NULL) { + /* static, no need create specs */ + return 0; + } + + specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del); + if (!path_specs) { + zc_error("zc_arraylist_new fail"); + return -1; + } + + for (p = path_str; *p != '\0'; p = q) { + a_spec = zlog_spec_new(p, &q, time_cache_count); + if (!a_spec) { + zc_error("zlog_spec_new fail"); + goto err; + } + + if (zc_arraylist_add(specs, a_spec)) { + zc_error("zc_arraylist_add fail"); + goto err; + } + } + + *path_specs = specs; + return 0; +err: + if (specs) zc_arraylist_del(specs); + if (a_spec) zlog_spec_del(a_spec); + return -1; +} + +zlog_rule_t *zlog_rule_new(char *line, + zc_arraylist_t *levels, + zlog_format_t * default_format, + zc_arraylist_t * formats, + unsigned int file_perms, + size_t fsync_period, + int * time_cache_count) +{ + int rc = 0; + int nscan = 0; + int nread = 0; + zlog_rule_t *a_rule; + + char selector[MAXLEN_CFG_LINE + 1]; + char category[MAXLEN_CFG_LINE + 1]; + char level[MAXLEN_CFG_LINE + 1]; + + char *action; + char output[MAXLEN_CFG_LINE + 1]; + char format_name[MAXLEN_CFG_LINE + 1]; + char file_path[MAXLEN_CFG_LINE + 1]; + char archive_max_size[MAXLEN_CFG_LINE + 1]; + char *file_limit; + + char *p; + char *q; + size_t len; + + zc_assert(line, NULL); + zc_assert(default_format, NULL); + zc_assert(formats, NULL); + + a_rule = calloc(1, sizeof(zlog_rule_t)); + if (!a_rule) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_rule->file_perms = file_perms; + a_rule->fsync_period = fsync_period; + + /* line [f.INFO "%H/log/aa.log", 20MB * 12; MyTemplate] + * selector [f.INFO] + * *action ["%H/log/aa.log", 20MB * 12; MyTemplate] + */ + memset(&selector, 0x00, sizeof(selector)); + nscan = sscanf(line, "%s %n", selector, &nread); + if (nscan != 1) { + zc_error("sscanf [%s] fail, selector", line); + goto err; + } + action = line + nread; + + /* + * selector [f.INFO] + * category [f] + * level [.INFO] + */ + memset(category, 0x00, sizeof(category)); + memset(level, 0x00, sizeof(level)); + nscan = sscanf(selector, " %[^.].%s", category, level); + if (nscan != 2) { + zc_error("sscanf [%s] fail, category or level is null", + selector); + goto err; + } + + /* check and set category */ + for (p = category; *p != '\0'; p++) { + if ((!isalnum(*p)) && (*p != '_') && (*p != '-') && (*p != '*') && (*p != '!')) { + zc_error("category name[%s] character is not in [a-Z][0-9][_!*-]", category); + goto err; + } + } + + /* as one line can't be longer than MAXLEN_CFG_LINE, same as category */ + strcpy(a_rule->category, category); + + /* check and set level */ + switch (level[0]) { + case '=': + /* aa.=debug */ + a_rule->compare_char = '='; + p = level + 1; + break; + case '!': + /* aa.!debug */ + a_rule->compare_char = '!'; + p = level + 1; + break; + case '*': + /* aa.* */ + a_rule->compare_char = '*'; + p = level; + break; + default: + /* aa.debug */ + a_rule->compare_char = '.'; + p = level; + break; + } + + a_rule->level = zlog_level_list_atoi(levels, p); + + /* level_bit is a bitmap represents which level can be output + * 32bytes, [0-255] levels, see level.c + * which bit field is 1 means allow output and 0 not + */ + switch (a_rule->compare_char) { + case '=': + memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap)); + a_rule->level_bitmap[a_rule->level / 8] |= (1 << (7 - a_rule->level % 8)); + break; + case '!': + memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap)); + a_rule->level_bitmap[a_rule->level / 8] &= ~(1 << (7 - a_rule->level % 8)); + break; + case '*': + memset(a_rule->level_bitmap, 0xFF, sizeof(a_rule->level_bitmap)); + break; + case '.': + memset(a_rule->level_bitmap, 0x00, sizeof(a_rule->level_bitmap)); + a_rule->level_bitmap[a_rule->level / 8] |= ~(0xFF << (8 - a_rule->level % 8)); + memset(a_rule->level_bitmap + a_rule->level / 8 + 1, 0xFF, + sizeof(a_rule->level_bitmap) - a_rule->level / 8 - 1); + break; + } + + /* action ["%H/log/aa.log", 20MB * 12 ; MyTemplate] + * output ["%H/log/aa.log", 20MB * 12] + * format [MyTemplate] + */ + memset(output, 0x00, sizeof(output)); + memset(format_name, 0x00, sizeof(format_name)); + nscan = sscanf(action, " %[^;];%s", output, format_name); + if (nscan < 1) { + zc_error("sscanf [%s] fail", action); + goto err; + } + + /* check and get format */ + if (STRCMP(format_name, ==, "")) { + zc_debug("no format specified, use default"); + a_rule->format = default_format; + } else { + int i; + int find_flag = 0; + zlog_format_t *a_format; + + zc_arraylist_foreach(formats, i, a_format) { + if (zlog_format_has_name(a_format, format_name)) { + a_rule->format = a_format; + find_flag = 1; + break; + } + } + if (!find_flag) { + zc_error("in conf file can't find format[%s], pls check", + format_name); + goto err; + } + } + + /* output [-"%E(HOME)/log/aa.log" , 20MB*12] [>syslog , LOG_LOCAL0 ] + * file_path [-"%E(HOME)/log/aa.log" ] [>syslog ] + * *file_limit [20MB * 12 ~ "aa.#i.log" ] [LOG_LOCAL0] + */ + memset(file_path, 0x00, sizeof(file_path)); + nscan = sscanf(output, " %[^,],", file_path); + if (nscan < 1) { + zc_error("sscanf [%s] fail", action); + goto err; + } + + file_limit = strchr(output, ','); + if (file_limit) { + file_limit++; /* skip the , */ + while( isspace(*file_limit) ) { + file_limit++; + } + } + + p = NULL; + switch (file_path[0]) { + case '-' : + /* sync file each time write log */ + if (file_path[1] != '"') { + zc_error(" - must set before a file output"); + goto err; + } + + /* no need to fsync, as file is opened by O_SYNC, write immediately */ + a_rule->fsync_period = 0; + + p = file_path + 1; + a_rule->file_open_flags = O_SYNC; + /* fall through */ + case '"' : + if (!p) p = file_path; + + rc = zlog_rule_parse_path(p, a_rule->file_path, sizeof(a_rule->file_path), + &(a_rule->dynamic_specs), time_cache_count); + if (rc) { + zc_error("zlog_rule_parse_path fail"); + goto err; + } + + if (file_limit) { + memset(archive_max_size, 0x00, sizeof(archive_max_size)); + nscan = sscanf(file_limit, " %[0-9MmKkBb] * %d ~", + archive_max_size, &(a_rule->archive_max_count)); + if (nscan) { + a_rule->archive_max_size = zc_parse_byte_size(archive_max_size); + } + p = strchr(file_limit, '"'); + if (p) { /* archive file path exist */ + rc = zlog_rule_parse_path(p, + a_rule->archive_path, sizeof(a_rule->file_path), + &(a_rule->archive_specs), time_cache_count); + if (rc) { + zc_error("zlog_rule_parse_path fail"); + goto err; + } + + p = strchr(a_rule->archive_path, '#'); + if ( (p == NULL) || ((strchr(p, 'r') == NULL) && (strchr(p, 's') == NULL))) { + zc_error("archive_path must contain #r or #s"); + goto err; + } + } + } + + /* try to figure out if the log file path is dynamic or static */ + if (a_rule->dynamic_specs) { + if (a_rule->archive_max_size <= 0) { + a_rule->output = zlog_rule_output_dynamic_file_single; + } else { + a_rule->output = zlog_rule_output_dynamic_file_rotate; + } + } else { + struct stat stb; + + if (a_rule->archive_max_size <= 0) { + a_rule->output = zlog_rule_output_static_file_single; + } else { + /* as rotate, so need to reopen everytime */ + a_rule->output = zlog_rule_output_static_file_rotate; + } + + a_rule->static_fd = open(a_rule->file_path, + O_WRONLY | O_APPEND | O_CREAT | a_rule->file_open_flags, + a_rule->file_perms); + if (a_rule->static_fd < 0) { + zc_error("open file[%s] fail, errno[%d]", a_rule->file_path, errno); + goto err; + } + + /* save off the inode information for checking for a changed file later on */ + if (fstat(a_rule->static_fd, &stb)) { + zc_error("stat [%s] fail, errno[%d], failing to open static_fd", a_rule->file_path, errno); + goto err; + } + + if (a_rule->archive_max_size > 0) { + close(a_rule->static_fd); + a_rule->static_fd = -1; + } + + a_rule->static_dev = stb.st_dev; + a_rule->static_ino = stb.st_ino; + } + break; + case '|' : + a_rule->pipe_fp = popen(output + 1, "w"); + if (!a_rule->pipe_fp) { + zc_error("popen fail, errno[%d]", errno); + goto err; + } + a_rule->pipe_fd = fileno(a_rule->pipe_fp); + if (a_rule->pipe_fd < 0 ) { + zc_error("fileno fail, errno[%d]", errno); + goto err; + } + a_rule->output = zlog_rule_output_pipe; + break; + case '>' : + if (STRNCMP(file_path + 1, ==, "syslog", 6)) { + a_rule->syslog_facility = syslog_facility_atoi(file_limit); + if (a_rule->syslog_facility == -187) { + zc_error("-187 get"); + goto err; + } + a_rule->output = zlog_rule_output_syslog; + openlog(NULL, LOG_NDELAY | LOG_NOWAIT | LOG_PID, LOG_USER); + } else if (STRNCMP(file_path + 1, ==, "stdout", 6)) { + a_rule->output = zlog_rule_output_stdout; + } else if (STRNCMP(file_path + 1, ==, "stderr", 6)) { + a_rule->output = zlog_rule_output_stderr; + } else { + zc_error + ("[%s]the string after is not syslog, stdout or stderr", output); + goto err; + } + break; + case '$' : + sscanf(file_path + 1, "%s", a_rule->record_name); + + if (file_limit) { /* record path exists */ + p = strchr(file_limit, '"'); + if (!p) { + zc_error("record_path not start with \", [%s]", file_limit); + goto err; + } + p++; /* skip 1st " */ + + q = strrchr(p, '"'); + if (!q) { + zc_error("matching \" not found in conf line[%s]", p); + goto err; + } + len = q - p; + if (len > sizeof(a_rule->record_path) - 1) { + zc_error("record_path too long %ld > %ld", len, sizeof(a_rule->record_path) - 1); + goto err; + } + memcpy(a_rule->record_path, p, len); + } + + /* replace any environment variables like %E(HOME) */ + rc = zc_str_replace_env(a_rule->record_path, sizeof(a_rule->record_path)); + if (rc) { + zc_error("zc_str_replace_env fail"); + goto err; + } + + /* try to figure out if the log file path is dynamic or static */ + if (strchr(a_rule->record_path, '%') == NULL) { + a_rule->output = zlog_rule_output_static_record; + } else { + zlog_spec_t *a_spec; + + a_rule->output = zlog_rule_output_dynamic_record; + + a_rule->dynamic_specs = zc_arraylist_new((zc_arraylist_del_fn)zlog_spec_del); + if (!(a_rule->dynamic_specs)) { + zc_error("zc_arraylist_new fail"); + goto err; + } + for (p = a_rule->record_path; *p != '\0'; p = q) { + a_spec = zlog_spec_new(p, &q, time_cache_count); + if (!a_spec) { + zc_error("zlog_spec_new fail"); + goto err; + } + + rc = zc_arraylist_add(a_rule->dynamic_specs, a_spec); + if (rc) { + zlog_spec_del(a_spec); + zc_error("zc_arraylist_add fail"); + goto err; + } + } + } + break; + default : + zc_error("the 1st char[%c] of file_path[%s] is wrong", + file_path[0], file_path); + goto err; + } + + return a_rule; +err: + zlog_rule_del(a_rule); + return NULL; +} + +void zlog_rule_del(zlog_rule_t * a_rule) +{ + zc_assert(a_rule,); + if (a_rule->dynamic_specs) { + zc_arraylist_del(a_rule->dynamic_specs); + a_rule->dynamic_specs = NULL; + } + if (a_rule->static_fd) { + if (close(a_rule->static_fd)) { + zc_error("close fail, maybe cause by write, errno[%d]", errno); + } + } + if (a_rule->pipe_fp) { + if (pclose(a_rule->pipe_fp) == -1) { + zc_error("pclose fail, errno[%d]", errno); + } + } + if (a_rule->archive_specs) { + zc_arraylist_del(a_rule->archive_specs); + a_rule->archive_specs = NULL; + } + zc_debug("zlog_rule_del[%p]", a_rule); + free(a_rule); + return; +} + +/*******************************************************************************/ +int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread) +{ + switch (a_rule->compare_char) { + case '*' : + return a_rule->output(a_rule, a_thread); + break; + case '.' : + if (a_thread->event->level >= a_rule->level) { + return a_rule->output(a_rule, a_thread); + } else { + return 0; + } + break; + case '=' : + if (a_thread->event->level == a_rule->level) { + return a_rule->output(a_rule, a_thread); + } else { + return 0; + } + break; + case '!' : + if (a_thread->event->level != a_rule->level) { + return a_rule->output(a_rule, a_thread); + } else { + return 0; + } + break; + } + + return 0; +} + +/*******************************************************************************/ +int zlog_rule_is_wastebin(zlog_rule_t * a_rule) +{ + zc_assert(a_rule, -1); + + if (STRCMP(a_rule->category, ==, "!")) { + return 1; + } + + return 0; +} + +/*******************************************************************************/ +int zlog_rule_match_category(zlog_rule_t * a_rule, char *category) +{ + zc_assert(a_rule, -1); + zc_assert(category, -1); + + if (STRCMP(a_rule->category, ==, "*")) { + /* '*' match anything, so go on */ + return 1; + } else if (STRCMP(a_rule->category, ==, category)) { + /* accurate compare */ + return 1; + } else { + /* aa_ match aa_xx & aa, but not match aa1_xx */ + size_t len; + len = strlen(a_rule->category); + + if (a_rule->category[len - 1] == '_') { + if (strlen(category) == len - 1) { + len--; + } + + if (STRNCMP(a_rule->category, ==, category, len)) { + return 1; + } + } + } + + return 0; +} + +/*******************************************************************************/ + +int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records) +{ + zlog_record_t *a_record; + + if (a_rule->output != zlog_rule_output_static_record + && a_rule->output != zlog_rule_output_dynamic_record) { + return 0; /* fliter, may go through not record rule */ + } + + a_record = zc_hashtable_get(records, a_rule->record_name); + if (a_record) { + a_rule->record_func = a_record->output; + } + return 0; +} diff --git a/zlog/rule.h b/zlog/rule.h new file mode 100644 index 0000000..e562185 --- /dev/null +++ b/zlog/rule.h @@ -0,0 +1,88 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +/** + * @file rule.h + * @brief rule decide to output in format by category & level + */ + +#ifndef __zlog_rule_h +#define __zlog_rule_h + +#include +#include + +#include "zc_defs.h" +#include "format.h" +#include "thread.h" +#include "rotater.h" +#include "record.h" + +typedef struct zlog_rule_s zlog_rule_t; + +typedef int (*zlog_rule_output_fn) (zlog_rule_t * a_rule, zlog_thread_t * a_thread); + +struct zlog_rule_s { + char category[MAXLEN_CFG_LINE + 1]; + char compare_char; + /* + * [*] log all level + * [.] log level >= rule level, default + * [=] log level == rule level + * [!] log level != rule level + */ + int level; + unsigned char level_bitmap[32]; /* for category determine whether ouput or not */ + + unsigned int file_perms; + int file_open_flags; + + char file_path[MAXLEN_PATH + 1]; + zc_arraylist_t *dynamic_specs; + int static_fd; + dev_t static_dev; + ino_t static_ino; + + long archive_max_size; + int archive_max_count; + char archive_path[MAXLEN_PATH + 1]; + zc_arraylist_t *archive_specs; + + FILE *pipe_fp; + int pipe_fd; + + size_t fsync_period; + size_t fsync_count; + + zc_arraylist_t *levels; + int syslog_facility; + + zlog_format_t *format; + zlog_rule_output_fn output; + + char record_name[MAXLEN_PATH + 1]; + char record_path[MAXLEN_PATH + 1]; + zlog_record_fn record_func; +}; + +zlog_rule_t *zlog_rule_new(char * line, + zc_arraylist_t * levels, + zlog_format_t * default_format, + zc_arraylist_t * formats, + unsigned int file_perms, + size_t fsync_period, + int * time_cache_count); + +void zlog_rule_del(zlog_rule_t * a_rule); +void zlog_rule_profile(zlog_rule_t * a_rule, int flag); +int zlog_rule_match_category(zlog_rule_t * a_rule, char *category); +int zlog_rule_is_wastebin(zlog_rule_t * a_rule); +int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records); +int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread); + +#endif diff --git a/zlog/spec.c b/zlog/spec.c new file mode 100644 index 0000000..b047605 --- /dev/null +++ b/zlog/spec.c @@ -0,0 +1,659 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conf.h" +#include "spec.h" +#include "level_list.h" +#include "zc_defs.h" + + +#define ZLOG_DEFAULT_TIME_FMT "%F %T" +#define ZLOG_HEX_HEAD \ + "\n 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF" + +/*******************************************************************************/ +void zlog_spec_profile(zlog_spec_t * a_spec, int flag) +{ + zc_assert(a_spec,); + zc_profile(flag, "----spec[%p][%.*s][%s|%d][%s,%ld,%ld,%s][%s]----", + a_spec, + a_spec->len, a_spec->str, + a_spec->time_fmt, + a_spec->time_cache_index, + a_spec->print_fmt, (long)a_spec->max_width, (long)a_spec->min_width, a_spec->left_fill_zeros ? "true" : "false", + a_spec->mdc_key); + return; +} + +/*******************************************************************************/ +/* implementation of write function */ + +static int zlog_spec_write_time(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + zlog_time_cache_t * a_cache = a_thread->event->time_caches + a_spec->time_cache_index; + time_t now_sec = a_thread->event->time_stamp.tv_sec; + struct tm *time_local = &(a_thread->event->time_local); + + /* the event meet the 1st time_spec in his life cycle */ + if (!now_sec) { + gettimeofday(&(a_thread->event->time_stamp), NULL); + now_sec = a_thread->event->time_stamp.tv_sec; + } + + /* When this event's last cached time_local is not now */ + if (a_thread->event->time_local_sec != now_sec) { + localtime_r(&(now_sec), time_local); + a_thread->event->time_local_sec = now_sec; + } + + /* When this spec's last cache time string is not now */ + if (a_cache->sec != now_sec) { + a_cache->len = strftime(a_cache->str, sizeof(a_cache->str), a_spec->time_fmt, time_local); + a_cache->sec = now_sec; + } + + return zlog_buf_append(a_buf, a_cache->str, a_cache->len); +} + +#if 0 +static int zlog_spec_write_time_D(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (!a_thread->event->time_stamp.tv_sec) { + gettimeofday(&(a_thread->event->time_stamp), NULL); + } + + /* + * It is modified when time slips one second. + * So it is a strong cache, as Default time format is always %F %T. + * That's why I said %D is faster than %d() + */ + if (a_thread->event->time_stamp.tv_sec != a_thread->event->time_last_D) { + + a_thread->event->time_last_D = a_thread->event->time_stamp.tv_sec; + localtime_r(&(a_thread->event->time_stamp.tv_sec), + &(a_thread->event->time_local)); + + strftime(a_thread->event->time_cache_D, + sizeof(a_thread->event->time_cache_D), + ZLOG_DEFAULT_TIME_FMT, &(a_thread->event->time_local) ); + } + return zlog_buf_append(a_buf, a_thread->event->time_cache_D, sizeof(a_thread->event->time_cache_D) - 1); +} +#endif + +static int zlog_spec_write_ms(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (!a_thread->event->time_stamp.tv_sec) { + gettimeofday(&(a_thread->event->time_stamp), NULL); + } + return zlog_buf_printf_dec32(a_buf, (a_thread->event->time_stamp.tv_usec / 1000), 3); +} + +static int zlog_spec_write_us(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (!a_thread->event->time_stamp.tv_sec) { + gettimeofday(&(a_thread->event->time_stamp), NULL); + } + return zlog_buf_printf_dec32(a_buf, a_thread->event->time_stamp.tv_usec, 6); +} + +static int zlog_spec_write_mdc(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + zlog_mdc_kv_t *a_mdc_kv; + + a_mdc_kv = zlog_mdc_get_kv(a_thread->mdc, a_spec->mdc_key); + if (!a_mdc_kv) { + zc_error("zlog_mdc_get_kv key[%s] fail", a_spec->mdc_key); + return 0; + } + + return zlog_buf_append(a_buf, a_mdc_kv->value, a_mdc_kv->value_len); +} + +static int zlog_spec_write_str(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + return zlog_buf_append(a_buf, a_spec->str, a_spec->len); +} + +static int zlog_spec_write_category(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + return zlog_buf_append(a_buf, a_thread->event->category_name, a_thread->event->category_name_len); +} + +static int zlog_spec_write_srcfile(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (!a_thread->event->file) { + return zlog_buf_append(a_buf, "(file=null)", sizeof("(file=null)") - 1); + } else { + return zlog_buf_append(a_buf, a_thread->event->file, a_thread->event->file_len); + } +} + +static int zlog_spec_write_srcfile_neat(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + char *p; + + if ((p = strrchr(a_thread->event->file, '/')) != NULL) { + return zlog_buf_append(a_buf, p + 1, + (char*)a_thread->event->file + a_thread->event->file_len - p - 1); + } else { + if (!a_thread->event->file) { + return zlog_buf_append(a_buf, "(file=null)", sizeof("(file=null)") - 1); + } else { + return zlog_buf_append(a_buf, a_thread->event->file, a_thread->event->file_len); + } + } +} + +static int zlog_spec_write_srcline(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + + return zlog_buf_printf_dec64(a_buf, a_thread->event->line, 0); +} + +static int zlog_spec_write_srcfunc(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (!a_thread->event->file) { + return zlog_buf_append(a_buf, "(func=null)", sizeof("(func=null)") - 1); + } else { + return zlog_buf_append(a_buf, a_thread->event->func, a_thread->event->func_len); + } +} + + +static int zlog_spec_write_hostname(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + return zlog_buf_append(a_buf, a_thread->event->host_name, a_thread->event->host_name_len); +} + +static int zlog_spec_write_newline(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + return zlog_buf_append(a_buf, FILE_NEWLINE, FILE_NEWLINE_LEN); +} + +static int zlog_spec_write_percent(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + return zlog_buf_append(a_buf, "%", 1); +} + +static int zlog_spec_write_pid(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + /* 1st in event lifecycle */ + if (!a_thread->event->pid) { + a_thread->event->pid = getpid(); + + /* compare with previous event */ + if (a_thread->event->pid != a_thread->event->last_pid) { + a_thread->event->last_pid = a_thread->event->pid; + a_thread->event->pid_str_len + = sprintf(a_thread->event->pid_str, "%u", a_thread->event->pid); + } + } + + return zlog_buf_append(a_buf, a_thread->event->pid_str, a_thread->event->pid_str_len); +} + +static int zlog_spec_write_tid_hex(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + + /* don't need to get tid again, as tmap_new_thread fetched it already */ + /* and fork not change tid */ + return zlog_buf_append(a_buf, a_thread->event->tid_hex_str, a_thread->event->tid_hex_str_len); +} + +static int zlog_spec_write_tid_long(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + + /* don't need to get tid again, as tmap_new_thread fetched it already */ + /* and fork not change tid */ + return zlog_buf_append(a_buf, a_thread->event->tid_str, a_thread->event->tid_str_len); +} + +static int zlog_spec_write_ktid(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + + /* don't need to get ktid again, as tmap_new_thread fetched it already */ + /* and fork not change tid */ + return zlog_buf_append(a_buf, a_thread->event->ktid_str, a_thread->event->ktid_str_len); +} + +static int zlog_spec_write_level_lowercase(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + zlog_level_t *a_level; + + a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level); + return zlog_buf_append(a_buf, a_level->str_lowercase, a_level->str_len); +} + +static int zlog_spec_write_level_uppercase(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + zlog_level_t *a_level; + + a_level = zlog_level_list_get(zlog_env_conf->levels, a_thread->event->level); + return zlog_buf_append(a_buf, a_level->str_uppercase, a_level->str_len); +} + +static int zlog_spec_write_usrmsg(zlog_spec_t * a_spec, zlog_thread_t * a_thread, zlog_buf_t * a_buf) +{ + if (a_thread->event->generate_cmd == ZLOG_FMT) { + if (a_thread->event->str_format) { + return zlog_buf_vprintf(a_buf, + a_thread->event->str_format, + a_thread->event->str_args); + } else { + return zlog_buf_append(a_buf, "format=(null)", sizeof("format=(null)")-1); + } + } else if (a_thread->event->generate_cmd == ZLOG_HEX) { + int rc; + long line_offset; + long byte_offset; + + /* thread buf start == null or len <= 0 */ + if (a_thread->event->hex_buf == NULL) { + rc = zlog_buf_append(a_buf, "buf=(null)", sizeof("buf=(null)")-1); + goto zlog_hex_exit; + } + + rc = zlog_buf_append(a_buf, ZLOG_HEX_HEAD, sizeof(ZLOG_HEX_HEAD)-1); + if (rc) { + goto zlog_hex_exit; + } + + line_offset = 0; + //byte_offset = 0; + + while (1) { + unsigned char c; + + rc = zlog_buf_append(a_buf, "\n", 1); + if (rc) goto zlog_hex_exit; + + rc = zlog_buf_printf_dec64(a_buf, line_offset + 1, 10); + if (rc) goto zlog_hex_exit; + rc = zlog_buf_append(a_buf, " ", 3); + if (rc) goto zlog_hex_exit; + + for (byte_offset = 0; byte_offset < 16; byte_offset++) { + if (line_offset * 16 + byte_offset < a_thread->event->hex_buf_len) { + c = *((unsigned char *)a_thread->event->hex_buf + + line_offset * 16 + byte_offset); + rc = zlog_buf_printf_hex(a_buf, c, 2); + if (rc) goto zlog_hex_exit; + rc = zlog_buf_append(a_buf, " ", 1); + if (rc) goto zlog_hex_exit; + } else { + rc = zlog_buf_append(a_buf, " ", 3); + if (rc) goto zlog_hex_exit; + } + } + + rc = zlog_buf_append(a_buf, " ", 2); + if (rc) goto zlog_hex_exit; + + for (byte_offset = 0; byte_offset < 16; byte_offset++) { + if (line_offset * 16 + byte_offset < a_thread->event->hex_buf_len) { + c = *((unsigned char *)a_thread->event->hex_buf + + line_offset * 16 + byte_offset); + if (c >= 32 && c <= 126) { + rc = zlog_buf_append(a_buf,(char*)&c, 1); + if (rc) goto zlog_hex_exit; + } else { + rc = zlog_buf_append(a_buf, ".", 1); + if (rc) goto zlog_hex_exit; + } + } else { + rc = zlog_buf_append(a_buf, " ", 1); + if (rc) goto zlog_hex_exit; + } + } + + if (line_offset * 16 + byte_offset >= a_thread->event->hex_buf_len) { + break; + } + + line_offset++; + } + + zlog_hex_exit: + if (rc < 0) { + zc_error("write hex msg fail"); + return -1; + } else if (rc > 0) { + zc_error("write hex msg, buf is full"); + return 1; + } + + return 0; + } + + return 0; +} + +/*******************************************************************************/ +/* implementation of gen function */ + +static int zlog_spec_gen_msg_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + /* no need to reprint %1.2d here */ + return a_spec->write_buf(a_spec, a_thread, a_thread->msg_buf); +} + +static int zlog_spec_gen_msg_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + int rc; + + zlog_buf_restart(a_thread->pre_msg_buf); + + rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_msg_buf); + if (rc < 0) { + zc_error("a_spec->gen_buf fail"); + return -1; + } else if (rc > 0) { + /* buf is full, try printf */ + } + + return zlog_buf_adjust_append(a_thread->msg_buf, + zlog_buf_str(a_thread->pre_msg_buf), zlog_buf_len(a_thread->pre_msg_buf), + a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width); +} + +/*******************************************************************************/ +static int zlog_spec_gen_path_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + /* no need to reprint %1.2d here */ + return a_spec->write_buf(a_spec, a_thread, a_thread->path_buf); +} + +static int zlog_spec_gen_path_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + int rc; + + zlog_buf_restart(a_thread->pre_path_buf); + + rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_path_buf); + if (rc < 0) { + zc_error("a_spec->gen_buf fail"); + return -1; + } else if (rc > 0) { + /* buf is full, try printf */ + } + + return zlog_buf_adjust_append(a_thread->path_buf, + zlog_buf_str(a_thread->pre_path_buf), zlog_buf_len(a_thread->pre_path_buf), + a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width); +} + +/*******************************************************************************/ +static int zlog_spec_gen_archive_path_direct(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + /* no need to reprint %1.2d here */ + return a_spec->write_buf(a_spec, a_thread, a_thread->archive_path_buf); +} + +static int zlog_spec_gen_archive_path_reformat(zlog_spec_t * a_spec, zlog_thread_t * a_thread) +{ + int rc; + + zlog_buf_restart(a_thread->pre_path_buf); + + rc = a_spec->write_buf(a_spec, a_thread, a_thread->pre_path_buf); + if (rc < 0) { + zc_error("a_spec->gen_buf fail"); + return -1; + } else if (rc > 0) { + /* buf is full, try printf */ + } + + return zlog_buf_adjust_append(a_thread->archive_path_buf, + zlog_buf_str(a_thread->pre_path_buf), zlog_buf_len(a_thread->pre_path_buf), + a_spec->left_adjust, a_spec->left_fill_zeros, a_spec->min_width, a_spec->max_width); +} + +/*******************************************************************************/ +static int zlog_spec_parse_print_fmt(zlog_spec_t * a_spec) +{ + /* -12.35 12 .35 */ + char *p, *q; + long i, j; + + p = a_spec->print_fmt; + if (*p == '-') { + a_spec->left_adjust = 1; + p++; + } else { + if (*p == '0') { + a_spec->left_fill_zeros = 1; + } + a_spec->left_adjust = 0; + } + + i = j = 0; + sscanf(p, "%ld.", &i); + q = strchr(p, '.'); + if (q) sscanf(q, ".%ld", &j); + + a_spec->min_width = (size_t) i; + a_spec->max_width = (size_t) j; + return 0; +} + +/*******************************************************************************/ +void zlog_spec_del(zlog_spec_t * a_spec) +{ + zc_assert(a_spec,); + zc_debug("zlog_spec_del[%p]", a_spec); + free(a_spec); +} + +/* a spec may consist of + * a const string: /home/bb + * a string begin with %: %12.35d(%F %X,%l) + */ +zlog_spec_t *zlog_spec_new(char *pattern_start, char **pattern_next, int *time_cache_count) +{ + char *p; + int nscan = 0; + int nread = 0; + zlog_spec_t *a_spec; + + zc_assert(pattern_start, NULL); + zc_assert(pattern_next, NULL); + + a_spec = calloc(1, sizeof(zlog_spec_t)); + if (!a_spec) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_spec->str = p = pattern_start; + + switch (*p) { + case '%': + /* a string begin with %: %12.35d(%F %X) */ + + /* process width and precision char in %-12.35P */ + nread = 0; + nscan = sscanf(p, "%%%[.0-9-]%n", a_spec->print_fmt, &nread); + if (nscan == 1) { + a_spec->gen_msg = zlog_spec_gen_msg_reformat; + a_spec->gen_path = zlog_spec_gen_path_reformat; + a_spec->gen_archive_path = zlog_spec_gen_archive_path_reformat; + if (zlog_spec_parse_print_fmt(a_spec)) { + zc_error("zlog_spec_parse_print_fmt fail"); + goto err; + } + } else { + nread = 1; /* skip the % char */ + a_spec->gen_msg = zlog_spec_gen_msg_direct; + a_spec->gen_path = zlog_spec_gen_path_direct; + a_spec->gen_archive_path = zlog_spec_gen_archive_path_direct; + } + + p += nread; + + if (*p == 'd') { + if (*(p+1) != '(') { + /* without '(' , use default */ + strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT); + p++; + } else if (STRNCMP(p, ==, "d()", 3)) { + /* with () but without detail time format, + * keep a_spec->time_fmt=="" */ + strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT); + p += 3; + } else { + nread = 0; + nscan = sscanf(p, "d(%[^)])%n", a_spec->time_fmt, &nread); + if (nscan != 1) { + nread = 0; + } + p += nread; + if (*(p - 1) != ')') { + zc_error("in string[%s] can't find match \')\'", a_spec->str); + goto err; + } + } + + a_spec->time_cache_index = *time_cache_count; + (*time_cache_count)++; + a_spec->write_buf = zlog_spec_write_time; + + *pattern_next = p; + a_spec->len = p - a_spec->str; + break; + } + + if (*p == 'M') { + nread = 0; + nscan = sscanf(p, "M(%[^)])%n", a_spec->mdc_key, &nread); + if (nscan != 1) { + nread = 0; + if (STRNCMP(p, ==, "M()", 3)) { + nread = 3; + } + } + p += nread; + if (*(p - 1) != ')') { + zc_error("in string[%s] can't find match \')\'", a_spec->str); + goto err; + } + + *pattern_next = p; + a_spec->len = p - a_spec->str; + a_spec->write_buf = zlog_spec_write_mdc; + break; + } + + if (STRNCMP(p, ==, "ms", 2)) { + p += 2; + *pattern_next = p; + a_spec->len = p - a_spec->str; + a_spec->write_buf = zlog_spec_write_ms; + break; + } else if (STRNCMP(p, ==, "us", 2)) { + p += 2; + *pattern_next = p; + a_spec->len = p - a_spec->str; + a_spec->write_buf = zlog_spec_write_us; + break; + } + + *pattern_next = p + 1; + a_spec->len = p - a_spec->str + 1; + + switch (*p) { + case 'c': + a_spec->write_buf = zlog_spec_write_category; + break; + case 'D': + strcpy(a_spec->time_fmt, ZLOG_DEFAULT_TIME_FMT); + a_spec->time_cache_index = *time_cache_count; + (*time_cache_count)++; + a_spec->write_buf = zlog_spec_write_time; + break; + case 'F': + a_spec->write_buf = zlog_spec_write_srcfile; + break; + case 'f': + a_spec->write_buf = zlog_spec_write_srcfile_neat; + break; + case 'H': + a_spec->write_buf = zlog_spec_write_hostname; + break; + case 'k': + a_spec->write_buf = zlog_spec_write_ktid; + break; + case 'L': + a_spec->write_buf = zlog_spec_write_srcline; + break; + case 'm': + a_spec->write_buf = zlog_spec_write_usrmsg; + break; + case 'n': + a_spec->write_buf = zlog_spec_write_newline; + break; + case 'p': + a_spec->write_buf = zlog_spec_write_pid; + break; + case 'U': + a_spec->write_buf = zlog_spec_write_srcfunc; + break; + case 'v': + a_spec->write_buf = zlog_spec_write_level_lowercase; + break; + case 'V': + a_spec->write_buf = zlog_spec_write_level_uppercase; + break; + case 't': + a_spec->write_buf = zlog_spec_write_tid_hex; + break; + case 'T': + a_spec->write_buf = zlog_spec_write_tid_long; + break; + case '%': + a_spec->write_buf = zlog_spec_write_percent; + break; + default: + zc_error("str[%s] in wrong format, p[%c]", a_spec->str, *p); + goto err; + } + break; + default: + /* a const string: /home/bb */ + *pattern_next = strchr(p, '%'); + if (*pattern_next) { + a_spec->len = *pattern_next - p; + } else { + a_spec->len = strlen(p); + *pattern_next = p + a_spec->len; + } + a_spec->write_buf = zlog_spec_write_str; + a_spec->gen_msg = zlog_spec_gen_msg_direct; + a_spec->gen_path = zlog_spec_gen_path_direct; + a_spec->gen_archive_path = zlog_spec_gen_archive_path_direct; + } + + zlog_spec_profile(a_spec, ZC_DEBUG); + return a_spec; +err: + zlog_spec_del(a_spec); + return NULL; +} + diff --git a/zlog/spec.h b/zlog/spec.h new file mode 100644 index 0000000..c3d78a2 --- /dev/null +++ b/zlog/spec.h @@ -0,0 +1,60 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_spec_h +#define __zlog_spec_h + +#include "event.h" +#include "buf.h" +#include "thread.h" + +typedef struct zlog_spec_s zlog_spec_t; + +/* write buf, according to each spec's Conversion Characters */ +typedef int (*zlog_spec_write_fn) (zlog_spec_t * a_spec, + zlog_thread_t * a_thread, + zlog_buf_t * a_buf); + +/* gen a_thread->msg or gen a_thread->path by using write_fn */ +typedef int (*zlog_spec_gen_fn) (zlog_spec_t * a_spec, + zlog_thread_t * a_thread); + +struct zlog_spec_s { + char *str; + int len; + + char time_fmt[MAXLEN_CFG_LINE + 1]; + int time_cache_index; + char mdc_key[MAXLEN_PATH + 1]; + + char print_fmt[MAXLEN_CFG_LINE + 1]; + int left_adjust; + int left_fill_zeros; + size_t max_width; + size_t min_width; + + zlog_spec_write_fn write_buf; + zlog_spec_gen_fn gen_msg; + zlog_spec_gen_fn gen_path; + zlog_spec_gen_fn gen_archive_path; +}; + +zlog_spec_t *zlog_spec_new(char *pattern_start, char **pattern_end, int * time_cache_count); +void zlog_spec_del(zlog_spec_t * a_spec); +void zlog_spec_profile(zlog_spec_t * a_spec, int flag); + +#define zlog_spec_gen_msg(a_spec, a_thread) \ + a_spec->gen_msg(a_spec, a_thread) + +#define zlog_spec_gen_path(a_spec, a_thread) \ + a_spec->gen_path(a_spec, a_thread) + +#define zlog_spec_gen_archive_path(a_spec, a_thread) \ + a_spec->gen_archive_path(a_spec, a_thread) + +#endif diff --git a/zlog/thread.c b/zlog/thread.c new file mode 100644 index 0000000..3cd112c --- /dev/null +++ b/zlog/thread.c @@ -0,0 +1,184 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include + +#include "zc_defs.h" +#include "event.h" +#include "buf.h" +#include "thread.h" +#include "mdc.h" + +void zlog_thread_profile(zlog_thread_t * a_thread, int flag) +{ + zc_assert(a_thread,); + zc_profile(flag, "--thread[%p][%p][%p][%p,%p,%p,%p,%p]--", + a_thread, + a_thread->mdc, + a_thread->event, + a_thread->pre_path_buf, + a_thread->path_buf, + a_thread->archive_path_buf, + a_thread->pre_msg_buf, + a_thread->msg_buf); + + zlog_mdc_profile(a_thread->mdc, flag); + zlog_event_profile(a_thread->event, flag); + zlog_buf_profile(a_thread->pre_path_buf, flag); + zlog_buf_profile(a_thread->path_buf, flag); + zlog_buf_profile(a_thread->archive_path_buf, flag); + zlog_buf_profile(a_thread->pre_msg_buf, flag); + zlog_buf_profile(a_thread->msg_buf, flag); + return; +} +/*******************************************************************************/ +void zlog_thread_del(zlog_thread_t * a_thread) +{ + zc_assert(a_thread,); + if (a_thread->mdc) + zlog_mdc_del(a_thread->mdc); + if (a_thread->event) + zlog_event_del(a_thread->event); + if (a_thread->pre_path_buf) + zlog_buf_del(a_thread->pre_path_buf); + if (a_thread->path_buf) + zlog_buf_del(a_thread->path_buf); + if (a_thread->archive_path_buf) + zlog_buf_del(a_thread->archive_path_buf); + if (a_thread->pre_msg_buf) + zlog_buf_del(a_thread->pre_msg_buf); + if (a_thread->msg_buf) + zlog_buf_del(a_thread->msg_buf); + + zc_debug("zlog_thread_del[%p]", a_thread); + free(a_thread); + return; +} + +zlog_thread_t *zlog_thread_new(int init_version, size_t buf_size_min, size_t buf_size_max, int time_cache_count) +{ + zlog_thread_t *a_thread; + + a_thread = calloc(1, sizeof(zlog_thread_t)); + if (!a_thread) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_thread->init_version = init_version; + + a_thread->mdc = zlog_mdc_new(); + if (!a_thread->mdc) { + zc_error("zlog_mdc_new fail"); + goto err; + } + + a_thread->event = zlog_event_new(time_cache_count); + if (!a_thread->event) { + zc_error("zlog_event_new fail"); + goto err; + } + + a_thread->pre_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); + if (!a_thread->pre_path_buf) { + zc_error("zlog_buf_new fail"); + goto err; + } + + a_thread->path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); + if (!a_thread->path_buf) { + zc_error("zlog_buf_new fail"); + goto err; + } + + a_thread->archive_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); + if (!a_thread->archive_path_buf) { + zc_error("zlog_buf_new fail"); + goto err; + } + + a_thread->pre_msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); + if (!a_thread->pre_msg_buf) { + zc_error("zlog_buf_new fail"); + goto err; + } + + a_thread->msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); + if (!a_thread->msg_buf) { + zc_error("zlog_buf_new fail"); + goto err; + } + + + //zlog_thread_profile(a_thread, ZC_DEBUG); + return a_thread; +err: + zlog_thread_del(a_thread); + return NULL; +} + +/*******************************************************************************/ +int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max) +{ + zlog_buf_t *pre_msg_buf_new = NULL; + zlog_buf_t *msg_buf_new = NULL; + zc_assert(a_thread, -1); + + if ( (a_thread->msg_buf->size_min == buf_size_min) + && (a_thread->msg_buf->size_max == buf_size_max)) { + zc_debug("buf size not changed, no need rebuild"); + return 0; + } + + pre_msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); + if (!pre_msg_buf_new) { + zc_error("zlog_buf_new fail"); + goto err; + } + + msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); + if (!msg_buf_new) { + zc_error("zlog_buf_new fail"); + goto err; + } + + zlog_buf_del(a_thread->pre_msg_buf); + a_thread->pre_msg_buf = pre_msg_buf_new; + + zlog_buf_del(a_thread->msg_buf); + a_thread->msg_buf = msg_buf_new; + + return 0; +err: + if (pre_msg_buf_new) zlog_buf_del(pre_msg_buf_new); + if (msg_buf_new) zlog_buf_del(msg_buf_new); + return -1; +} + +int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count) +{ + zlog_event_t *event_new = NULL; + zc_assert(a_thread, -1); + + event_new = zlog_event_new(time_cache_count); + if (!event_new) { + zc_error("zlog_event_new fail"); + goto err; + } + + zlog_event_del(a_thread->event); + a_thread->event = event_new; + return 0; +err: + if (event_new) zlog_event_del(event_new); + return -1; +} + + +/*******************************************************************************/ diff --git a/zlog/thread.h b/zlog/thread.h new file mode 100644 index 0000000..8548bbd --- /dev/null +++ b/zlog/thread.h @@ -0,0 +1,38 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_thread_h +#define __zlog_thread_h + +#include "zc_defs.h" +#include "event.h" +#include "buf.h" +#include "mdc.h" + +typedef struct { + int init_version; + zlog_mdc_t *mdc; + zlog_event_t *event; + + zlog_buf_t *pre_path_buf; + zlog_buf_t *path_buf; + zlog_buf_t *archive_path_buf; + zlog_buf_t *pre_msg_buf; + zlog_buf_t *msg_buf; +} zlog_thread_t; + + +void zlog_thread_del(zlog_thread_t * a_thread); +void zlog_thread_profile(zlog_thread_t * a_thread, int flag); +zlog_thread_t *zlog_thread_new(int init_version, + size_t buf_size_min, size_t buf_size_max, int time_cache_count); + +int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max); +int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count); + +#endif diff --git a/zlog/version.h b/zlog/version.h new file mode 100644 index 0000000..98adba7 --- /dev/null +++ b/zlog/version.h @@ -0,0 +1 @@ +#define ZLOG_VERSION "1.2.12" diff --git a/zlog/zc_arraylist.c b/zlog/zc_arraylist.c new file mode 100644 index 0000000..b1625a1 --- /dev/null +++ b/zlog/zc_arraylist.c @@ -0,0 +1,132 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include + +#include "zc_defs.h" + +zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del) +{ + zc_arraylist_t *a_list; + + a_list = (zc_arraylist_t *) calloc(1, sizeof(zc_arraylist_t)); + if (!a_list) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + a_list->size = ARRAY_LIST_DEFAULT_SIZE; + a_list->len = 0; + + /* this could be NULL */ + a_list->del = del; + a_list->array = (void **)calloc(a_list->size, sizeof(void *)); + if (!a_list->array) { + zc_error("calloc fail, errno[%d]", errno); + free(a_list); + return NULL; + } + + return a_list; +} + +void zc_arraylist_del(zc_arraylist_t * a_list) +{ + int i; + + if (!a_list) + return; + if (a_list->del) { + for (i = 0; i < a_list->len; i++) { + if (a_list->array[i]) + a_list->del(a_list->array[i]); + } + } + if (a_list->array) + free(a_list->array); + free(a_list); + return; +} + +static int zc_arraylist_expand_inner(zc_arraylist_t * a_list, int max) +{ + void *tmp; + int new_size; + int diff_size; + + new_size = zc_max(a_list->size * 2, max); + tmp = realloc(a_list->array, new_size * sizeof(void *)); + if (!tmp) { + zc_error("realloc fail, errno[%d]", errno); + return -1; + } + a_list->array = (void **)tmp; + diff_size = new_size - a_list->size; + if (diff_size) memset(a_list->array + a_list->size, 0x00, diff_size * sizeof(void *)); + a_list->size = new_size; + return 0; +} + +int zc_arraylist_set(zc_arraylist_t * a_list, int idx, void *data) +{ + if (idx > a_list->size - 1) { + if (zc_arraylist_expand_inner(a_list, idx)) { + zc_error("expand_internal fail"); + return -1; + } + } + if (a_list->array[idx] && a_list->del) a_list->del(a_list->array[idx]); + a_list->array[idx] = data; + if (a_list->len <= idx) + a_list->len = idx + 1; + return 0; +} + +int zc_arraylist_add(zc_arraylist_t * a_list, void *data) +{ + return zc_arraylist_set(a_list, a_list->len, data); +} + +/* assum idx < len */ +static int zc_arraylist_insert_inner(zc_arraylist_t * a_list, int idx, + void *data) +{ + if (a_list->array[idx] == NULL) { + a_list->array[idx] = data; + return 0; + } + if (a_list->len > a_list->size - 1) { + if (zc_arraylist_expand_inner(a_list, 0)) { + zc_error("expand_internal fail"); + return -1; + } + } + memmove(a_list->array + idx + 1, a_list->array + idx, + (a_list->len - idx) * sizeof(void *)); + a_list->array[idx] = data; + a_list->len++; + return 0; +} + +int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp, + void *data) +{ + int i; + + for (i = 0; i < a_list->len; i++) { + if ((*cmp) (a_list->array[i], data) > 0) + break; + } + + if (i == a_list->len) + return zc_arraylist_add(a_list, data); + else + return zc_arraylist_insert_inner(a_list, i, data); +} diff --git a/zlog/zc_arraylist.h b/zlog/zc_arraylist.h new file mode 100644 index 0000000..50f3f77 --- /dev/null +++ b/zlog/zc_arraylist.h @@ -0,0 +1,41 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zc_arraylist_h +#define __zc_arraylist_h + +#define ARRAY_LIST_DEFAULT_SIZE 32 + +typedef void (*zc_arraylist_del_fn) (void *data); +typedef int (*zc_arraylist_cmp_fn) (void *data1, void *data2); + +/* make zc_arraylist_foreach speed up, so keep struct defination here */ +typedef struct { + void **array; + int len; + int size; + zc_arraylist_del_fn del; +} zc_arraylist_t; + +zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del); +void zc_arraylist_del(zc_arraylist_t * a_list); + +int zc_arraylist_set(zc_arraylist_t * a_list, int i, void *data); +int zc_arraylist_add(zc_arraylist_t * a_list, void *data); +int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp, + void *data); + +#define zc_arraylist_len(a_list) (a_list->len) + +#define zc_arraylist_get(a_list, i) \ + ((i >= a_list->len) ? NULL : a_list->array[i]) + +#define zc_arraylist_foreach(a_list, i, a_unit) \ + for(i = 0, a_unit = a_list->array[0]; (i < a_list->len) && (a_unit = a_list->array[i], 1) ; i++) + +#endif diff --git a/zlog/zc_defs.h b/zlog/zc_defs.h new file mode 100644 index 0000000..9524999 --- /dev/null +++ b/zlog/zc_defs.h @@ -0,0 +1,18 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zc_defs_h +#define __zc_defs_h + +#include "zc_profile.h" +#include "zc_arraylist.h" +#include "zc_hashtable.h" +#include "zc_xplatform.h" +#include "zc_util.h" + +#endif diff --git a/zlog/zc_hashtable.c b/zlog/zc_hashtable.c new file mode 100644 index 0000000..00ce20f --- /dev/null +++ b/zlog/zc_hashtable.c @@ -0,0 +1,330 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include + +#include "zc_defs.h" +#include "zc_hashtable.h" + +struct zc_hashtable_s { + size_t nelem; + + zc_hashtable_entry_t **tab; + size_t tab_size; + + zc_hashtable_hash_fn hash; + zc_hashtable_equal_fn equal; + zc_hashtable_del_fn key_del; + zc_hashtable_del_fn value_del; +}; + +zc_hashtable_t *zc_hashtable_new(size_t a_size, + zc_hashtable_hash_fn hash, + zc_hashtable_equal_fn equal, + zc_hashtable_del_fn key_del, + zc_hashtable_del_fn value_del) +{ + zc_hashtable_t *a_table; + + a_table = calloc(1, sizeof(*a_table)); + if (!a_table) { + zc_error("calloc fail, errno[%d]", errno); + return NULL; + } + + a_table->tab = calloc(a_size, sizeof(*(a_table->tab))); + if (!a_table->tab) { + zc_error("calloc fail, errno[%d]", errno); + free(a_table); + return NULL; + } + a_table->tab_size = a_size; + + a_table->nelem = 0; + a_table->hash = hash; + a_table->equal = equal; + + /* these two could be NULL */ + a_table->key_del = key_del; + a_table->value_del = value_del; + + return a_table; +} + +void zc_hashtable_del(zc_hashtable_t * a_table) +{ + size_t i; + zc_hashtable_entry_t *p; + zc_hashtable_entry_t *q; + + if (!a_table) { + zc_error("a_table[%p] is NULL, just do nothing", a_table); + return; + } + + for (i = 0; i < a_table->tab_size; i++) { + for (p = (a_table->tab)[i]; p; p = q) { + q = p->next; + if (a_table->key_del) { + a_table->key_del(p->key); + } + if (a_table->value_del) { + a_table->value_del(p->value); + } + free(p); + } + } + if (a_table->tab) + free(a_table->tab); + free(a_table); + + return; +} + +void zc_hashtable_clean(zc_hashtable_t * a_table) +{ + size_t i; + zc_hashtable_entry_t *p; + zc_hashtable_entry_t *q; + + for (i = 0; i < a_table->tab_size; i++) { + for (p = (a_table->tab)[i]; p; p = q) { + q = p->next; + if (a_table->key_del) { + a_table->key_del(p->key); + } + if (a_table->value_del) { + a_table->value_del(p->value); + } + free(p); + } + (a_table->tab)[i] = NULL; + } + a_table->nelem = 0; + return; +} + +static int zc_hashtable_rehash(zc_hashtable_t * a_table) +{ + size_t i; + size_t j; + size_t tab_size; + zc_hashtable_entry_t **tab; + zc_hashtable_entry_t *p; + zc_hashtable_entry_t *q; + + tab_size = 2 * a_table->tab_size; + tab = calloc(tab_size, sizeof(*tab)); + if (!tab) { + zc_error("calloc fail, errno[%d]", errno); + return -1; + } + + for (i = 0; i < a_table->tab_size; i++) { + for (p = (a_table->tab)[i]; p; p = q) { + q = p->next; + + p->next = NULL; + p->prev = NULL; + j = p->hash_key % tab_size; + if (tab[j]) { + tab[j]->prev = p; + p->next = tab[j]; + } + tab[j] = p; + } + } + free(a_table->tab); + a_table->tab = tab; + a_table->tab_size = tab_size; + + return 0; +} + +zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key) +{ + unsigned int i; + zc_hashtable_entry_t *p; + + i = a_table->hash(a_key) % a_table->tab_size; + for (p = (a_table->tab)[i]; p; p = p->next) { + if (a_table->equal(a_key, p->key)) + return p; + } + + return NULL; +} + +void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key) +{ + unsigned int i; + zc_hashtable_entry_t *p; + + i = a_table->hash(a_key) % a_table->tab_size; + for (p = (a_table->tab)[i]; p; p = p->next) { + if (a_table->equal(a_key, p->key)) + return p->value; + } + + return NULL; +} + +int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value) +{ + int rc = 0; + unsigned int i; + zc_hashtable_entry_t *p = NULL; + + i = a_table->hash(a_key) % a_table->tab_size; + for (p = (a_table->tab)[i]; p; p = p->next) { + if (a_table->equal(a_key, p->key)) + break; + } + + if (p) { + if (a_table->key_del) { + a_table->key_del(p->key); + } + if (a_table->value_del) { + a_table->value_del(p->value); + } + p->key = a_key; + p->value = a_value; + return 0; + } else { + if (a_table->nelem > a_table->tab_size * 1.3) { + rc = zc_hashtable_rehash(a_table); + if (rc) { + zc_error("rehash fail"); + return -1; + } + } + + p = calloc(1, sizeof(*p)); + if (!p) { + zc_error("calloc fail, errno[%d]", errno); + return -1; + } + + p->hash_key = a_table->hash(a_key); + p->key = a_key; + p->value = a_value; + p->next = NULL; + p->prev = NULL; + + i = p->hash_key % a_table->tab_size; + if ((a_table->tab)[i]) { + (a_table->tab)[i]->prev = p; + p->next = (a_table->tab)[i]; + } + (a_table->tab)[i] = p; + a_table->nelem++; + } + + return 0; +} + +void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key) +{ + zc_hashtable_entry_t *p; + unsigned int i; + + if (!a_table || !a_key) { + zc_error("a_table[%p] or a_key[%p] is NULL, just do nothing", a_table, a_key); + return; + } + + i = a_table->hash(a_key) % a_table->tab_size; + for (p = (a_table->tab)[i]; p; p = p->next) { + if (a_table->equal(a_key, p->key)) + break; + } + + if (!p) { + zc_error("p[%p] not found in hashtable", p); + return; + } + + if (a_table->key_del) { + a_table->key_del(p->key); + } + if (a_table->value_del) { + a_table->value_del(p->value); + } + + if (p->next) { + p->next->prev = p->prev; + } + if (p->prev) { + p->prev->next = p->next; + } else { + unsigned int i; + + i = p->hash_key % a_table->tab_size; + a_table->tab[i] = p->next; + } + + free(p); + a_table->nelem--; + + return; +} + +zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table) +{ + size_t i; + zc_hashtable_entry_t *p; + + for (i = 0; i < a_table->tab_size; i++) { + for (p = (a_table->tab)[i]; p; p = p->next) { + if (p) + return p; + } + } + + return NULL; +} + +zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry) +{ + size_t i; + size_t j; + + if (a_entry->next) + return a_entry->next; + + i = a_entry->hash_key % a_table->tab_size; + + for (j = i + 1; j < a_table->tab_size; j++) { + if ((a_table->tab)[j]) { + return (a_table->tab)[j]; + } + } + + return NULL; +} + +/*******************************************************************************/ + +unsigned int zc_hashtable_str_hash(const void *str) +{ + unsigned int h = 5381; + const char *p = (const char *)str; + + while (*p != '\0') + h = ((h << 5) + h) + (*p++); /* hash * 33 + c */ + + return h; +} + +int zc_hashtable_str_equal(const void *key1, const void *key2) +{ + return (STRCMP((const char *)key1, ==, (const char *)key2)); +} diff --git a/zlog/zc_hashtable.h b/zlog/zc_hashtable.h new file mode 100644 index 0000000..0f1c529 --- /dev/null +++ b/zlog/zc_hashtable.h @@ -0,0 +1,49 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zc_hashtalbe_h +#define __zc_hashtalbe_h + +#include + +typedef struct zc_hashtable_entry_s { + unsigned int hash_key; + void *key; + void *value; + struct zc_hashtable_entry_s *prev; + struct zc_hashtable_entry_s *next; +} zc_hashtable_entry_t; + +typedef struct zc_hashtable_s zc_hashtable_t; + +typedef unsigned int (*zc_hashtable_hash_fn) (const void *key); +typedef int (*zc_hashtable_equal_fn) (const void *key1, const void *key2); +typedef void (*zc_hashtable_del_fn) (void *kv); + +zc_hashtable_t *zc_hashtable_new(size_t a_size, + zc_hashtable_hash_fn hash_fn, + zc_hashtable_equal_fn equal_fn, + zc_hashtable_del_fn key_del_fn, + zc_hashtable_del_fn value_del_fn); + +void zc_hashtable_del(zc_hashtable_t * a_table); +void zc_hashtable_clean(zc_hashtable_t * a_table); +int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value); +zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key); +void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key); +void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key); +zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table); +zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry); + +#define zc_hashtable_foreach(a_table, a_entry) \ +for(a_entry = zc_hashtable_begin(a_table); a_entry; a_entry = zc_hashtable_next(a_table, a_entry)) + +unsigned int zc_hashtable_str_hash(const void *str); +int zc_hashtable_str_equal(const void *key1, const void *key2); + +#endif diff --git a/zlog/zc_profile.c b/zlog/zc_profile.c new file mode 100644 index 0000000..ff0f606 --- /dev/null +++ b/zlog/zc_profile.c @@ -0,0 +1,86 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zc_profile.h" +#include "zc_xplatform.h" + +static void zc_time(char *time_str, size_t time_str_size) +{ + time_t tt; + struct tm local_time; + + time(&tt); + localtime_r(&tt, &local_time); + strftime(time_str, time_str_size, "%m-%d %T", &local_time); + + return; +} + +int zc_profile_inner(int flag, const char *file, const long line, const char *fmt, ...) +{ + va_list args; + char time_str[20 + 1]; + FILE *fp = NULL; + + static char *debug_log = NULL; + static char *error_log = NULL; + static size_t init_flag = 0; + + if (!init_flag) { + init_flag = 1; + debug_log = getenv("ZLOG_PROFILE_DEBUG"); + error_log = getenv("ZLOG_PROFILE_ERROR"); + } + + switch (flag) { + case ZC_DEBUG: + if (debug_log == NULL) return 0; + fp = fopen(debug_log, "a"); + if (!fp) return -1; + zc_time(time_str, sizeof(time_str)); + fprintf(fp, "%s DEBUG (%d:%s:%ld) ", time_str, getpid(), file, line); + break; + case ZC_WARN: + if (error_log == NULL) return 0; + fp = fopen(error_log, "a"); + if (!fp) return -1; + zc_time(time_str, sizeof(time_str)); + fprintf(fp, "%s WARN (%d:%s:%ld) ", time_str, getpid(), file, line); + break; + case ZC_ERROR: + if (error_log == NULL) return 0; + fp = fopen(error_log, "a"); + if (!fp) return -1; + zc_time(time_str, sizeof(time_str)); + fprintf(fp, "%s ERROR (%d:%s:%ld) ", time_str, getpid(), file, line); + break; + } + + /* writing file twice(time & msg) is not atomic + * may cause cross + * but avoid log size limit */ + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + fprintf(fp, "\n"); + + fclose(fp); + return 0; +} + diff --git a/zlog/zc_profile.h b/zlog/zc_profile.h new file mode 100644 index 0000000..e629ef1 --- /dev/null +++ b/zlog/zc_profile.h @@ -0,0 +1,53 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zc_profile_h +#define __zc_profile_h + +#include + +#define EMPTY() +#define zc_assert(expr, rv) \ + if(!(expr)) { \ + zc_error(#expr" is null or 0"); \ + return rv; \ + } + +enum zc_profile_flag { + ZC_DEBUG = 0, + ZC_WARN = 1, + ZC_ERROR = 2 +}; + + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + #define zc_debug(...) \ + zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, __VA_ARGS__) + #define zc_warn(...) \ + zc_profile_inner(ZC_WARN, __FILE__, __LINE__, __VA_ARGS__) + #define zc_error(...) \ + zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, __VA_ARGS__) + #define zc_profile(flag, ...) \ + zc_profile_inner(flag, __FILE__, __LINE__, __VA_ARGS__) +#elif defined __GNUC__ + #define zc_debug(fmt, args...) \ + zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, fmt, ## args) + #define zc_warn(fmt, args...) \ + zc_profile_inner(ZC_WARN, __FILE__, __LINE__, fmt, ## args) + #define zc_error(fmt, args...) \ + zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, fmt, ## args) + #define zc_profile(flag, fmt, args...) \ + zc_profile_inner(flag, __FILE__, __LINE__, fmt, ## args) +#endif + + +int zc_profile_inner(int flag, + const char *file, const long line, + const char *fmt, ...); + +#endif diff --git a/zlog/zc_util.c b/zlog/zc_util.c new file mode 100644 index 0000000..07deb22 --- /dev/null +++ b/zlog/zc_util.c @@ -0,0 +1,147 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include +#include +#include +#include +#include +#include + +#include "zc_defs.h" + +size_t zc_parse_byte_size(char *astring) +{ + /* Parse size in bytes depending on the suffix. Valid suffixes are KB, MB and GB */ + char *p; + char *q; + size_t sz; + long res; + int c, m; + + zc_assert(astring, 0); + + /* clear space */ + for (p = q = astring; *p != '\0'; p++) { + if (isspace(*p)) { + continue; + } else { + *q = *p; + q++; + } + } + *q = '\0'; + + sz = strlen(astring); + res = strtol(astring, (char **)NULL, 10); + + if (res <= 0) + return 0; + + if (astring[sz - 1] == 'B' || astring[sz - 1] == 'b') { + c = astring[sz - 2]; + m = 1024; + } else { + c = astring[sz - 1]; + m = 1000; + } + + switch (c) { + case 'K': + case 'k': + res *= m; + break; + case 'M': + case 'm': + res *= m * m; + break; + case 'G': + case 'g': + res *= m * m * m; + break; + default: + if (!isdigit(c)) { + zc_error("Wrong suffix parsing " "size in bytes for string [%s], ignoring suffix", + astring); + } + break; + } + + return (res); +} + +/*******************************************************************************/ +int zc_str_replace_env(char *str, size_t str_size) +{ + char *p; + char *q; + char fmt[MAXLEN_CFG_LINE + 1]; + char env_key[MAXLEN_CFG_LINE + 1]; + char env_value[MAXLEN_CFG_LINE + 1]; + int str_len; + int env_value_len; + int nscan; + int nread; + + str_len = strlen(str); + q = str; + + do { + p = strchr(q, '%'); + if (!p) { + /* can't find more % */ + break; + } + + memset(fmt, 0x00, sizeof(fmt)); + memset(env_key, 0x00, sizeof(env_key)); + memset(env_value, 0x00, sizeof(env_value)); + nread = 0; + nscan = sscanf(p + 1, "%[.0-9-]%n", fmt + 1, &nread); + if (nscan == 1) { + fmt[0] = '%'; + fmt[nread + 1] = 's'; + } else { + nread = 0; + strcpy(fmt, "%s"); + } + + q = p + 1 + nread; + + nscan = sscanf(q, "E(%[^)])%n", env_key, &nread); + if (nscan == 0) { + continue; + } + + q += nread; + + if (*(q - 1) != ')') { + zc_error("in string[%s] can't find match )", p); + return -1; + } + + env_value_len = snprintf(env_value, sizeof(env_value), fmt, getenv(env_key)); + if (env_value_len < 0 || env_value_len >= sizeof(env_value)) { + zc_error("snprintf fail, errno[%d], evn_value_len[%d]", + errno, env_value_len); + return -1; + } + + str_len = str_len - (q - p) + env_value_len; + if (str_len > str_size - 1) { + zc_error("repalce env_value[%s] cause overlap", env_value); + return -1; + } + + memmove(p + env_value_len, q, strlen(q) + 1); + memcpy(p, env_value, env_value_len); + + } while (1); + + return 0; +} diff --git a/zlog/zc_util.h b/zlog/zc_util.h new file mode 100644 index 0000000..3f032cd --- /dev/null +++ b/zlog/zc_util.h @@ -0,0 +1,17 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ +#ifndef __zc_util_h +#define __zc_util_h + +size_t zc_parse_byte_size(char *astring); +int zc_str_replace_env(char *str, size_t str_size); + +#define zc_max(a,b) ((a) > (b) ? (a) : (b)) +#define zc_min(a,b) ((a) < (b) ? (a) : (b)) + +#endif diff --git a/zlog/zc_xplatform.h b/zlog/zc_xplatform.h new file mode 100644 index 0000000..ecfa7df --- /dev/null +++ b/zlog/zc_xplatform.h @@ -0,0 +1,61 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ +#ifndef __zc_xplatform_h +#define __zc_xplatform_h + +#include + +#define ZLOG_INT32_LEN sizeof("-2147483648") - 1 +#define ZLOG_INT64_LEN sizeof("-9223372036854775808") - 1 + +#if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8)) +#define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffffLL +#else +#define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffff +#endif + +#define ZLOG_MAX_INT32_VALUE (uint32_t) 0x7fffffff + +#define MAXLEN_PATH 1024 +#define MAXLEN_CFG_LINE (MAXLEN_PATH * 4) + +#define FILE_NEWLINE "\n" +#define FILE_NEWLINE_LEN 1 + +#include +#include + +#define STRCMP(_a_,_C_,_b_) ( strcmp(_a_,_b_) _C_ 0 ) +#define STRNCMP(_a_,_C_,_b_,_n_) ( strncmp(_a_,_b_,_n_) _C_ 0 ) +#define STRICMP(_a_,_C_,_b_) ( strcasecmp(_a_,_b_) _C_ 0 ) +#define STRNICMP(_a_,_C_,_b_,_n_) ( strncasecmp(_a_,_b_,_n_) _C_ 0 ) + + +#ifdef __APPLE__ +#include +#endif + +/* Define zlog_fstat to fstat or fstat64() */ +#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) +#define zlog_fstat fstat64 +#define zlog_stat stat64 +#else +#define zlog_fstat fstat +#define zlog_stat stat +#endif + +/* Define zlog_fsync to fdatasync() in Linux and fsync() for all the rest */ +#ifdef __linux__ +#define zlog_fsync fdatasync +#else +#define zlog_fsync fsync +#endif + + + +#endif diff --git a/zlog/zlog-chk-conf.c b/zlog/zlog-chk-conf.c new file mode 100644 index 0000000..0a4f630 --- /dev/null +++ b/zlog/zlog-chk-conf.c @@ -0,0 +1,70 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" + +#include +#include +#include +#include + +#include + +#include "zlog.h" +#include "version.h" + + +int main(int argc, char *argv[]) +{ + int rc = 0; + int op; + int quiet = 0; + static const char *help = + "usage: zlog-chk-conf [conf files]...\n" + "\t-q,\tsuppress non-error message\n" + "\t-h,\tshow help message\n" + "zlog version: " ZLOG_VERSION "\n"; + + while((op = getopt(argc, argv, "qhv")) > 0) { + if (op == 'h') { + fputs(help, stdout); + return 0; + } else if (op == 'q') { + quiet = 1; + } + } + + argc -= optind; + argv += optind; + + if (argc == 0) { + fputs(help, stdout); + return -1; + } + + setenv("ZLOG_PROFILE_ERROR", "/dev/stderr", 1); + setenv("ZLOG_CHECK_FORMAT_RULE", "1", 1); + + while (argc > 0) { + rc = zlog_init(*argv); + if (rc) { + printf("\n---[%s] syntax error, see error message above\n", + *argv); + exit(2); + } else { + zlog_fini(); + if (!quiet) { + printf("--[%s] syntax right\n", *argv); + } + } + argc--; + argv++; + } + + exit(0); +} diff --git a/zlog/zlog.c b/zlog/zlog.c new file mode 100644 index 0000000..0bff453 --- /dev/null +++ b/zlog/zlog.c @@ -0,0 +1,1024 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#include "fmacros.h" + +#include +#include +#include +#include +#include + +#include "conf.h" +#include "category_table.h" +#include "record_table.h" +#include "mdc.h" +#include "zc_defs.h" +#include "rule.h" +#include "version.h" + +/*******************************************************************************/ +extern char *zlog_git_sha1; +/*******************************************************************************/ +static pthread_rwlock_t zlog_env_lock = PTHREAD_RWLOCK_INITIALIZER; +zlog_conf_t *zlog_env_conf; +static pthread_key_t zlog_thread_key; +static zc_hashtable_t *zlog_env_categories; +static zc_hashtable_t *zlog_env_records; +static zlog_category_t *zlog_default_category; +static size_t zlog_env_reload_conf_count; +static int zlog_env_is_init = 0; +static int zlog_env_init_version = 0; +/*******************************************************************************/ +/* inner no need thread-safe */ +static void zlog_fini_inner(void) +{ + /* pthread_key_delete(zlog_thread_key); */ + /* never use pthread_key_delete, + * it will cause other thread can't release zlog_thread_t + * after one thread call pthread_key_delete + * also key not init will cause a core dump + */ + + if (zlog_env_categories) zlog_category_table_del(zlog_env_categories); + zlog_env_categories = NULL; + zlog_default_category = NULL; + if (zlog_env_records) zlog_record_table_del(zlog_env_records); + zlog_env_records = NULL; + if (zlog_env_conf) zlog_conf_del(zlog_env_conf); + zlog_env_conf = NULL; + return; +} + +static void zlog_clean_rest_thread(void) +{ + zlog_thread_t *a_thread; + a_thread = pthread_getspecific(zlog_thread_key); + if (!a_thread) return; + zlog_thread_del(a_thread); + return; +} + +static int zlog_init_inner(const char *confpath) +{ + int rc = 0; + + /* the 1st time in the whole process do init */ + if (zlog_env_init_version == 0) { + /* clean up is done by OS when a thread call pthread_exit */ + rc = pthread_key_create(&zlog_thread_key, (void (*) (void *)) zlog_thread_del); + if (rc) { + zc_error("pthread_key_create fail, rc[%d]", rc); + goto err; + } + + /* if some thread do not call pthread_exit, like main thread + * atexit will clean it + */ + rc = atexit(zlog_clean_rest_thread); + if (rc) { + zc_error("atexit fail, rc[%d]", rc); + goto err; + } + zlog_env_init_version++; + } /* else maybe after zlog_fini() and need not create pthread_key */ + + zlog_env_conf = zlog_conf_new(confpath); + if (!zlog_env_conf) { + zc_error("zlog_conf_new[%s] fail", confpath); + goto err; + } + + zlog_env_categories = zlog_category_table_new(); + if (!zlog_env_categories) { + zc_error("zlog_category_table_new fail"); + goto err; + } + + zlog_env_records = zlog_record_table_new(); + if (!zlog_env_records) { + zc_error("zlog_record_table_new fail"); + goto err; + } + + return 0; +err: + zlog_fini_inner(); + return -1; +} + +/*******************************************************************************/ +int zlog_init(const char *confpath) +{ + int rc; + zc_debug("------zlog_init start------"); + zc_debug("------compile time[%s %s], version[%s]------", __DATE__, __TIME__, ZLOG_VERSION); + + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return -1; + } + + if (zlog_env_is_init) { + zc_error("already init, use zlog_reload pls"); + goto err; + } + + + if (zlog_init_inner(confpath)) { + zc_error("zlog_init_inner[%s] fail", confpath); + goto err; + } + + zlog_env_is_init = 1; + zlog_env_init_version++; + + zc_debug("------zlog_init success end------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +err: + zc_error("------zlog_init fail end------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return -1; +} + +int dzlog_init(const char *confpath, const char *cname) +{ + int rc = 0; + zc_debug("------dzlog_init start------"); + zc_debug("------compile time[%s %s], version[%s]------", + __DATE__, __TIME__, ZLOG_VERSION); + + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return -1; + } + + if (zlog_env_is_init) { + zc_error("already init, use zlog_reload pls"); + goto err; + } + + if (zlog_init_inner(confpath)) { + zc_error("zlog_init_inner[%s] fail", confpath); + goto err; + } + + zlog_default_category = zlog_category_table_fetch_category( + zlog_env_categories, + cname, + zlog_env_conf->rules); + if (!zlog_default_category) { + zc_error("zlog_category_table_fetch_category[%s] fail", cname); + goto err; + } + + zlog_env_is_init = 1; + zlog_env_init_version++; + + zc_debug("------dzlog_init success end------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +err: + zc_error("------dzlog_init fail end------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return -1; +} +/*******************************************************************************/ +int zlog_reload(const char *confpath) +{ + int rc = 0; + int i = 0; + zlog_conf_t *new_conf = NULL; + zlog_rule_t *a_rule; + int c_up = 0; + + zc_debug("------zlog_reload start------"); + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return -1; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto quit; + } + + /* use last conf file */ + if (confpath == NULL) confpath = zlog_env_conf->file; + + /* reach reload period */ + if (confpath == (char*)-1) { + /* test again, avoid other threads already reloaded */ + if (zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period) { + confpath = zlog_env_conf->file; + } else { + /* do nothing, already done */ + goto quit; + } + } + + /* reset counter, whether automaticlly or mannually */ + zlog_env_reload_conf_count = 0; + + new_conf = zlog_conf_new(confpath); + if (!new_conf) { + zc_error("zlog_conf_new fail"); + goto err; + } + + zc_arraylist_foreach(new_conf->rules, i, a_rule) { + zlog_rule_set_record(a_rule, zlog_env_records); + } + + if (zlog_category_table_update_rules(zlog_env_categories, new_conf->rules)) { + c_up = 0; + zc_error("zlog_category_table_update fail"); + goto err; + } else { + c_up = 1; + } + + zlog_env_init_version++; + + if (c_up) zlog_category_table_commit_rules(zlog_env_categories); + zlog_conf_del(zlog_env_conf); + zlog_env_conf = new_conf; + zc_debug("------zlog_reload success, total init verison[%d] ------", zlog_env_init_version); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +err: + /* fail, roll back everything */ + zc_warn("zlog_reload fail, use old conf file, still working"); + if (new_conf) zlog_conf_del(new_conf); + if (c_up) zlog_category_table_rollback_rules(zlog_env_categories); + zc_error("------zlog_reload fail, total init version[%d] ------", zlog_env_init_version); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return -1; +quit: + zc_debug("------zlog_reload do nothing------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +} +/*******************************************************************************/ +void zlog_fini(void) +{ + int rc = 0; + + zc_debug("------zlog_fini start------"); + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return; + } + + if (!zlog_env_is_init) { + zc_error("before finish, must zlog_init() or dzlog_init() fisrt"); + goto exit; + } + + zlog_fini_inner(); + zlog_env_is_init = 0; + +exit: + zc_debug("------zlog_fini end------"); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return; + } + return; +} +/*******************************************************************************/ +zlog_category_t *zlog_get_category(const char *cname) +{ + int rc = 0; + zlog_category_t *a_category = NULL; + + zc_assert(cname, NULL); + zc_debug("------zlog_get_category[%s] start------", cname); + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return NULL; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + a_category = NULL; + goto err; + } + + a_category = zlog_category_table_fetch_category( + zlog_env_categories, + cname, + zlog_env_conf->rules); + if (!a_category) { + zc_error("zlog_category_table_fetch_category[%s] fail", cname); + goto err; + } + + zc_debug("------zlog_get_category[%s] success, end------ ", cname); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return NULL; + } + return a_category; +err: + zc_error("------zlog_get_category[%s] fail, end------ ", cname); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return NULL; + } + return NULL; +} + +int dzlog_set_category(const char *cname) +{ + int rc = 0; + zc_assert(cname, -1); + + zc_debug("------dzlog_set_category[%s] start------", cname); + rc = pthread_rwlock_wrlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return -1; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto err; + } + + zlog_default_category = zlog_category_table_fetch_category( + zlog_env_categories, + cname, + zlog_env_conf->rules); + if (!zlog_default_category) { + zc_error("zlog_category_table_fetch_category[%s] fail", cname); + goto err; + } + + zc_debug("------dzlog_set_category[%s] end, success------ ", cname); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +err: + zc_error("------dzlog_set_category[%s] end, fail------ ", cname); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return -1; +} +/*******************************************************************************/ +#define zlog_fetch_thread(a_thread, fail_goto) do { \ + int rd = 0; \ + a_thread = pthread_getspecific(zlog_thread_key); \ + if (!a_thread) { \ + a_thread = zlog_thread_new(zlog_env_init_version, \ + zlog_env_conf->buf_size_min, zlog_env_conf->buf_size_max, \ + zlog_env_conf->time_cache_count); \ + if (!a_thread) { \ + zc_error("zlog_thread_new fail"); \ + goto fail_goto; \ + } \ + \ + rd = pthread_setspecific(zlog_thread_key, a_thread); \ + if (rd) { \ + zlog_thread_del(a_thread); \ + zc_error("pthread_setspecific fail, rd[%d]", rd); \ + goto fail_goto; \ + } \ + } \ + \ + if (a_thread->init_version != zlog_env_init_version) { \ + /* as mdc is still here, so can not easily del and new */ \ + rd = zlog_thread_rebuild_msg_buf(a_thread, \ + zlog_env_conf->buf_size_min, \ + zlog_env_conf->buf_size_max); \ + if (rd) { \ + zc_error("zlog_thread_resize_msg_buf fail, rd[%d]", rd); \ + goto fail_goto; \ + } \ + \ + rd = zlog_thread_rebuild_event(a_thread, zlog_env_conf->time_cache_count); \ + if (rd) { \ + zc_error("zlog_thread_resize_msg_buf fail, rd[%d]", rd); \ + goto fail_goto; \ + } \ + a_thread->init_version = zlog_env_init_version; \ + } \ +} while (0) + +/*******************************************************************************/ +int zlog_put_mdc(const char *key, const char *value) +{ + int rc = 0; + zlog_thread_t *a_thread; + + zc_assert(key, -1); + zc_assert(value, -1); + + rc = pthread_rwlock_rdlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return -1; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto err; + } + + zlog_fetch_thread(a_thread, err); + + if (zlog_mdc_put(a_thread->mdc, key, value)) { + zc_error("zlog_mdc_put fail, key[%s], value[%s]", key, value); + goto err; + } + + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return 0; +err: + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return -1; + } + return -1; +} + +char *zlog_get_mdc(char *key) +{ + int rc = 0; + char *value = NULL; + zlog_thread_t *a_thread; + + zc_assert(key, NULL); + + rc = pthread_rwlock_rdlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc); + return NULL; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto err; + } + + a_thread = pthread_getspecific(zlog_thread_key); + if (!a_thread) { + zc_error("thread not found, maybe not use zlog_put_mdc before"); + goto err; + } + + value = zlog_mdc_get(a_thread->mdc, key); + if (!value) { + zc_error("key[%s] not found in mdc", key); + goto err; + } + + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return NULL; + } + return value; +err: + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return NULL; + } + return NULL; +} + +void zlog_remove_mdc(char *key) +{ + int rc = 0; + zlog_thread_t *a_thread; + + zc_assert(key, ); + + rc = pthread_rwlock_rdlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc); + return; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + a_thread = pthread_getspecific(zlog_thread_key); + if (!a_thread) { + zc_error("thread not found, maybe not use zlog_put_mdc before"); + goto exit; + } + + zlog_mdc_remove(a_thread->mdc, key); + +exit: + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return; + } + return; +} + +void zlog_clean_mdc(void) +{ + int rc = 0; + zlog_thread_t *a_thread; + + rc = pthread_rwlock_rdlock(&zlog_env_lock); + if (rc) {; + zc_error("pthread_rwlock_rdlock fail, rc[%d]", rc); + return; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + a_thread = pthread_getspecific(zlog_thread_key); + if (!a_thread) { + zc_error("thread not found, maybe not use zlog_put_mdc before"); + goto exit; + } + + zlog_mdc_clean(a_thread->mdc); + +exit: + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return; + } + return; +} + +int zlog_level_switch(zlog_category_t * category, int level) +{ + // This is NOT thread safe. + memset(category->level_bitmap, 0x00, sizeof(category->level_bitmap)); + category->level_bitmap[level / 8] |= ~(0xFF << (8 - level % 8)); + memset(category->level_bitmap + level / 8 + 1, 0xFF, + sizeof(category->level_bitmap) - level / 8 - 1); + + return 0; +} + +/*******************************************************************************/ +void vzlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args) +{ + zlog_thread_t *a_thread; + + /* The bitmap determination here is not under the protection of rdlock. + * It may be changed by other CPU by zlog_reload() halfway. + * + * Old or strange value may be read here, + * but it is safe, the bitmap is valid as long as category exist, + * And will be the right value after zlog_reload() + * + * For speed up, if one log will not be ouput, + * There is no need to aquire rdlock. + */ + if (zlog_category_needless_level(category, level)) return; + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + zlog_fetch_thread(a_thread, exit); + + zlog_event_set_fmt(a_thread->event, + category->name, category->name_len, + file, filelen, func, funclen, line, level, + format, args); + + if (zlog_category_output(category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + goto exit; + } + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +void hzlog(zlog_category_t *category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen) +{ + zlog_thread_t *a_thread; + + if (zlog_category_needless_level(category, level)) return; + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + zlog_fetch_thread(a_thread, exit); + + zlog_event_set_hex(a_thread->event, + category->name, category->name_len, + file, filelen, func, funclen, line, level, + buf, buflen); + + if (zlog_category_output(category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + goto exit; + } + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +/*******************************************************************************/ +/* for speed up, copy from vzlog */ +void vdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args) +{ + zlog_thread_t *a_thread; + + if (zlog_category_needless_level(zlog_default_category, level)) return; + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + /* that's the differnce, must judge default_category in lock */ + if (!zlog_default_category) { + zc_error("zlog_default_category is null," + "dzlog_init() or dzlog_set_cateogry() is not called above"); + goto exit; + } + + zlog_fetch_thread(a_thread, exit); + + zlog_event_set_fmt(a_thread->event, + zlog_default_category->name, zlog_default_category->name_len, + file, filelen, func, funclen, line, level, + format, args); + + if (zlog_category_output(zlog_default_category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + goto exit; + } + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +void hdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen) +{ + zlog_thread_t *a_thread; + + if (zlog_category_needless_level(zlog_default_category, level)) return; + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + /* that's the differnce, must judge default_category in lock */ + if (!zlog_default_category) { + zc_error("zlog_default_category is null," + "dzlog_init() or dzlog_set_cateogry() is not called above"); + goto exit; + } + + zlog_fetch_thread(a_thread, exit); + + zlog_event_set_hex(a_thread->event, + zlog_default_category->name, zlog_default_category->name_len, + file, filelen, func, funclen, line, level, + buf, buflen); + + if (zlog_category_output(zlog_default_category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + goto exit; + } + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +/*******************************************************************************/ +void zlog(zlog_category_t * category, + const char *file, size_t filelen, const char *func, size_t funclen, + long line, const int level, + const char *format, ...) +{ + zlog_thread_t *a_thread; + va_list args; + + if (category && zlog_category_needless_level(category, level)) return; + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + zlog_fetch_thread(a_thread, exit); + + va_start(args, format); + zlog_event_set_fmt(a_thread->event, category->name, category->name_len, + file, filelen, func, funclen, line, level, + format, args); + if (zlog_category_output(category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + va_end(args); + goto exit; + } + va_end(args); + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +/*******************************************************************************/ +void dzlog(const char *file, size_t filelen, const char *func, size_t funclen, long line, int level, + const char *format, ...) +{ + zlog_thread_t *a_thread; + va_list args; + + + pthread_rwlock_rdlock(&zlog_env_lock); + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto exit; + } + + /* that's the differnce, must judge default_category in lock */ + if (!zlog_default_category) { + zc_error("zlog_default_category is null," + "dzlog_init() or dzlog_set_cateogry() is not called above"); + goto exit; + } + + if (zlog_category_needless_level(zlog_default_category, level)) goto exit; + + zlog_fetch_thread(a_thread, exit); + + va_start(args, format); + zlog_event_set_fmt(a_thread->event, + zlog_default_category->name, zlog_default_category->name_len, + file, filelen, func, funclen, line, level, + format, args); + + if (zlog_category_output(zlog_default_category, a_thread)) { + zc_error("zlog_output fail, srcfile[%s], srcline[%ld]", file, line); + va_end(args); + goto exit; + } + va_end(args); + + if (zlog_env_conf->reload_conf_period && + ++zlog_env_reload_conf_count > zlog_env_conf->reload_conf_period ) { + /* under the protection of lock read env conf */ + goto reload; + } + +exit: + pthread_rwlock_unlock(&zlog_env_lock); + return; +reload: + pthread_rwlock_unlock(&zlog_env_lock); + /* will be wrlock, so after unlock */ + if (zlog_reload((char *)-1)) { + zc_error("reach reload-conf-period but zlog_reload fail, zlog-chk-conf [file] see detail"); + } + return; +} + +/*******************************************************************************/ +void zlog_profile(void) +{ + int rc = 0; + rc = pthread_rwlock_rdlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_wrlock fail, rc[%d]", rc); + return; + } + zc_warn("------zlog_profile start------ "); + zc_warn("is init:[%d]", zlog_env_is_init); + zc_warn("init version:[%d]", zlog_env_init_version); + zlog_conf_profile(zlog_env_conf, ZC_WARN); + zlog_record_table_profile(zlog_env_records, ZC_WARN); + zlog_category_table_profile(zlog_env_categories, ZC_WARN); + if (zlog_default_category) { + zc_warn("-default_category-"); + zlog_category_profile(zlog_default_category, ZC_WARN); + } + zc_warn("------zlog_profile end------ "); + rc = pthread_rwlock_unlock(&zlog_env_lock); + if (rc) { + zc_error("pthread_rwlock_unlock fail, rc=[%d]", rc); + return; + } + return; +} +/*******************************************************************************/ +int zlog_set_record(const char *rname, zlog_record_fn record_output) +{ + int rc = 0; + int rd = 0; + zlog_rule_t *a_rule; + zlog_record_t *a_record; + int i = 0; + + zc_assert(rname, -1); + zc_assert(record_output, -1); + + rd = pthread_rwlock_wrlock(&zlog_env_lock); + if (rd) { + zc_error("pthread_rwlock_rdlock fail, rd[%d]", rd); + return -1; + } + + if (!zlog_env_is_init) { + zc_error("never call zlog_init() or dzlog_init() before"); + goto zlog_set_record_exit; + } + + a_record = zlog_record_new(rname, record_output); + if (!a_record) { + rc = -1; + zc_error("zlog_record_new fail"); + goto zlog_set_record_exit; + } + + rc = zc_hashtable_put(zlog_env_records, a_record->name, a_record); + if (rc) { + zlog_record_del(a_record); + zc_error("zc_hashtable_put fail"); + goto zlog_set_record_exit; + } + + zc_arraylist_foreach(zlog_env_conf->rules, i, a_rule) { + zlog_rule_set_record(a_rule, zlog_env_records); + } + + zlog_set_record_exit: + rd = pthread_rwlock_unlock(&zlog_env_lock); + if (rd) { + zc_error("pthread_rwlock_unlock fail, rd=[%d]", rd); + return -1; + } + return rc; +} +/*******************************************************************************/ +int zlog_level_enabled(zlog_category_t *category, const int level) +{ + return category && (zlog_category_needless_level(category, level) == 0); +} + +const char *zlog_version(void) { return ZLOG_VERSION; } diff --git a/zlog/zlog.h b/zlog/zlog.h new file mode 100644 index 0000000..d40212f --- /dev/null +++ b/zlog/zlog.h @@ -0,0 +1,279 @@ +/* + * This file is part of the zlog Library. + * + * Copyright (C) 2011 by Hardy Simpson + * + * Licensed under the LGPL v2.1, see the file COPYING in base directory. + */ + +#ifndef __zlog_h +#define __zlog_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* for va_list */ +#include /* for size_t */ + +# if defined __GNUC__ +# define ZLOG_CHECK_PRINTF(m,n) __attribute__((format(printf,m,n))) +# else +# define ZLOG_CHECK_PRINTF(m,n) +# endif + +typedef struct zlog_category_s zlog_category_t; + +int zlog_init(const char *confpath); +int zlog_reload(const char *confpath); +void zlog_fini(void); + +void zlog_profile(void); + +zlog_category_t *zlog_get_category(const char *cname); +int zlog_level_enabled(zlog_category_t *category, const int level); + +int zlog_put_mdc(const char *key, const char *value); +char *zlog_get_mdc(const char *key); +void zlog_remove_mdc(const char *key); +void zlog_clean_mdc(void); + +int zlog_level_switch(zlog_category_t * category, int level); +int zlog_level_enabled(zlog_category_t * category, int level); + +void zlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, ...) ZLOG_CHECK_PRINTF(8,9); +void vzlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args); +void hzlog(zlog_category_t * category, + const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen); + +int dzlog_init(const char *confpath, const char *cname); +int dzlog_set_category(const char *cname); + +void dzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, ...) ZLOG_CHECK_PRINTF(7,8); +void vdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const char *format, va_list args); +void hdzlog(const char *file, size_t filelen, + const char *func, size_t funclen, + long line, int level, + const void *buf, size_t buflen); + +typedef struct zlog_msg_s { + char *buf; + size_t len; + char *path; +} zlog_msg_t; + +typedef int (*zlog_record_fn)(zlog_msg_t *msg); +int zlog_set_record(const char *rname, zlog_record_fn record); + +const char *zlog_version(void); + +/******* useful macros, can be redefined at user's h file **********/ + +typedef enum { + ZLOG_LEVEL_DEBUG = 20, + ZLOG_LEVEL_INFO = 40, + ZLOG_LEVEL_NOTICE = 60, + ZLOG_LEVEL_WARN = 80, + ZLOG_LEVEL_ERROR = 100, + ZLOG_LEVEL_FATAL = 120 +} zlog_level; + +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# if defined __GNUC__ && __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#endif + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +/* zlog macros */ +#define zlog_fatal(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, __VA_ARGS__) +#define zlog_error(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, __VA_ARGS__) +#define zlog_warn(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, __VA_ARGS__) +#define zlog_notice(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, __VA_ARGS__) +#define zlog_info(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, __VA_ARGS__) +#define zlog_debug(cat, ...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, __VA_ARGS__) +/* dzlog macros */ +#define dzlog_fatal(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, __VA_ARGS__) +#define dzlog_error(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, __VA_ARGS__) +#define dzlog_warn(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, __VA_ARGS__) +#define dzlog_notice(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, __VA_ARGS__) +#define dzlog_info(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, __VA_ARGS__) +#define dzlog_debug(...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, __VA_ARGS__) +#elif defined __GNUC__ +/* zlog macros */ +#define zlog_fatal(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, ##args) +#define zlog_error(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, ##args) +#define zlog_warn(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, ##args) +#define zlog_notice(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, ##args) +#define zlog_info(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, ##args) +#define zlog_debug(cat, format, args...) \ + zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, ##args) +/* dzlog macros */ +#define dzlog_fatal(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, ##args) +#define dzlog_error(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, ##args) +#define dzlog_warn(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, ##args) +#define dzlog_notice(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, ##args) +#define dzlog_info(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, ##args) +#define dzlog_debug(format, args...) \ + dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, ##args) +#endif + +/* vzlog macros */ +#define vzlog_fatal(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, args) +#define vzlog_error(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, args) +#define vzlog_warn(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, args) +#define vzlog_notice(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, args) +#define vzlog_info(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, args) +#define vzlog_debug(cat, format, args) \ + vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, args) + +/* hzlog macros */ +#define hzlog_fatal(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, buf, buf_len) +#define hzlog_error(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, buf, buf_len) +#define hzlog_warn(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, buf, buf_len) +#define hzlog_notice(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, buf, buf_len) +#define hzlog_info(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, buf, buf_len) +#define hzlog_debug(cat, buf, buf_len) \ + hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, buf, buf_len) + + +/* vdzlog macros */ +#define vdzlog_fatal(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, format, args) +#define vdzlog_error(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, format, args) +#define vdzlog_warn(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, format, args) +#define vdzlog_notice(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, format, args) +#define vdzlog_info(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, format, args) +#define vdzlog_debug(format, args) \ + vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, format, args) + +/* hdzlog macros */ +#define hdzlog_fatal(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_FATAL, buf, buf_len) +#define hdzlog_error(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_ERROR, buf, buf_len) +#define hdzlog_warn(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_WARN, buf, buf_len) +#define hdzlog_notice(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_NOTICE, buf, buf_len) +#define hdzlog_info(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_INFO, buf, buf_len) +#define hdzlog_debug(buf, buf_len) \ + hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ + ZLOG_LEVEL_DEBUG, buf, buf_len) + +/* enabled macros */ +#define zlog_fatal_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_FATAL) +#define zlog_error_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_ERROR) +#define zlog_warn_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_WARN) +#define zlog_notice_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_NOTICE) +#define zlog_info_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_INFO) +#define zlog_debug_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_DEBUG) + +#ifdef __cplusplus +} +#endif + +#endif