summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryangwei <[email protected]>2019-08-31 23:35:44 +0800
committeryangwei <[email protected]>2019-08-31 23:35:44 +0800
commit49822347cb81f3c7fa624c7fa7d8cf75d61da3d8 (patch)
treeecf7d053209181a4026c9c994f85b528f1d5d925
parentcecbe2628d4467f807ed9ea0eb79e4fa8f97eaf2 (diff)
后台改为zlog实现
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt7
-rw-r--r--demo/test_handle_logger.c2
-rw-r--r--src/MESA_handle_logger.c217
-rw-r--r--src/version.map4
-rw-r--r--zlog/CMakeLists.txt11
-rw-r--r--zlog/buf.c649
-rw-r--r--zlog/buf.h56
-rw-r--r--zlog/category.c233
-rw-r--r--zlog/category.h38
-rw-r--r--zlog/category_table.c129
-rw-r--r--zlog/category_table.h28
-rw-r--r--zlog/conf.c504
-rw-r--r--zlog/conf.h46
-rw-r--r--zlog/event.c182
-rw-r--r--zlog/event.h90
-rw-r--r--zlog/fmacros.h24
-rw-r--r--zlog/format.c164
-rw-r--r--zlog/format.h32
-rw-r--r--zlog/level.c141
-rw-r--r--zlog/level.h26
-rw-r--r--zlog/level_list.c145
-rw-r--r--zlog/level_list.h33
-rw-r--r--zlog/makefile204
-rw-r--r--zlog/mdc.c145
-rw-r--r--zlog/mdc.h36
-rw-r--r--zlog/record.c53
-rw-r--r--zlog/record.h32
-rw-r--r--zlog/record_table.c56
-rw-r--r--zlog/record_table.h19
-rw-r--r--zlog/rotater.c575
-rw-r--r--zlog/rotater.h45
-rw-r--r--zlog/rule.c1058
-rw-r--r--zlog/rule.h88
-rw-r--r--zlog/spec.c659
-rw-r--r--zlog/spec.h60
-rw-r--r--zlog/thread.c184
-rw-r--r--zlog/thread.h38
-rw-r--r--zlog/version.h1
-rw-r--r--zlog/zc_arraylist.c132
-rw-r--r--zlog/zc_arraylist.h41
-rw-r--r--zlog/zc_defs.h18
-rw-r--r--zlog/zc_hashtable.c330
-rw-r--r--zlog/zc_hashtable.h49
-rw-r--r--zlog/zc_profile.c86
-rw-r--r--zlog/zc_profile.h53
-rw-r--r--zlog/zc_util.c147
-rw-r--r--zlog/zc_util.h17
-rw-r--r--zlog/zc_xplatform.h61
-rw-r--r--zlog/zlog-chk-conf.c70
-rw-r--r--zlog/zlog.c1024
-rw-r--r--zlog/zlog.h279
52 files changed, 8198 insertions, 127 deletions
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 <stdio.h>
-#include <stdlib.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include <unistd.h>
-#include<sys/stat.h>
-#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <errno.h>
+#include <stdint.h>
+
+#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 <stdio.h>
+ 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 <[email protected]>
+ *
+ * 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 <stdarg.h>
+#include <stdint.h>
+
+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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+#include "fmacros.h"
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#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, &section);
+ 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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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 <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#ifndef __zlog_event_h
+#define __zlog_event_h
+
+#include <sys/types.h> /* for pid_t */
+#include <sys/time.h> /* for struct timeval */
+#include <pthread.h> /* for pthread_t */
+#include <stdarg.h> /* 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "syslog.h"
+
+#include "zc_defs.h"
+#include "level.h"
+#include "level_list.h"
+
+/* zlog_level_list == zc_arraylist_t<zlog_level_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 <[email protected]>
+ *
+ * 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 <[email protected]>
+# 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <string.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#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 <[email protected]>
+ *
+ * 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 <stdio.h>
+#include <pthread.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <pthread.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#ifndef __zc_hashtalbe_h
+#define __zc_hashtalbe_h
+
+#include <stdlib.h>
+
+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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#ifndef __zc_profile_h
+#define __zc_profile_h
+
+#include <stdarg.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+
+#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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+#ifndef __zc_xplatform_h
+#define __zc_xplatform_h
+
+#include <limits.h>
+
+#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 <string.h>
+#include <strings.h>
+
+#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 <AvailabilityMacros.h>
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#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 <[email protected]>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING in base directory.
+ */
+
+#include "fmacros.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <pthread.h>
+
+#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 <[email protected]>
+ *
+ * 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 <stdarg.h> /* for va_list */
+#include <stdio.h> /* 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__ "<unknown>"
+# 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