├── INSTALL ├── src ├── version.h ├── zc_defs.h ├── zc_util.h ├── fmacros.h ├── record_table.h ├── level.h ├── format.h ├── record.h ├── level_list.h ├── category_table.h ├── mdc.h ├── thread.h ├── conf.h ├── category.h ├── rotater.h ├── zc_arraylist.h ├── record.c ├── zlog-chk-conf.c ├── zc_profile.h ├── record_table.c ├── zc_xplatform.h ├── spec.h ├── buf.h ├── zc_hashtable.h ├── zc_profile.c ├── event.h ├── rule.h ├── zc_util.c ├── zc_arraylist.c ├── level.c ├── mdc.c ├── category_table.c ├── level_list.c ├── format.c ├── thread.c ├── event.c ├── category.c ├── zc_hashtable.c ├── makefile ├── zlog.h ├── rotater.c └── conf.c ├── test ├── test_hex.conf ├── test_default.conf ├── test_profile.conf ├── test_record.conf ├── test_pipe.conf ├── test_category.conf ├── test_mdc.conf ├── test_enabled.conf ├── test_level.conf ├── test_leak.2.conf ├── val.sh ├── test_hello.conf ├── test_init.conf ├── test_init.2.conf ├── test_prompt.conf ├── test_longlog.conf ├── test_leak.conf ├── test_tmp.conf ├── test_syslog.conf ├── test_press_zlog2.conf ├── test_default.c ├── test_multithread.conf ├── test_profile.c ├── fuzzers │ └── zlog_init_fuzzer.c ├── test_press_zlog.conf ├── test_pipe.c ├── test_hello.c ├── test_syslog.c ├── test_level.c ├── makefile ├── test_record.c ├── test_conf.c ├── test_category.c ├── test_tmp.c ├── test_conf2.c ├── test_mdc.c ├── test_enabled.c ├── test_bitmap.c ├── test_prompt.c ├── test_conf2.conf.h ├── test_leak.c ├── test_init.c ├── test_level.h ├── test_press_syslog.c ├── test_conf.conf ├── test_enabled.h ├── test_longlog.c ├── test_hashtable.c ├── test_press_zlog.c ├── test_press_zlog2.c ├── test_press_write2.c ├── test_press_write.c ├── test_hex.c ├── test_buf.c └── test_multithread.c ├── TODO ├── tools └── mk_targz.sh ├── makefile ├── doc ├── makefile ├── zlog.conf ├── performence.txt ├── GettingStart-CN.txt └── GettingStart-EN.txt ├── .gitignore ├── Changelog └── README.md /INSTALL: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #define ZLOG_VERSION "1.2.12" 2 | -------------------------------------------------------------------------------- /test/test_hex.conf: -------------------------------------------------------------------------------- 1 | [rules] 2 | *.* "hex.log"; 3 | -------------------------------------------------------------------------------- /test/test_default.conf: -------------------------------------------------------------------------------- 1 | [rules] 2 | my_cat.* >stdout 3 | -------------------------------------------------------------------------------- /test/test_profile.conf: -------------------------------------------------------------------------------- 1 | [formats] 2 | simple="%m%n" 3 | [rules] 4 | my_cat.* >stdout; simple 5 | -------------------------------------------------------------------------------- /test/test_record.conf: -------------------------------------------------------------------------------- 1 | [formats] 2 | simple = "%m%n" 3 | [rules] 4 | my_cat.* $myoutput, " mypath %c %d";simple 5 | -------------------------------------------------------------------------------- /test/test_pipe.conf: -------------------------------------------------------------------------------- 1 | [formats] 2 | simple = "%m%n" 3 | [rules] 4 | my_cat.* |/usr/bin/cronolog test_pipe_%Y%m%d.log; 5 | -------------------------------------------------------------------------------- /test/test_category.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | default format = "%V %v %m%n" 3 | [rules] 4 | my_cat.* >stdout; 5 | my-cat.* >stdout; 6 | -------------------------------------------------------------------------------- /test/test_mdc.conf: -------------------------------------------------------------------------------- 1 | [formats] 2 | mdc_format= "%d(%F %X.%ms) %-6V (%c:%F:%L) [%M(myname)] - %m%n" 3 | [rules] 4 | *.* >stdout; mdc_format 5 | -------------------------------------------------------------------------------- /test/test_enabled.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | default format = "%V %v %m%n" 3 | [levels] 4 | TRACE = 30, LOG_DEBUG 5 | [rules] 6 | my_cat.TRACE >stdout; 7 | -------------------------------------------------------------------------------- /test/test_level.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | default format = "%V %v %m%n" 3 | [levels] 4 | TRACE = 30, LOG_DEBUG 5 | [rules] 6 | my_cat.TRACE >stdout; 7 | -------------------------------------------------------------------------------- /test/test_leak.2.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min = 100 4 | buffer max = 200 5 | default format = "%m%n" 6 | 7 | [rules ] 8 | *.* >stdout; 9 | -------------------------------------------------------------------------------- /test/val.sh: -------------------------------------------------------------------------------- 1 | unset ZLOG_PROFILE_ERROR 2 | unset ZLOG_PROFILE_DEBUG_LOG 3 | 4 | rm -f press*log 5 | 6 | valgrind --tool=callgrind ./test_press_zlog 1 10 10000 7 | -------------------------------------------------------------------------------- /test/test_hello.conf: -------------------------------------------------------------------------------- 1 | [formats] 2 | simple = "%d.%ms %m%n" 3 | simple2 = "%d.%us %m%n" 4 | [rules] 5 | my_cat.* >stderr; 6 | my_cat.* >stdout;simple 7 | my_cat.* >stdout;simple2 8 | -------------------------------------------------------------------------------- /test/test_init.conf: -------------------------------------------------------------------------------- 1 | [ global ] 2 | strict init = true 3 | buffer min = 1024 4 | buffer max = 2MB 5 | rotate lock file= /tmp/zlog.lock 6 | 7 | [ rules ] 8 | my_cat.* >stderr; 9 | -------------------------------------------------------------------------------- /test/test_init.2.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | buffer min = 2048 3 | buffer max = 4096 4 | default format = "%V %m%n" 5 | [levels] 6 | TEST = 40, LOG_INFO 7 | 8 | 9 | [formats] 10 | simple = "%m%n" 11 | [rules] 12 | my_cat.* >stderr; 13 | -------------------------------------------------------------------------------- /test/test_prompt.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min = 1024 4 | buffer max = 0 5 | 6 | [formats] 7 | simple = "%r%d %V %m%n" 8 | prompt = "%r%d(%T)>%m" 9 | 10 | [rules ] 11 | !.* >stdout;simple 12 | prompt.* >stdout;prompt 13 | -------------------------------------------------------------------------------- /test/test_longlog.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | #buffer min = 1024 4 | #buffer max = 0 5 | rotate lock file = /tmp/zlog.lock 6 | 7 | [formats] 8 | simple = "%d %V %m%n" 9 | simple2 = "%d %V %m%n" 10 | 11 | [rules ] 12 | *.* "test_longlog.log" 13 | -------------------------------------------------------------------------------- /test/test_leak.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min = 2048 4 | buffer max = 4096 5 | rotate lock file = /tmp/zlog.lock 6 | default format = "%d(%F %T).%ms %-6V (%c:%F:%L) - %m%n" 7 | 8 | [ levels ] 9 | TEST = 40, LOG_INFO 10 | 11 | [rules ] 12 | *.* >stderr; 13 | -------------------------------------------------------------------------------- /test/test_tmp.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min = 1024 4 | buffer max = 0 5 | rotate lock file = /tmp/zlog.lock 6 | 7 | [formats] 8 | simple = "%d %V %m%n" 9 | simple2 = "%d %V %m%n" 10 | 11 | [rules ] 12 | *.=debug >stdout;simple 13 | *.=info >stdout;simple2 14 | -------------------------------------------------------------------------------- /test/test_syslog.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min= 1024 4 | buffer max= 2MB 5 | rotate lock file = /tmp/zlog.lock 6 | default format = "defalut - %d(%F %X.%ms) %-6V (%c:%F:%U:%L) - %m%n" 7 | 8 | [formats] 9 | null = "%n" 10 | print = "print - [%-10.3d(%F)]%n" 11 | 12 | simple = "simple - %m%n" 13 | 14 | [rules] 15 | *.* >syslog , LOG_LOCAL0 16 | my_cat.* >stdout;simple 17 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | [p] 使用valgrind测试性能 2 | [ ] 更好的错误展现,当系统出问题的时候直接报错 3 | [ ] hzlog的可定制 4 | [ ] hex那段重写,内置到buf内,参考od的设计 5 | [ ] 分类匹配的可定制化, rcat 6 | [ ] 自行管理文件缓存,替代stdio 7 | [ ] 减少dynamic文件名open的次数,通过日期改变智能推断, file_table? 8 | [ ] async file输出的增加 9 | [ ] 兼容性问题 zlog.h内 10 | [ ] 增加trace级别 11 | [ ] gettid() 12 | [ ] 性能对比, log4x, pantheios, glog 13 | [ ] perl, python, go, c++支持 14 | [ ] redis对接,协议设计 15 | [ ] 和rsyslog对接的问题 16 | [x] linux fsync->fdatasync, open.. 17 | 18 | -------------------------------------------------------------------------------- /src/zc_defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zc_defs_h 10 | #define __zc_defs_h 11 | 12 | #include "zc_profile.h" 13 | #include "zc_arraylist.h" 14 | #include "zc_hashtable.h" 15 | #include "zc_xplatform.h" 16 | #include "zc_util.h" 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /test/test_press_zlog2.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | default format = "%d.%us %-6V %p:%T:%F:%L %m%n" 3 | 4 | [rules] 5 | cat0.* "press.0.log" 6 | cat1.* "press.1.log" 7 | cat2.* "press.2.log" 8 | cat3.* "press.3.log" 9 | cat4.* "press.4.log" 10 | cat5.* "press.5.log" 11 | cat6.* "press.6.log" 12 | cat7.* "press.7.log" 13 | cat8.* "press.8.log" 14 | cat9.* "press.9.log" 15 | -------------------------------------------------------------------------------- /src/zc_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | #ifndef __zc_util_h 9 | #define __zc_util_h 10 | 11 | size_t zc_parse_byte_size(char *astring); 12 | int zc_str_replace_env(char *str, size_t str_size); 13 | 14 | #define zc_max(a,b) ((a) > (b) ? (a) : (b)) 15 | #define zc_min(a,b) ((a) < (b) ? (a) : (b)) 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef __zlog_fmacro_h 2 | #define __zlog_fmacro_h 3 | 4 | #define _DEFAULT_SOURCE 5 | 6 | #if defined(__linux__) || defined(__OpenBSD__) || defined(_AIX) 7 | #ifndef _XOPEN_SOURCE 8 | #define _XOPEN_SOURCE 700 9 | #endif 10 | #ifndef _XOPEN_SOURCE_EXTENDED 11 | #define _XOPEN_SOURCE_EXTENDED 12 | #endif 13 | #else 14 | #define _XOPEN_SOURCE 15 | #endif 16 | 17 | #ifndef _LARGEFILE_SOURCE 18 | #define _LARGEFILE_SOURCE 19 | #endif 20 | #ifndef _FILE_OFFSET_BITS 21 | #define _FILE_OFFSET_BITS 64 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/record_table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_record_table_h 10 | #define __zlog_record_table_h 11 | 12 | #include "zc_defs.h" 13 | #include "record.h" 14 | 15 | zc_hashtable_t *zlog_record_table_new(void); 16 | void zlog_record_table_del(zc_hashtable_t * records); 17 | void zlog_record_table_profile(zc_hashtable_t * records, int flag); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /tools/mk_targz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ "$1" = "" ] 4 | then 5 | echo "Usage: mk_targz.sh " 6 | echo "Example: mk_targz.sh 1.2.7" 7 | exit 1 8 | fi 9 | 10 | if [ ! -d .git ] 11 | then 12 | echo "Must run at git home directory" 13 | exit 2 14 | fi 15 | 16 | HASH=`git show-ref --hash=8 refs/tags/${1}` 17 | PREFIX="zlog-${1}-${HASH}/" 18 | TARBALL="/tmp/zlog-${1}-${HASH}.tar.gz" 19 | git archive --format=tar -v --prefix=$PREFIX $1 | gzip -c > $TARBALL 20 | cp ${TARBALL} /tmp/zlog-latest-stable.tar.gz 21 | echo "File created: $TARBALL" 22 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Top level makefile, the real shit is at src/makefile 2 | 3 | TARGETS=noopt 32bit 4 | 5 | all: 6 | cd src && $(MAKE) $@ 7 | 8 | install: 9 | cd src && $(MAKE) $@ 10 | 11 | $(TARGETS): 12 | cd src && $(MAKE) $@ 13 | 14 | doc: 15 | cd doc && $(MAKE) 16 | 17 | test: 18 | cd test && $(MAKE) 19 | 20 | TAGS: 21 | find . -type f -name "*.[ch]" | xargs etags - 22 | 23 | clean: 24 | cd src && $(MAKE) $@ 25 | cd test && $(MAKE) $@ 26 | cd doc && $(MAKE) $@ 27 | rm -f TAGS 28 | 29 | distclean: clean 30 | 31 | dummy: 32 | 33 | .PHONY: doc install test TAGS 34 | -------------------------------------------------------------------------------- /test/test_default.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | 16 | rc = dzlog_init("test_default.conf", "my_cat"); 17 | if (rc) { 18 | printf("init failed\n"); 19 | return -1; 20 | } 21 | 22 | dzlog_info("hello, zlog"); 23 | 24 | zlog_fini(); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /doc/makefile: -------------------------------------------------------------------------------- 1 | doc = \ 2 | UsersGuide-EN.pdf \ 3 | UsersGuide-CN.pdf \ 4 | UsersGuide-EN.tex \ 5 | UsersGuide-CN.tex \ 6 | UsersGuide-EN.html \ 7 | UsersGuide-CN.html \ 8 | GettingStart-EN.txt \ 9 | GettingStart-CN.txt 10 | 11 | all : $(doc) 12 | 13 | UsersGuide-EN.pdf : UsersGuide-EN.lyx 14 | lyx -f -e pdf2 $^ 15 | 16 | UsersGuide-CN.pdf : UsersGuide-CN.lyx 17 | lyx -f -e pdf4 $^ 18 | 19 | %.tex : %.lyx 20 | lyx -f -e pdflatex $< 21 | 22 | %.html : %.tex 23 | hevea book.hva -s $< 24 | hevea book.hva -s $< 25 | 26 | clean : 27 | -rm -f *.pdf *.haux *.html *.htoc *.tex *.lyx~ 28 | -------------------------------------------------------------------------------- /test/test_multithread.conf: -------------------------------------------------------------------------------- 1 | [levels] 2 | TRACE = 10, LOG_DEBUG 3 | SECURITY = 150, LOG_ALERT 4 | [formats] 5 | simple = "%d(%m%d%H%M%S).%us %-6c %-10V [%06k] %m%n" 6 | security = "%d(%m%d%H%M%S).%us %-6c [%-8V] %m%n" 7 | developer = "%d(%m%d%H%M%S).%us %-6c %-10V [%t] %F(%L)/%U() - %m%n" 8 | csv = "%d.%ms;%m%n [%08t] [%T] [%06k] " 9 | [rules] 10 | clsn.ERROR >stdout; developer 11 | high.ERROR >stdout; security 12 | main.* >stdout; simple 13 | main.* "./test_multithread-logs.txt"; simple 14 | thrd.* "./test_multithread-logs/threadslog.csv", 20KB * 30 ~ "./test_multithread-logs/threadslog#r.csv"; csv 15 | -------------------------------------------------------------------------------- /test/test_profile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | 16 | rc = dzlog_init("test_profile.conf", "my_cat"); 17 | if (rc) { 18 | printf("init failed\n"); 19 | return -1; 20 | } 21 | 22 | dzlog_info("hello, zlog"); 23 | 24 | zlog_profile(); 25 | 26 | zlog_fini(); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/fuzzers/zlog_init_fuzzer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "zlog.h" 5 | 6 | int 7 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 8 | { 9 | char filename[256]; 10 | sprintf(filename, "/tmp/libfuzzer.%d", getpid()); 11 | 12 | FILE *fp = fopen(filename, "wb"); 13 | if (!fp) 14 | return 0; 15 | fwrite(data, size, 1, fp); 16 | fclose(fp); 17 | 18 | int rc = zlog_init(filename); 19 | if (rc == 0) 20 | { 21 | zlog_fini(); 22 | } 23 | unlink(filename); 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/test_press_zlog.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | #default format = "%d(%F %T).%us %-6V %p:%T:%F:%L %m%n" 3 | 4 | default format = "%d.%us %-6V %p:%T:%F:%L %m%n" 5 | 6 | [rules] 7 | # time ./test_press_zlog 1 10 100000 real user sys 8 | 9 | #*.* | /usr/bin/cronolog press%Y%m%d.log #1.632s 2.010s 1.100s 10 | *.* "press.log" #2.364s 2.090s 2.460s 11 | #*.* "press.log",10M #4.644s 2.540s 6.260s 12 | #*.* "press%d(%Y%m%d).log" #4.132s 2.910s 5.030s 13 | #*.* "press%d(%Y%m%d).log",1M*5 #4.713s 2.740s 6.310s 14 | #*.* "press.%d(%F).log",1MB ~ "press.#2r.log"#4.730s 2.690s 6.360s 15 | -------------------------------------------------------------------------------- /test/test_pipe.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_pipe.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | zlog_info(zc, "hello, zlog"); 31 | zlog_fini(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/level.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_level_h 10 | #define __zlog_level_h 11 | 12 | #include "zc_defs.h" 13 | 14 | typedef struct zlog_level_s { 15 | int int_level; 16 | char str_uppercase[MAXLEN_PATH + 1]; 17 | char str_lowercase[MAXLEN_PATH + 1]; 18 | size_t str_len; 19 | int syslog_level; 20 | } zlog_level_t; 21 | 22 | zlog_level_t *zlog_level_new(char *line); 23 | void zlog_level_del(zlog_level_t *a_level); 24 | void zlog_level_profile(zlog_level_t *a_level, int flag); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /test/test_hello.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_hello.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | zlog_info(zc, "hello, zlog"); 31 | 32 | zlog_fini(); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/test_syslog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_syslog.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | zlog_info(zc, "hello, zlog -- info"); 31 | zlog_error(zc, "hello, zlog -- error"); 32 | 33 | zlog_fini(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | 4 | *.o 5 | *.lo 6 | *.la 7 | *.gcda 8 | *.gcno 9 | aclocal.m4 10 | autom4te.cache 11 | build 12 | compile 13 | config.guess 14 | config.h 15 | config.h.in 16 | config.h.in~ 17 | config.log 18 | config.status 19 | config.sub 20 | configure 21 | depcomp 22 | .deps 23 | install-sh 24 | .libs 25 | libtool 26 | libzlog.so* 27 | libzlog.a* 28 | ltmain.sh 29 | Makefile 30 | Makefile.in 31 | missing 32 | stamp-h1 33 | tags 34 | TAGS 35 | zlog-chk-conf 36 | zlog-*.tar.gz 37 | zlog.pc 38 | callgrind* 39 | err.log 40 | test_* 41 | !test_*.c 42 | !test_*.conf 43 | !test_*.h 44 | doc/*.lyx~ 45 | doc/*.pdf 46 | doc/obj.think 47 | doc/zlog.3 48 | doc/zlogtest.xls 49 | doc/*.haux 50 | doc/*.html 51 | doc/*.htoc 52 | doc/*.tex 53 | test/press* 54 | test/*.png 55 | release.h 56 | *.dylib 57 | -------------------------------------------------------------------------------- /test/test_level.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "test_level.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_level.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | zlog_trace(zc, "hello, zlog - trace"); 31 | zlog_debug(zc, "hello, zlog - debug"); 32 | zlog_info(zc, "hello, zlog - info"); 33 | 34 | zlog_fini(); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /doc/zlog.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | reload conf period = 10M 4 | 5 | buffer min = 1024 6 | buffer max = 2MB 7 | 8 | #rotate lock file = /tmp/zlog.lock 9 | rotate lock file = self 10 | default format = "%d(%F %T.%l) %-6V (%c:%F:%L) - %m%n" 11 | 12 | file perms = 600 13 | fsync period = 1K 14 | 15 | [levels] 16 | TRACE = 10 17 | CRIT = 130, LOG_CRIT 18 | 19 | [formats] 20 | simple = "%m%n" 21 | normal = "%d(%F %T.%l) %m%n" 22 | 23 | [rules] 24 | default.* >stdout; simple 25 | 26 | *.* -"%12.2E(HOME)/log/%c.log", \ 27 | 1MB * 12 ~ "%E(HOME)/log/%c.%D(%F) #2r #3s.log"; \ 28 | simple 29 | 30 | my_.INFO >stderr; 31 | my_cat.!ERROR "aa.log" 32 | my_dog.=DEBUG >syslog, LOG_LOCAL0; simple 33 | my_dog.=DEBUG | /usr/bin/cronolog /www/logs/example_%Y%m%d.log ; normal 34 | my_mice.* $record_func , "record_path%c"; normal 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/makefile: -------------------------------------------------------------------------------- 1 | exe = \ 2 | test_tmp \ 3 | test_longlog \ 4 | test_buf \ 5 | test_bitmap \ 6 | test_conf \ 7 | test_conf2 \ 8 | test_hashtable \ 9 | test_hello \ 10 | test_hex \ 11 | test_init \ 12 | test_level \ 13 | test_leak \ 14 | test_mdc \ 15 | test_multithread \ 16 | test_record \ 17 | test_pipe \ 18 | test_press_zlog \ 19 | test_press_zlog2 \ 20 | test_press_write \ 21 | test_press_write2 \ 22 | test_press_syslog \ 23 | test_syslog \ 24 | test_default \ 25 | test_profile \ 26 | test_category \ 27 | test_prompt \ 28 | test_enabled 29 | 30 | all : $(exe) 31 | 32 | $(exe) : %:%.o 33 | gcc -O2 -g -o $@ $^ -L../src -lzlog -lpthread -Wl,-rpath ../src 34 | 35 | .c.o : 36 | gcc -O2 -g -Wall -D_GNU_SOURCE -o $@ -c $< -I. -I../src 37 | 38 | clean : 39 | rm -f press.log* *.o $(exe) 40 | 41 | .PHONY : clean all 42 | -------------------------------------------------------------------------------- /test/test_record.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int output(zlog_msg_t *msg) 13 | { 14 | printf("[mystd]:[%s][%s][%ld]\n", msg->path, msg->buf, (long)msg->len); 15 | return 0; 16 | } 17 | 18 | int main(int argc, char** argv) 19 | { 20 | int rc; 21 | zlog_category_t *zc; 22 | 23 | rc = zlog_init("test_record.conf"); 24 | if (rc) { 25 | printf("init failed\n"); 26 | return -1; 27 | } 28 | 29 | zlog_set_record("myoutput", output); 30 | 31 | zc = zlog_get_category("my_cat"); 32 | if (!zc) { 33 | printf("get cat fail\n"); 34 | zlog_fini(); 35 | return -2; 36 | } 37 | 38 | zlog_info(zc, "hello, zlog"); 39 | zlog_fini(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/test_conf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | 17 | int main(int argc, char** argv) 18 | { 19 | int rc; 20 | zlog_category_t *zc; 21 | 22 | 23 | rc = zlog_init("test_conf.conf"); 24 | if (rc) { 25 | printf("init failed, try zlog-chk-conf test_conf.conf for more detail\n"); 26 | return -1; 27 | } 28 | 29 | zc = zlog_get_category("my_cat"); 30 | if (!zc) { 31 | printf("get cat fail\n"); 32 | zlog_fini(); 33 | return -2; 34 | } 35 | 36 | zlog_info(zc, "hello, zlog"); 37 | 38 | zlog_fini(); 39 | printf("log end\n"); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/test_category.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_category.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | zlog_debug(zc, "hello, zlog - debug"); 31 | 32 | zc = zlog_get_category("my-cat"); 33 | if (!zc) { 34 | printf("get cat fail\n"); 35 | zlog_fini(); 36 | return -2; 37 | } 38 | 39 | zlog_info(zc, "hello, zlog - info"); 40 | 41 | zlog_fini(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/test_tmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | #include 12 | 13 | int main(int argc, char** argv) 14 | { 15 | int rc; 16 | zlog_category_t *zc; 17 | 18 | rc = zlog_init("test_tmp.conf"); 19 | if (rc) { 20 | printf("init failed\n"); 21 | return -1; 22 | } 23 | 24 | zc = zlog_get_category("my_cat"); 25 | if (!zc) { 26 | printf("get cat fail\n"); 27 | zlog_fini(); 28 | return -2; 29 | } 30 | 31 | zlog_debug(zc, "%s%d", "hello, zlog ", 1); 32 | zlog_info(zc, "hello, zlog 2"); 33 | 34 | sleep(1); 35 | 36 | zlog_info(zc, "hello, zlog 3"); 37 | zlog_debug(zc, "hello, zlog 4"); 38 | 39 | // zlog_profile(); 40 | 41 | zlog_fini(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_format_h 10 | #define __zlog_format_h 11 | 12 | #include "thread.h" 13 | #include "zc_defs.h" 14 | 15 | typedef struct zlog_format_s zlog_format_t; 16 | 17 | struct zlog_format_s { 18 | char name[MAXLEN_CFG_LINE + 1]; 19 | char pattern[MAXLEN_CFG_LINE + 1]; 20 | zc_arraylist_t *pattern_specs; 21 | }; 22 | 23 | zlog_format_t *zlog_format_new(char *line, int * time_cache_count); 24 | void zlog_format_del(zlog_format_t * a_format); 25 | void zlog_format_profile(zlog_format_t * a_format, int flag); 26 | 27 | int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread); 28 | 29 | #define zlog_format_has_name(a_format, fname) \ 30 | STRCMP(a_format->name, ==, fname) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/record.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_record_h 10 | #define __zlog_record_h 11 | 12 | #include "zc_defs.h" 13 | 14 | /* record is user-defined output function and it's name from configure file */ 15 | typedef struct zlog_msg_s { 16 | char *buf; 17 | size_t len; 18 | char *path; 19 | } zlog_msg_t; /* 3 of this first, see need thread or not later */ 20 | 21 | typedef int (*zlog_record_fn)(zlog_msg_t * msg); 22 | 23 | typedef struct zlog_record_s { 24 | char name[MAXLEN_PATH + 1]; 25 | zlog_record_fn output; 26 | } zlog_record_t; 27 | 28 | zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output); 29 | void zlog_record_del(zlog_record_t *a_record); 30 | void zlog_record_profile(zlog_record_t *a_record, int flag); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /test/test_conf2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | #include "test_conf2.conf.h" 17 | 18 | int main(int argc, char** argv) 19 | { 20 | int rc; 21 | zlog_category_t *zc; 22 | 23 | rc = zlog_init(test_conf2_conf); 24 | if (rc) { 25 | printf("init failed, save [] in a config file and try zlog-chk-conf for more detail [%s]\n", test_conf2_conf); 26 | return -1; 27 | } 28 | 29 | zc = zlog_get_category("my_cat"); 30 | if (!zc) { 31 | printf("get cat fail\n"); 32 | zlog_fini(); 33 | return -2; 34 | } 35 | 36 | zlog_info(zc, "hello, zlog"); 37 | 38 | zlog_fini(); 39 | printf("log end\n"); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/test_mdc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | 17 | int main(int argc, char** argv) 18 | { 19 | int rc; 20 | zlog_category_t *zc; 21 | 22 | rc = zlog_init("test_mdc.conf"); 23 | if (rc) { 24 | printf("init failed\n"); 25 | return -1; 26 | } 27 | 28 | zc = zlog_get_category("my_cat"); 29 | if (!zc) { 30 | printf("get cat fail\n"); 31 | zlog_fini(); 32 | return -2; 33 | } 34 | 35 | 36 | zlog_info(zc, "1.hello, zlog"); 37 | 38 | zlog_put_mdc("myname", "Zhang"); 39 | 40 | zlog_info(zc, "2.hello, zlog"); 41 | 42 | zlog_put_mdc("myname", "Li"); 43 | 44 | zlog_info(zc, "3.hello, zlog"); 45 | 46 | zlog_fini(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/level_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_level_list_h 10 | #define __zlog_level_list_h 11 | 12 | #include "zc_defs.h" 13 | #include "level.h" 14 | 15 | zc_arraylist_t *zlog_level_list_new(void); 16 | void zlog_level_list_del(zc_arraylist_t *levels); 17 | void zlog_level_list_profile(zc_arraylist_t *levels, int flag); 18 | 19 | /* conf init use, slow */ 20 | /* if l is wrong or str=="", return -1 */ 21 | int zlog_level_list_set(zc_arraylist_t *levels, char *line); 22 | 23 | /* spec output use, fast */ 24 | /* rule output use, fast */ 25 | /* if not found, return levels[254] */ 26 | zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l); 27 | 28 | /* rule init use, slow */ 29 | /* if not found, return -1 */ 30 | int zlog_level_list_atoi(zc_arraylist_t *levels, char *str); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/category_table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_category_table_h 10 | #define __zlog_category_table_h 11 | 12 | #include "zc_defs.h" 13 | #include "category.h" 14 | 15 | zc_hashtable_t *zlog_category_table_new(void); 16 | void zlog_category_table_del(zc_hashtable_t * categories); 17 | void zlog_category_table_profile(zc_hashtable_t * categories, int flag); 18 | 19 | /* if none, create new and return */ 20 | zlog_category_t *zlog_category_table_fetch_category( 21 | zc_hashtable_t * categories, 22 | const char *category_name, zc_arraylist_t * rules); 23 | 24 | int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules); 25 | void zlog_category_table_commit_rules(zc_hashtable_t * categories); 26 | void zlog_category_table_rollback_rules(zc_hashtable_t * categories); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/mdc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_mdc_h 10 | #define __zlog_mdc_h 11 | 12 | #include "zc_defs.h" 13 | 14 | typedef struct zlog_mdc_s zlog_mdc_t; 15 | struct zlog_mdc_s { 16 | zc_hashtable_t *tab; 17 | }; 18 | 19 | zlog_mdc_t *zlog_mdc_new(void); 20 | void zlog_mdc_del(zlog_mdc_t * a_mdc); 21 | void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag); 22 | 23 | void zlog_mdc_clean(zlog_mdc_t * a_mdc); 24 | int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value); 25 | char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key); 26 | void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key); 27 | 28 | typedef struct zlog_mdc_kv_s { 29 | char key[MAXLEN_PATH + 1]; 30 | char value[MAXLEN_PATH + 1]; 31 | size_t value_len; 32 | } zlog_mdc_kv_t; 33 | 34 | zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /test/test_enabled.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2018 by Teracom Telemática S/A 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "test_enabled.h" 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc; 16 | 17 | rc = zlog_init("test_enabled.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | if (!zc) { 25 | printf("get cat fail\n"); 26 | zlog_fini(); 27 | return -2; 28 | } 29 | 30 | if (zlog_trace_enabled(zc)) { 31 | /* do something heavy to collect data */ 32 | zlog_trace(zc, "hello, zlog - trace"); 33 | } 34 | 35 | if (zlog_debug_enabled(zc)) { 36 | /* do something heavy to collect data */ 37 | zlog_debug(zc, "hello, zlog - debug"); 38 | } 39 | 40 | if (zlog_info_enabled(zc)) { 41 | /* do something heavy to collect data */ 42 | zlog_info(zc, "hello, zlog - info"); 43 | } 44 | 45 | zlog_fini(); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /test/test_bitmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "zlog.h" 13 | 14 | int main(int argc, char** argv) 15 | { 16 | unsigned char aa[32]; 17 | int i, j; 18 | 19 | if (argc != 3) { 20 | printf("useage: test_bitmap i j\n"); 21 | exit(1); 22 | } 23 | 24 | dzlog_init(NULL, "AA"); 25 | 26 | 27 | i = atoi(argv[1]); 28 | j = atoi(argv[2]); 29 | 30 | memset(aa, 0x00, sizeof(aa)); 31 | 32 | /* 32 byte, 256 bit 33 | * [11111..1100...00] 34 | * i 35 | */ 36 | aa[i/8] |= ~(0xFF << (8 - i % 8)); 37 | memset(aa + i/8 + 1, 0xFF, sizeof(aa) - i/8 - 1); 38 | 39 | hdzlog_info(aa, sizeof(aa)); 40 | 41 | dzlog_info("%0x", aa[j/8]); 42 | dzlog_info("%0x", aa[j/8] >> 6); 43 | 44 | /* see j of bits fits */ 45 | dzlog_info("%0x", ~((aa[j/8] >> (7 - j % 8)) & 0x01) ); 46 | 47 | zlog_fini(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /test/test_prompt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2020 by Bjoern Riemer 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | #include 9 | #include "zlog.h" 10 | #include 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int rc; 15 | zlog_category_t *zc,*pzc; 16 | 17 | rc = zlog_init("test_prompt.conf"); 18 | if (rc) { 19 | printf("init failed\n"); 20 | return -1; 21 | } 22 | 23 | zc = zlog_get_category("my_cat"); 24 | pzc = zlog_get_category("prompt"); 25 | if (!zc || !pzc) { 26 | printf("get cat fail\n"); 27 | zlog_fini(); 28 | return -2; 29 | } 30 | 31 | zlog_debug(zc, "%s%d", "hello, zlog ", 1); 32 | zlog_info(zc, "hello, zlog 2"); 33 | 34 | for (int i =0; i<15;i++){ 35 | zlog_info(pzc, "prompt>"); 36 | sleep(1); 37 | if (! (i%3)) 38 | zlog_debug(zc, "dummy log entry %d",i); 39 | if (! (i%5)) 40 | zlog_info(zc, "hello, zlog %d",i); 41 | } 42 | zlog_info(zc, "done"); 43 | 44 | // zlog_profile(); 45 | 46 | zlog_fini(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /src/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_thread_h 10 | #define __zlog_thread_h 11 | 12 | #include "zc_defs.h" 13 | #include "event.h" 14 | #include "buf.h" 15 | #include "mdc.h" 16 | 17 | typedef struct { 18 | int init_version; 19 | zlog_mdc_t *mdc; 20 | zlog_event_t *event; 21 | 22 | zlog_buf_t *pre_path_buf; 23 | zlog_buf_t *path_buf; 24 | zlog_buf_t *archive_path_buf; 25 | zlog_buf_t *pre_msg_buf; 26 | zlog_buf_t *msg_buf; 27 | } zlog_thread_t; 28 | 29 | 30 | void zlog_thread_del(zlog_thread_t * a_thread); 31 | void zlog_thread_profile(zlog_thread_t * a_thread, int flag); 32 | zlog_thread_t *zlog_thread_new(int init_version, 33 | size_t buf_size_min, size_t buf_size_max, int time_cache_count); 34 | 35 | int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max); 36 | int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /test/test_conf2.conf.h: -------------------------------------------------------------------------------- 1 | #define test_conf2_conf "[global]\nstrict init = true\nbuffer min= 1024\nbuffer max= 2MB\nrotate lock file = /tmp/zlog.lock\ndefault format = \"defalut - %d(%F %X.%ms) %-6V (%c:%F:%U:%L) - %m%n\"\n\n[formats]\nnull = \"%n\"\nprint = \"print - [%-10.3d(%F)]%n\"\n\ndate = \"date start%n%d(%a--Wed)%n%d(%A--Wednesday)%n%d(%b--Mar)%n%d(%B--March)%n%d(%c--WedMar211:45:262011)%n%d(%C--20)%n%d(%d--02)%n%d(%D--03/02/11)%n%d(%e--2)%n%d(%F--2011-03-02)%n%d(%g--11)%n%d(%G--2011)%n%d(%h--Mar)%n%d(%H--11)%n%d(%I--11)%n%d(%j--061)%n%d(%k-k)%n%d(%l-l)%n%d(%ms--500)%n%d(%m--03)%n%d(%M--45)%n%d(%us--500730)%n%d(%p--AM)%n%d(%r--11:45:26AM)%n%d(%R--11:45)%n%d(%s--epoch)%n%d(%S--26)%n%d(%t--)%n%d(%T--11:45:26)%n%d(%u--3)%n%d(%U--09)%n%d(%V--09)%n%d(%w--3)%n%d(%W--09)%n%d(%x--03/02/11)%n%d(%X--11:45:26)%n%d(%y--11)%n%d(%Y--2011)%n%d(%z--+0800)%n%d(%Z--CST)%n%d(%%--%)%n%d(%J--%J)%ndate end%n\"\n\nsimple = \"simple - %m%n\"\n\ntext = \"text - text%n\"\n\nms = \"ms - %d(%a--Wed)[%d(%ms)]%n\"\n\nmsus = \"msus - %d(%ms,%us,%ms,%us)%n\"\n\n[rules]\n*.* >stderr;\n*.* >stderr; null\n*.* >stderr; print\n*.* >stderr; date\n*.* >stderr; simple\n*.* >stderr; text\n*.* >stderr; ms\n*.* >stderr; msus" 2 | -------------------------------------------------------------------------------- /src/conf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_conf_h 10 | #define __zlog_conf_h 11 | 12 | #include "zc_defs.h" 13 | #include "format.h" 14 | #include "rotater.h" 15 | 16 | typedef struct zlog_conf_s { 17 | char file[MAXLEN_PATH + 1]; 18 | char cfg_ptr[MAXLEN_CFG_LINE*MAXLINES_NO]; 19 | char mtime[20 + 1]; 20 | 21 | int strict_init; 22 | size_t buf_size_min; 23 | size_t buf_size_max; 24 | 25 | char rotate_lock_file[MAXLEN_CFG_LINE + 1]; 26 | zlog_rotater_t *rotater; 27 | 28 | char default_format_line[MAXLEN_CFG_LINE + 1]; 29 | zlog_format_t *default_format; 30 | 31 | unsigned int file_perms; 32 | size_t fsync_period; 33 | size_t reload_conf_period; 34 | 35 | zc_arraylist_t *levels; 36 | zc_arraylist_t *formats; 37 | zc_arraylist_t *rules; 38 | int time_cache_count; 39 | } zlog_conf_t; 40 | 41 | extern zlog_conf_t * zlog_env_conf; 42 | 43 | zlog_conf_t *zlog_conf_new(const char *config); 44 | void zlog_conf_del(zlog_conf_t * a_conf); 45 | void zlog_conf_profile(zlog_conf_t * a_conf, int flag); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /test/test_leak.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | 17 | int main(int argc, char** argv) 18 | { 19 | int rc; 20 | int k; 21 | int i; 22 | 23 | if (argc != 2) { 24 | printf("test_leak ntime\n"); 25 | return -1; 26 | } 27 | 28 | rc = zlog_init("test_leak.conf"); 29 | 30 | k = atoi(argv[1]); 31 | while (k-- > 0) { 32 | i = rand(); 33 | switch (i % 4) { 34 | case 0: 35 | rc = dzlog_init("test_leak.conf", "xxx"); 36 | dzlog_info("init, rc=[%d]", rc); 37 | break; 38 | case 1: 39 | rc = zlog_reload(NULL); 40 | dzlog_info("reload null, rc=[%d]", rc); 41 | break; 42 | case 2: 43 | rc = zlog_reload("test_leak.2.conf"); 44 | dzlog_info("reload 2, rc=[%d]", rc); 45 | break; 46 | case 3: 47 | zlog_fini(); 48 | printf("fini\n"); 49 | // printf("zlog_finish\tj=[%d], rc=[%d]\n", j, rc); 50 | break; 51 | } 52 | } 53 | 54 | zlog_fini(); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | 17 | int main(int argc, char** argv) 18 | { 19 | int rc; 20 | 21 | zlog_category_t *zc; 22 | 23 | rc = zlog_init("test_init.conf"); 24 | if (rc) { 25 | printf("init fail"); 26 | return -2; 27 | } 28 | zc = zlog_get_category("my_cat"); 29 | if (!zc) { 30 | printf("zlog_get_category fail\n"); 31 | zlog_fini(); 32 | return -1; 33 | } 34 | zlog_info(zc, "before update"); 35 | sleep(1); 36 | rc = zlog_reload("test_init.2.conf"); 37 | if (rc) { 38 | printf("update fail\n"); 39 | } 40 | zlog_info(zc, "after update"); 41 | zlog_profile(); 42 | zlog_fini(); 43 | 44 | sleep(1); 45 | zlog_init("test_init.conf"); 46 | zc = zlog_get_category("my_cat"); 47 | if (!zc) { 48 | printf("zlog_get_category fail\n"); 49 | zlog_fini(); 50 | return -1; 51 | } 52 | zlog_info(zc, "init again"); 53 | zlog_fini(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_level.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * The zlog Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * The zlog Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with the zlog Library. If not, see . 18 | */ 19 | 20 | #ifndef __test_level_h 21 | #define __test_level_h 22 | 23 | #include "zlog.h" 24 | 25 | enum { 26 | ZLOG_LEVEL_TRACE = 30, 27 | /* must equals conf file setting */ 28 | }; 29 | 30 | #define zlog_trace(cat, format, args...) \ 31 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 32 | ZLOG_LEVEL_TRACE, format, ##args) 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /test/test_press_syslog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int work(long loop_count) 17 | { 18 | while(loop_count-- > 0) { 19 | syslog(LOG_INFO, "loglog"); 20 | } 21 | return 0; 22 | } 23 | 24 | 25 | int test(long process_count, long loop_count) 26 | { 27 | long i; 28 | pid_t pid; 29 | 30 | for (i = 0; i < process_count; i++) { 31 | pid = fork(); 32 | if (pid < 0) { 33 | printf("fork fail\n"); 34 | } else if(pid == 0) { 35 | work(loop_count); 36 | return 0; 37 | } 38 | } 39 | 40 | for (i = 0; i < process_count; i++) { 41 | pid = wait(NULL); 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | 48 | int main(int argc, char** argv) 49 | { 50 | 51 | if (argc != 3) { 52 | fprintf(stderr, "test nprocess nloop"); 53 | exit(1); 54 | } 55 | 56 | openlog(NULL, LOG_NDELAY|LOG_NOWAIT|LOG_PID, LOG_LOCAL0); 57 | 58 | test(atol(argv[1]), atol(argv[2])); 59 | 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /test/test_conf.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | strict init = true 3 | buffer min= 1024 4 | buffer max= 2MB 5 | rotate lock file = /tmp/zlog.lock 6 | default format = "defalut - %d(%F %X.%ms) %-6V (%c:%F:%U:%L) - %m%n" 7 | 8 | [formats] 9 | null = "%n" 10 | print = "print - [%-10.3d(%F)]%n" 11 | 12 | date = "date start%n%d(%a--Wed)%n%d(%A--Wednesday)%n%d(%b--Mar)%n%d(%B--March)%n%d(%c--WedMar211:45:262011)%n%d(%C--20)%n%d(%d--02)%n%d(%D--03/02/11)%n%d(%e--2)%n%d(%F--2011-03-02)%n%d(%g--11)%n%d(%G--2011)%n%d(%h--Mar)%n%d(%H--11)%n%d(%I--11)%n%d(%j--061)%n%d(%k-k)%n%d(%l-l)%n%d(%ms--500)%n%d(%m--03)%n%d(%M--45)%n%d(%us--500730)%n%d(%p--AM)%n%d(%r--11:45:26AM)%n%d(%R--11:45)%n%d(%s--epoch)%n%d(%S--26)%n%d(%t--)%n%d(%T--11:45:26)%n%d(%u--3)%n%d(%U--09)%n%d(%V--09)%n%d(%w--3)%n%d(%W--09)%n%d(%x--03/02/11)%n%d(%X--11:45:26)%n%d(%y--11)%n%d(%Y--2011)%n%d(%z--+0800)%n%d(%Z--CST)%n%d(%%--%)%n%d(%J--%J)%ndate end%n" 13 | 14 | simple = "simple - %m%n" 15 | 16 | text = "text - text%n" 17 | 18 | ms = "ms - %d(%a--Wed)[%d(%ms)]%n" 19 | 20 | msus = "msus - %d(%ms,%us,%ms,%us)%n" 21 | 22 | [rules] 23 | *.* >stderr; 24 | *.* >stderr; null 25 | *.* >stderr; print 26 | *.* >stderr; date 27 | *.* >stderr; simple 28 | *.* >stderr; text 29 | *.* >stderr; ms 30 | *.* >stderr; msus 31 | -------------------------------------------------------------------------------- /test/test_enabled.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2018 by Teracom Telemática S/A 5 | * 6 | * The zlog Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * The zlog Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with the zlog Library. If not, see . 18 | */ 19 | 20 | #ifndef __test_level_h 21 | #define __test_level_h 22 | 23 | #include "zlog.h" 24 | 25 | enum { 26 | ZLOG_LEVEL_TRACE = 30, 27 | /* must equals conf file setting */ 28 | }; 29 | 30 | #define zlog_trace(cat, format, args...) \ 31 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 32 | ZLOG_LEVEL_TRACE, format, ##args) 33 | 34 | #define zlog_trace_enabled(cat) zlog_level_enabled(cat, ZLOG_LEVEL_TRACE) 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/category.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_category_h 10 | #define __zlog_category_h 11 | 12 | #include "zc_defs.h" 13 | #include "thread.h" 14 | 15 | typedef struct zlog_category_s { 16 | char name[MAXLEN_PATH + 1]; 17 | size_t name_len; 18 | unsigned char level_bitmap[32]; 19 | unsigned char level_bitmap_backup[32]; 20 | zc_arraylist_t *fit_rules; 21 | zc_arraylist_t *fit_rules_backup; 22 | } zlog_category_t; 23 | 24 | zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules); 25 | void zlog_category_del(zlog_category_t * a_category); 26 | void zlog_category_profile(zlog_category_t *a_category, int flag); 27 | 28 | int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules); 29 | void zlog_category_commit_rules(zlog_category_t * a_category); 30 | void zlog_category_rollback_rules(zlog_category_t * a_category); 31 | 32 | int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread); 33 | 34 | #define zlog_category_needless_level(a_category, lv) \ 35 | a_category && !((a_category->level_bitmap[lv/8] >> (7 - lv % 8)) & 0x01) 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/rotater.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_rotater_h 10 | #define __zlog_rotater_h 11 | 12 | #include "zc_defs.h" 13 | 14 | typedef struct zlog_rotater_s { 15 | pthread_mutex_t lock_mutex; 16 | char *lock_file; 17 | int lock_fd; 18 | 19 | /* single-use members */ 20 | char *base_path; /* aa.log */ 21 | char *archive_path; /* aa.#5i.log */ 22 | char glob_path[MAXLEN_PATH + 1]; /* aa.*.log */ 23 | size_t num_start_len; /* 3, offset to glob_path */ 24 | size_t num_end_len; /* 6, offset to glob_path */ 25 | int num_width; /* 5 */ 26 | int mv_type; /* ROLLING or SEQUENCE */ 27 | int max_count; 28 | zc_arraylist_t *files; 29 | } zlog_rotater_t; 30 | 31 | zlog_rotater_t *zlog_rotater_new(char *lock_file); 32 | void zlog_rotater_del(zlog_rotater_t *a_rotater); 33 | 34 | /* 35 | * return 36 | * -1 fail 37 | * 0 no rotate, or rotate and success 38 | */ 39 | int zlog_rotater_rotate(zlog_rotater_t *a_rotater, 40 | char *base_path, size_t msg_len, 41 | char *archive_path, long archive_max_size, int archive_max_count); 42 | 43 | void zlog_rotater_profile(zlog_rotater_t *a_rotater, int flag); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/zc_arraylist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zc_arraylist_h 10 | #define __zc_arraylist_h 11 | 12 | #define ARRAY_LIST_DEFAULT_SIZE 32 13 | 14 | typedef void (*zc_arraylist_del_fn) (void *data); 15 | typedef int (*zc_arraylist_cmp_fn) (void *data1, void *data2); 16 | 17 | /* make zc_arraylist_foreach speed up, so keep struct defination here */ 18 | typedef struct { 19 | void **array; 20 | int len; 21 | int size; 22 | zc_arraylist_del_fn del; 23 | } zc_arraylist_t; 24 | 25 | zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del); 26 | void zc_arraylist_del(zc_arraylist_t * a_list); 27 | 28 | int zc_arraylist_set(zc_arraylist_t * a_list, int i, void *data); 29 | int zc_arraylist_add(zc_arraylist_t * a_list, void *data); 30 | int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp, 31 | void *data); 32 | 33 | #define zc_arraylist_len(a_list) (a_list->len) 34 | 35 | #define zc_arraylist_get(a_list, i) \ 36 | ((i >= a_list->len) ? NULL : a_list->array[i]) 37 | 38 | #define zc_arraylist_foreach(a_list, i, a_unit) \ 39 | for(i = 0, a_unit = a_list->array[0]; (i < a_list->len) && (a_unit = a_list->array[i], 1) ; i++) 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/record.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | #include "errno.h" 9 | #include "zc_defs.h" 10 | #include "record.h" 11 | 12 | void zlog_record_profile(zlog_record_t *a_record, int flag) 13 | { 14 | zc_assert(a_record,); 15 | zc_profile(flag, "--record:[%p][%s:%p]--", a_record, a_record->name, a_record->output); 16 | return; 17 | } 18 | 19 | void zlog_record_del(zlog_record_t *a_record) 20 | { 21 | zc_assert(a_record,); 22 | zc_debug("zlog_record_del[%p]", a_record); 23 | free(a_record); 24 | return; 25 | } 26 | 27 | zlog_record_t *zlog_record_new(const char *name, zlog_record_fn output) 28 | { 29 | zlog_record_t *a_record; 30 | 31 | zc_assert(name, NULL); 32 | zc_assert(output, NULL); 33 | 34 | a_record = calloc(1, sizeof(zlog_record_t)); 35 | if (!a_record) { 36 | zc_error("calloc fail, errno[%d]", errno); 37 | return NULL; 38 | } 39 | 40 | if (strlen(name) > sizeof(a_record->name) - 1) { 41 | zc_error("name[%s] is too long", name); 42 | goto err; 43 | } 44 | 45 | strcpy(a_record->name, name); 46 | a_record->output = output; 47 | 48 | zlog_record_profile(a_record, ZC_DEBUG); 49 | return a_record; 50 | err: 51 | zlog_record_del(a_record); 52 | return NULL; 53 | } 54 | -------------------------------------------------------------------------------- /test/test_longlog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zlog.h" 11 | #include 12 | #include 13 | 14 | #define str "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" 15 | #define str2 str str 16 | #define str4 str2 str2 17 | #define str8 str4 str4 18 | #define str16 str8 str8 19 | #define str32 str16 str16 20 | #define str64 str32 str32 21 | 22 | int main(int argc, char** argv) 23 | { 24 | int i, k; 25 | int rc; 26 | zlog_category_t *zc; 27 | 28 | if (argc != 2) { 29 | printf("useage: test_longlog [count]\n"); 30 | exit(1); 31 | } 32 | 33 | rc = zlog_init("test_longlog.conf"); 34 | if (rc) { 35 | printf("init failed\n"); 36 | return -1; 37 | } 38 | 39 | zc = zlog_get_category("my_cat"); 40 | if (!zc) { 41 | printf("get cat fail\n"); 42 | zlog_fini(); 43 | return -2; 44 | } 45 | 46 | k = atoi(argv[1]); 47 | while (k-- > 0) { 48 | i = rand(); 49 | switch (i % 3) { 50 | case 0: 51 | zlog_info(zc, str32); 52 | break; 53 | case 1: 54 | zlog_info(zc, str64); 55 | break; 56 | case 2: 57 | zlog_info(zc, str16); 58 | break; 59 | } 60 | } 61 | 62 | 63 | zlog_fini(); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test/test_hashtable.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zc_profile.c" 16 | #include "zc_hashtable.h" 17 | #include "zc_hashtable.c" 18 | 19 | void myfree(void *kv) 20 | { 21 | } 22 | 23 | int main(void) 24 | { 25 | zc_hashtable_t *a_table; 26 | zc_hashtable_entry_t *a_entry; 27 | 28 | a_table = zc_hashtable_new(20, 29 | zc_hashtable_str_hash, 30 | zc_hashtable_str_equal, 31 | myfree, myfree); 32 | 33 | zc_hashtable_put(a_table, "aaa", "bnbb"); 34 | zc_hashtable_put(a_table, "bbb", "bnbb"); 35 | zc_hashtable_put(a_table, "ccc", "bnbb"); 36 | 37 | zc_hashtable_put(a_table, "aaa", "123"); 38 | 39 | zc_hashtable_foreach(a_table, a_entry) { 40 | printf("k[%s],v[%s]\n", (char*)a_entry->key, (char*)a_entry->value); 41 | } 42 | 43 | printf("getv[%s]\n", (char*)zc_hashtable_get(a_table, "ccc")); 44 | 45 | zc_hashtable_remove(a_table, "ccc"); 46 | 47 | zc_hashtable_foreach(a_table, a_entry) { 48 | printf("k[%s],v[%s]\n", (char*)a_entry->key, (char*)a_entry->value); 49 | } 50 | 51 | 52 | zc_hashtable_remove(a_table, NULL); 53 | zc_hashtable_del(NULL); 54 | 55 | zc_hashtable_del(a_table); 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/zlog-chk-conf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include "fmacros.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include "zlog.h" 19 | #include "version.h" 20 | 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | int rc = 0; 25 | int op; 26 | int quiet = 0; 27 | static const char *help = 28 | "usage: zlog-chk-conf [conf files]...\n" 29 | "\t-q,\tsuppress non-error message\n" 30 | "\t-h,\tshow help message\n" 31 | "zlog version: " ZLOG_VERSION "\n"; 32 | 33 | while((op = getopt(argc, argv, "qhv")) > 0) { 34 | if (op == 'h') { 35 | fputs(help, stdout); 36 | return 0; 37 | } else if (op == 'q') { 38 | quiet = 1; 39 | } 40 | } 41 | 42 | argc -= optind; 43 | argv += optind; 44 | 45 | if (argc == 0) { 46 | fputs(help, stdout); 47 | return -1; 48 | } 49 | 50 | setenv("ZLOG_PROFILE_ERROR", "/dev/stderr", 1); 51 | setenv("ZLOG_CHECK_FORMAT_RULE", "1", 1); 52 | 53 | while (argc > 0) { 54 | rc = zlog_init(*argv); 55 | if (rc) { 56 | printf("\n---[%s] syntax error, see error message above\n", 57 | *argv); 58 | exit(2); 59 | } else { 60 | zlog_fini(); 61 | if (!quiet) { 62 | printf("--[%s] syntax right\n", *argv); 63 | } 64 | } 65 | argc--; 66 | argv++; 67 | } 68 | 69 | exit(0); 70 | } 71 | -------------------------------------------------------------------------------- /src/zc_profile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zc_profile_h 10 | #define __zc_profile_h 11 | 12 | #include 13 | 14 | #define EMPTY() 15 | #define zc_assert(expr, rv) \ 16 | if(!(expr)) { \ 17 | zc_error(#expr" is null or 0"); \ 18 | return rv; \ 19 | } 20 | 21 | enum zc_profile_flag { 22 | ZC_DEBUG = 0, 23 | ZC_WARN = 1, 24 | ZC_ERROR = 2 25 | }; 26 | 27 | 28 | #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L 29 | #define zc_debug(...) \ 30 | zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 31 | #define zc_warn(...) \ 32 | zc_profile_inner(ZC_WARN, __FILE__, __LINE__, __VA_ARGS__) 33 | #define zc_error(...) \ 34 | zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, __VA_ARGS__) 35 | #define zc_profile(flag, ...) \ 36 | zc_profile_inner(flag, __FILE__, __LINE__, __VA_ARGS__) 37 | #elif defined __GNUC__ 38 | #define zc_debug(fmt, args...) \ 39 | zc_profile_inner(ZC_DEBUG, __FILE__, __LINE__, fmt, ## args) 40 | #define zc_warn(fmt, args...) \ 41 | zc_profile_inner(ZC_WARN, __FILE__, __LINE__, fmt, ## args) 42 | #define zc_error(fmt, args...) \ 43 | zc_profile_inner(ZC_ERROR, __FILE__, __LINE__, fmt, ## args) 44 | #define zc_profile(flag, fmt, args...) \ 45 | zc_profile_inner(flag, __FILE__, __LINE__, fmt, ## args) 46 | #endif 47 | 48 | 49 | int zc_profile_inner(int flag, 50 | const char *file, const long line, 51 | const char *fmt, ...); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/record_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zc_defs.h" 14 | #include "record_table.h" 15 | 16 | void zlog_record_table_profile(zc_hashtable_t * records, int flag) 17 | { 18 | zc_hashtable_entry_t *a_entry; 19 | zlog_record_t *a_record; 20 | 21 | zc_assert(records,); 22 | zc_profile(flag, "-record_table[%p]-", records); 23 | zc_hashtable_foreach(records, a_entry) { 24 | a_record = (zlog_record_t *) a_entry->value; 25 | zlog_record_profile(a_record, flag); 26 | } 27 | return; 28 | } 29 | 30 | /*******************************************************************************/ 31 | 32 | void zlog_record_table_del(zc_hashtable_t * records) 33 | { 34 | zc_assert(records,); 35 | zc_hashtable_del(records); 36 | zc_debug("zlog_record_table_del[%p]", records); 37 | return; 38 | } 39 | 40 | zc_hashtable_t *zlog_record_table_new(void) 41 | { 42 | zc_hashtable_t *records; 43 | 44 | records = zc_hashtable_new(20, 45 | (zc_hashtable_hash_fn) zc_hashtable_str_hash, 46 | (zc_hashtable_equal_fn) zc_hashtable_str_equal, 47 | NULL, (zc_hashtable_del_fn) zlog_record_del); 48 | if (!records) { 49 | zc_error("zc_hashtable_new fail"); 50 | return NULL; 51 | } else { 52 | zlog_record_table_profile(records, ZC_DEBUG); 53 | return records; 54 | } 55 | } 56 | /*******************************************************************************/ 57 | -------------------------------------------------------------------------------- /src/zc_xplatform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | #ifndef __zc_xplatform_h 9 | #define __zc_xplatform_h 10 | 11 | #include 12 | 13 | #define ZLOG_INT32_LEN sizeof("-2147483648") - 1 14 | #define ZLOG_INT64_LEN sizeof("-9223372036854775808") - 1 15 | 16 | #if ((__GNU__ == 2) && (__GNUC_MINOR__ < 8)) 17 | #define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffffLL 18 | #else 19 | #define ZLOG_MAX_UINT32_VALUE (uint32_t) 0xffffffff 20 | #endif 21 | 22 | #define ZLOG_MAX_INT32_VALUE (uint32_t) 0x7fffffff 23 | 24 | #define MAXLEN_PATH 1024 25 | #define MAXLEN_CFG_LINE (MAXLEN_PATH * 4) 26 | #define MAXLINES_NO 128 27 | 28 | #define FILE_NEWLINE "\n" 29 | #define FILE_NEWLINE_LEN 1 30 | 31 | #include 32 | #include 33 | 34 | #define STRCMP(_a_,_C_,_b_) ( strcmp(_a_,_b_) _C_ 0 ) 35 | #define STRNCMP(_a_,_C_,_b_,_n_) ( strncmp(_a_,_b_,_n_) _C_ 0 ) 36 | #define STRICMP(_a_,_C_,_b_) ( strcasecmp(_a_,_b_) _C_ 0 ) 37 | #define STRNICMP(_a_,_C_,_b_,_n_) ( strncasecmp(_a_,_b_,_n_) _C_ 0 ) 38 | 39 | 40 | #ifdef __APPLE__ 41 | #include 42 | #endif 43 | 44 | /* Define zlog_fstat to fstat or fstat64() */ 45 | #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) 46 | #define zlog_fstat fstat64 47 | #define zlog_stat stat64 48 | #else 49 | #define zlog_fstat fstat 50 | #define zlog_stat stat 51 | #endif 52 | 53 | /* Define zlog_fsync to fdatasync() in Linux and fsync() for all the rest */ 54 | #ifdef __linux__ 55 | #define zlog_fsync fdatasync 56 | #else 57 | #define zlog_fsync fsync 58 | #endif 59 | 60 | 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/spec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_spec_h 10 | #define __zlog_spec_h 11 | 12 | #include "event.h" 13 | #include "buf.h" 14 | #include "thread.h" 15 | 16 | typedef struct zlog_spec_s zlog_spec_t; 17 | 18 | /* write buf, according to each spec's Conversion Characters */ 19 | typedef int (*zlog_spec_write_fn) (zlog_spec_t * a_spec, 20 | zlog_thread_t * a_thread, 21 | zlog_buf_t * a_buf); 22 | 23 | /* gen a_thread->msg or gen a_thread->path by using write_fn */ 24 | typedef int (*zlog_spec_gen_fn) (zlog_spec_t * a_spec, 25 | zlog_thread_t * a_thread); 26 | 27 | struct zlog_spec_s { 28 | char *str; 29 | int len; 30 | 31 | char time_fmt[MAXLEN_CFG_LINE + 1]; 32 | int time_cache_index; 33 | char mdc_key[MAXLEN_PATH + 1]; 34 | 35 | char print_fmt[MAXLEN_CFG_LINE + 1]; 36 | int left_adjust; 37 | int left_fill_zeros; 38 | size_t max_width; 39 | size_t min_width; 40 | 41 | zlog_spec_write_fn write_buf; 42 | zlog_spec_gen_fn gen_msg; 43 | zlog_spec_gen_fn gen_path; 44 | zlog_spec_gen_fn gen_archive_path; 45 | }; 46 | 47 | zlog_spec_t *zlog_spec_new(char *pattern_start, char **pattern_end, int * time_cache_count); 48 | void zlog_spec_del(zlog_spec_t * a_spec); 49 | void zlog_spec_profile(zlog_spec_t * a_spec, int flag); 50 | 51 | #define zlog_spec_gen_msg(a_spec, a_thread) \ 52 | a_spec->gen_msg(a_spec, a_thread) 53 | 54 | #define zlog_spec_gen_path(a_spec, a_thread) \ 55 | a_spec->gen_path(a_spec, a_thread) 56 | 57 | #define zlog_spec_gen_archive_path(a_spec, a_thread) \ 58 | a_spec->gen_archive_path(a_spec, a_thread) 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /test/test_press_zlog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "zlog.h" 17 | 18 | static zlog_category_t *zc; 19 | static long loop_count; 20 | 21 | void * work(void *ptr) 22 | { 23 | long j = loop_count; 24 | while(j-- > 0) { 25 | zlog_info(zc, "loglog"); 26 | } 27 | return 0; 28 | } 29 | 30 | 31 | int test(long process_count, long thread_count) 32 | { 33 | long i; 34 | pid_t pid; 35 | long j; 36 | 37 | for (i = 0; i < process_count; i++) { 38 | pid = fork(); 39 | if (pid < 0) { 40 | printf("fork fail\n"); 41 | } else if(pid == 0) { 42 | pthread_t tid[thread_count]; 43 | for (j = 0; j < thread_count; j++) { 44 | pthread_create(&(tid[j]), NULL, work, NULL); 45 | } 46 | for (j = 0; j < thread_count; j++) { 47 | pthread_join(tid[j], NULL); 48 | } 49 | return 0; 50 | } 51 | } 52 | 53 | for (i = 0; i < process_count; i++) { 54 | pid = wait(NULL); 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | 61 | int main(int argc, char** argv) 62 | { 63 | int rc; 64 | 65 | if (argc != 4) { 66 | fprintf(stderr, "test nprocess nthreads nloop\n"); 67 | exit(1); 68 | } 69 | 70 | rc = zlog_init("test_press_zlog.conf"); 71 | if (rc) { 72 | printf("init failed\n"); 73 | return 2; 74 | } 75 | 76 | zc = zlog_get_category("my_cat"); 77 | if (!zc) { 78 | printf("get cat failed\n"); 79 | zlog_fini(); 80 | return 3; 81 | } 82 | 83 | loop_count = atol(argv[3]); 84 | test(atol(argv[1]), atol(argv[2])); 85 | 86 | zlog_fini(); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /src/buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_buf_h 10 | #define __zlog_buf_h 11 | 12 | /* buf, is a dynamic expand buffer for one single log, 13 | * as one single log will interlace if use multiple write() to file. 14 | * and buf is always keep in a thread, to make each thread has its 15 | * own buffer to avoid lock. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | typedef struct zlog_buf_s { 22 | char *start; 23 | char *tail; 24 | char *end; 25 | char *end_plus_1; 26 | 27 | size_t size_min; 28 | size_t size_max; 29 | size_t size_real; 30 | 31 | char truncate_str[MAXLEN_PATH + 1]; 32 | size_t truncate_str_len; 33 | } zlog_buf_t; 34 | 35 | 36 | zlog_buf_t *zlog_buf_new(size_t min, size_t max, const char *truncate_str); 37 | void zlog_buf_del(zlog_buf_t * a_buf); 38 | void zlog_buf_profile(zlog_buf_t * a_buf, int flag); 39 | 40 | int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args); 41 | int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len); 42 | int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len, 43 | int left_adjust, int zero_pad, size_t in_width, size_t out_width); 44 | int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width); 45 | int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width); 46 | int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width); 47 | 48 | #define zlog_buf_restart(a_buf) do { \ 49 | a_buf->tail = a_buf->start; \ 50 | } while(0) 51 | 52 | #define zlog_buf_len(a_buf) (a_buf->tail - a_buf->start) 53 | #define zlog_buf_str(a_buf) (a_buf->start) 54 | #define zlog_buf_seal(a_buf) do {*(a_buf)->tail = '\0';} while (0) 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /test/test_press_zlog2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "zlog.h" 19 | 20 | static long loop_count; 21 | 22 | 23 | void * work(void *ptr) 24 | { 25 | long j = loop_count; 26 | char category[20]; 27 | sprintf(category, "cat%ld", (long)ptr); 28 | zlog_category_t *zc; 29 | 30 | zc = zlog_get_category(category); 31 | 32 | while(j-- > 0) { 33 | zlog_info(zc, "loglog"); 34 | } 35 | return 0; 36 | } 37 | 38 | 39 | int test(long process_count, long thread_count) 40 | { 41 | long i; 42 | pid_t pid; 43 | long j; 44 | 45 | for (i = 0; i < process_count; i++) { 46 | pid = fork(); 47 | if (pid < 0) { 48 | printf("fork fail\n"); 49 | } else if(pid == 0) { 50 | pthread_t tid[thread_count]; 51 | 52 | for (j = 0; j < thread_count; j++) { 53 | pthread_create(&(tid[j]), NULL, work, (void*)j); 54 | } 55 | for (j = 0; j < thread_count; j++) { 56 | pthread_join(tid[j], NULL); 57 | } 58 | return 0; 59 | } 60 | } 61 | 62 | for (i = 0; i < process_count; i++) { 63 | pid = wait(NULL); 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int main(int argc, char** argv) 71 | { 72 | int rc = 0; 73 | if (argc != 4) { 74 | fprintf(stderr, "test nprocess nthreads nloop\n"); 75 | exit(1); 76 | } 77 | 78 | rc = zlog_init("test_press_zlog2.conf"); 79 | if (rc) { 80 | printf("init failed\n"); 81 | return 2; 82 | } 83 | 84 | loop_count = atol(argv[3]); 85 | test(atol(argv[1]), atol(argv[2])); 86 | 87 | zlog_fini(); 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /src/zc_hashtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zc_hashtalbe_h 10 | #define __zc_hashtalbe_h 11 | 12 | #include 13 | 14 | typedef struct zc_hashtable_entry_s { 15 | unsigned int hash_key; 16 | void *key; 17 | void *value; 18 | struct zc_hashtable_entry_s *prev; 19 | struct zc_hashtable_entry_s *next; 20 | } zc_hashtable_entry_t; 21 | 22 | typedef struct zc_hashtable_s zc_hashtable_t; 23 | 24 | typedef unsigned int (*zc_hashtable_hash_fn) (const void *key); 25 | typedef int (*zc_hashtable_equal_fn) (const void *key1, const void *key2); 26 | typedef void (*zc_hashtable_del_fn) (void *kv); 27 | 28 | zc_hashtable_t *zc_hashtable_new(size_t a_size, 29 | zc_hashtable_hash_fn hash_fn, 30 | zc_hashtable_equal_fn equal_fn, 31 | zc_hashtable_del_fn key_del_fn, 32 | zc_hashtable_del_fn value_del_fn); 33 | 34 | void zc_hashtable_del(zc_hashtable_t * a_table); 35 | void zc_hashtable_clean(zc_hashtable_t * a_table); 36 | int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value); 37 | zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key); 38 | void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key); 39 | void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key); 40 | zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table); 41 | zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry); 42 | 43 | #define zc_hashtable_foreach(a_table, a_entry) \ 44 | for(a_entry = zc_hashtable_begin(a_table); a_entry; a_entry = zc_hashtable_next(a_table, a_entry)) 45 | 46 | unsigned int zc_hashtable_str_hash(const void *str); 47 | int zc_hashtable_str_equal(const void *key1, const void *key2); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /test/test_press_write2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "zlog.h" 19 | 20 | static long loop_count; 21 | 22 | 23 | void * work(void *ptr) 24 | { 25 | long j = loop_count; 26 | static char log[] = "2012-06-14 20:30:38.481187 INFO 24536:140716226213632:test_press_zlog.c:36 loglog\n"; 27 | char file[20]; 28 | 29 | sprintf(file, "press.%ld.log", (long)ptr); 30 | 31 | int fd; 32 | fd = open(file, O_CREAT | O_WRONLY | O_APPEND , 0644); 33 | //FILE *fp; 34 | 35 | while(j-- > 0) { 36 | write(fd, log, sizeof(log)-1); 37 | //fwrite(log, sizeof(log)-1, 1, fp); 38 | } 39 | //fclose(fp); 40 | close(fd); 41 | return 0; 42 | } 43 | 44 | 45 | int test(long process_count, long thread_count) 46 | { 47 | long i; 48 | pid_t pid; 49 | long j; 50 | 51 | for (i = 0; i < process_count; i++) { 52 | pid = fork(); 53 | if (pid < 0) { 54 | printf("fork fail\n"); 55 | } else if(pid == 0) { 56 | pthread_t tid[thread_count]; 57 | 58 | for (j = 0; j < thread_count; j++) { 59 | pthread_create(&(tid[j]), NULL, work, (void*)j); 60 | } 61 | for (j = 0; j < thread_count; j++) { 62 | pthread_join(tid[j], NULL); 63 | } 64 | return 0; 65 | } 66 | } 67 | 68 | for (i = 0; i < process_count; i++) { 69 | pid = wait(NULL); 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | 76 | int main(int argc, char** argv) 77 | { 78 | if (argc != 4) { 79 | fprintf(stderr, "test nprocess nthreads nloop\n"); 80 | exit(1); 81 | } 82 | 83 | 84 | loop_count = atol(argv[3]); 85 | test(atol(argv[1]), atol(argv[2])); 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /test/test_press_write.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #include "zlog.h" 20 | 21 | int fd; 22 | static long loop_count; 23 | 24 | 25 | void * work(void *ptr) 26 | { 27 | long j = loop_count; 28 | static char aa[] = "2012-06-14 20:30:38.481187 INFO 24536:140716226213632:test_press_zlog.c:36 loglog\n"; 29 | 30 | while(j-- > 0) { 31 | // fprintf(fp, "2012-05-16 17:24:58.282603 INFO 22471:test_press_zlog.c:33 loglog\n"); 32 | // fwrite(aa, sizeof(aa)-1, 1, fp); 33 | write(fd, aa, sizeof(aa)-1); 34 | } 35 | return 0; 36 | } 37 | 38 | 39 | int test(long process_count, long thread_count) 40 | { 41 | long i; 42 | pid_t pid; 43 | long j; 44 | 45 | for (i = 0; i < process_count; i++) { 46 | pid = fork(); 47 | if (pid < 0) { 48 | printf("fork fail\n"); 49 | } else if(pid == 0) { 50 | pthread_t tid[thread_count]; 51 | 52 | for (j = 0; j < thread_count; j++) { 53 | pthread_create(&(tid[j]), NULL, work, NULL); 54 | } 55 | for (j = 0; j < thread_count; j++) { 56 | pthread_join(tid[j], NULL); 57 | } 58 | return 0; 59 | } 60 | } 61 | 62 | for (i = 0; i < process_count; i++) { 63 | pid = wait(NULL); 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int main(int argc, char** argv) 71 | { 72 | if (argc != 4) { 73 | fprintf(stderr, "test nprocess nthreads nloop\n"); 74 | exit(1); 75 | } 76 | 77 | 78 | fd = open("press.log", O_CREAT | O_WRONLY | O_APPEND, 0644); 79 | //fp = fdopen(fd, "a"); 80 | loop_count = atol(argv[3]); 81 | test(atol(argv[1]), atol(argv[2])); 82 | //fclose(fp); 83 | close(fd); 84 | 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /src/zc_profile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include "fmacros.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "zc_profile.h" 21 | #include "zc_xplatform.h" 22 | 23 | static void zc_time(char *time_str, size_t time_str_size) 24 | { 25 | time_t tt; 26 | struct tm local_time; 27 | 28 | time(&tt); 29 | localtime_r(&tt, &local_time); 30 | strftime(time_str, time_str_size, "%m-%d %T", &local_time); 31 | 32 | return; 33 | } 34 | 35 | int zc_profile_inner(int flag, const char *file, const long line, const char *fmt, ...) 36 | { 37 | va_list args; 38 | char time_str[20 + 1]; 39 | FILE *fp = NULL; 40 | 41 | static char *debug_log = NULL; 42 | static char *error_log = NULL; 43 | static size_t init_flag = 0; 44 | 45 | if (!init_flag) { 46 | init_flag = 1; 47 | debug_log = getenv("ZLOG_PROFILE_DEBUG"); 48 | error_log = getenv("ZLOG_PROFILE_ERROR"); 49 | } 50 | 51 | switch (flag) { 52 | case ZC_DEBUG: 53 | if (debug_log == NULL) return 0; 54 | fp = fopen(debug_log, "a"); 55 | if (!fp) return -1; 56 | zc_time(time_str, sizeof(time_str)); 57 | fprintf(fp, "%s DEBUG (%d:%s:%ld) ", time_str, getpid(), file, line); 58 | break; 59 | case ZC_WARN: 60 | if (error_log == NULL) return 0; 61 | fp = fopen(error_log, "a"); 62 | if (!fp) return -1; 63 | zc_time(time_str, sizeof(time_str)); 64 | fprintf(fp, "%s WARN (%d:%s:%ld) ", time_str, getpid(), file, line); 65 | break; 66 | case ZC_ERROR: 67 | if (error_log == NULL) return 0; 68 | fp = fopen(error_log, "a"); 69 | if (!fp) return -1; 70 | zc_time(time_str, sizeof(time_str)); 71 | fprintf(fp, "%s ERROR (%d:%s:%ld) ", time_str, getpid(), file, line); 72 | break; 73 | } 74 | 75 | /* writing file twice(time & msg) is not atomic 76 | * may cause cross 77 | * but avoid log size limit */ 78 | va_start(args, fmt); 79 | vfprintf(fp, fmt, args); 80 | va_end(args); 81 | fprintf(fp, "\n"); 82 | 83 | fclose(fp); 84 | return 0; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /doc/performence.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------- 2 | using makefile.linux for test, libzlog compile in O2 3 | ------------------------------------------------- 4 | [direct write, no logging library] - The Sky! 5 | $ time ./test_press_write 1 10 100000 6 | real 0m1.872s 7 | user 0m0.140s 8 | sys 0m3.290s 9 | 10 | $ time ./test_press_write2 1 10 100000 11 | real 0m0.909s 12 | user 0m0.080s 13 | sys 0m1.710s 14 | ------------------------------------------------- 15 | v1.1.1 (fwrite is not atomic, so backup to write) 16 | $ time ./test_press_zlog 1 10 100000 17 | real 0m2.334s 18 | user 0m1.780s 19 | sys 0m2.710s 20 | 21 | $ time ./test_press_zlog2 1 10 100000 22 | real 0m2.134s 23 | user 0m1.840s 24 | sys 0m1.990s 25 | ------------------------------------------------- 26 | v1.1.0 27 | $ time ./test_press_zlog 1 10 100000 28 | real 0m1.107s 29 | user 0m1.500s 30 | sys 0m0.340s 31 | 32 | $ time ./test_press_zlog2 1 10 100000 33 | real 0m0.898s 34 | user 0m1.480s 35 | sys 0m0.150s 36 | ------------------------------------------------- 37 | v1.0.7 38 | $ time ./test_press_zlog 1 10 100000 39 | real 0m1.783s 40 | user 0m3.000s 41 | sys 0m0.300s 42 | 43 | $ time ./test_press_zlog2 1 10 100000 44 | real 0m1.621s 45 | user 0m2.980s 46 | sys 0m0.120s 47 | ------------------------------------------------- 48 | v1.0.6 49 | $ time ./test_press_zlog 1 10 100000 50 | real 0m1.814s 51 | user 0m3.060s 52 | sys 0m0.270s 53 | 54 | $ time ./test_press_zlog2 1 10 100000 55 | real 0m1.605s 56 | user 0m2.990s 57 | sys 0m0.140s 58 | ------------------------------------------------- 59 | v1.0.5 60 | $ time ./test_press_zlog 1 10 100000 61 | real 0m2.779s 62 | user 0m4.170s 63 | sys 0m0.560s 64 | 65 | $ time ./test_press_zlog2 1 10 100000 66 | real 0m2.713s 67 | user 0m4.410s 68 | sys 0m0.900s 69 | ------------------------------------------------- 70 | v1.0.3 71 | $ time ./test_press_zlog 1 10 100000 72 | 73 | real 0m6.349s 74 | user 0m6.300s 75 | sys 0m5.950s 76 | 77 | $ time ./test_press_zlog2 1 10 100000 78 | real 0m6.377s 79 | user 0m6.240s 80 | sys 0m6.090s 81 | ------------------------------------------------- 82 | v1.0.0 83 | $ time ./test_press_zlog 1 10 100000 84 | real 0m6.364s 85 | user 0m6.040s 86 | sys 0m6.270s 87 | 88 | $ time ./test_press_zlog2 1 10 100000 89 | real 0m6.361s 90 | user 0m6.150s 91 | sys 0m6.020s 92 | ------------------------------------------------- 93 | -------------------------------------------------------------------------------- /src/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_event_h 10 | #define __zlog_event_h 11 | 12 | #include /* for pid_t */ 13 | #include /* for struct timeval */ 14 | #include /* for pthread_t */ 15 | #include /* for va_list */ 16 | #include "zc_defs.h" 17 | 18 | typedef enum { 19 | ZLOG_FMT = 0, 20 | ZLOG_HEX = 1, 21 | } zlog_event_cmd; 22 | 23 | typedef struct zlog_time_cache_s { 24 | char str[MAXLEN_CFG_LINE + 1]; 25 | size_t len; 26 | time_t sec; 27 | } zlog_time_cache_t; 28 | 29 | typedef struct { 30 | char *category_name; 31 | size_t category_name_len; 32 | char host_name[256 + 1]; 33 | size_t host_name_len; 34 | 35 | const char *file; 36 | size_t file_len; 37 | const char *func; 38 | size_t func_len; 39 | long line; 40 | int level; 41 | 42 | const void *hex_buf; 43 | size_t hex_buf_len; 44 | const char *str_format; 45 | va_list str_args; 46 | zlog_event_cmd generate_cmd; 47 | 48 | struct timeval time_stamp; 49 | 50 | time_t time_local_sec; 51 | struct tm time_local; 52 | 53 | zlog_time_cache_t *time_caches; 54 | int time_cache_count; 55 | 56 | pid_t pid; 57 | pid_t last_pid; 58 | char pid_str[30 + 1]; 59 | size_t pid_str_len; 60 | 61 | pthread_t tid; 62 | char tid_str[30 + 1]; 63 | size_t tid_str_len; 64 | 65 | char tid_hex_str[30 + 1]; 66 | size_t tid_hex_str_len; 67 | 68 | #if defined __linux__ || __APPLE__ 69 | pid_t ktid; 70 | char ktid_str[30+1]; 71 | size_t ktid_str_len; 72 | #endif 73 | } zlog_event_t; 74 | 75 | 76 | zlog_event_t *zlog_event_new(int time_cache_count); 77 | void zlog_event_del(zlog_event_t * a_event); 78 | void zlog_event_profile(zlog_event_t * a_event, int flag); 79 | 80 | void zlog_event_set_fmt(zlog_event_t * a_event, 81 | char *category_name, size_t category_name_len, 82 | const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, 83 | const char *str_format, va_list str_args); 84 | 85 | void zlog_event_set_hex(zlog_event_t * a_event, 86 | char *category_name, size_t category_name_len, 87 | const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, 88 | const void *hex_buf, size_t hex_buf_len); 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/rule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | /** 10 | * @file rule.h 11 | * @brief rule decide to output in format by category & level 12 | */ 13 | 14 | #ifndef __zlog_rule_h 15 | #define __zlog_rule_h 16 | 17 | #include 18 | #include 19 | 20 | #include "zc_defs.h" 21 | #include "format.h" 22 | #include "thread.h" 23 | #include "rotater.h" 24 | #include "record.h" 25 | 26 | typedef struct zlog_rule_s zlog_rule_t; 27 | 28 | typedef int (*zlog_rule_output_fn) (zlog_rule_t * a_rule, zlog_thread_t * a_thread); 29 | 30 | struct zlog_rule_s { 31 | char category[MAXLEN_CFG_LINE + 1]; 32 | char compare_char; 33 | /* 34 | * [*] log all level 35 | * [.] log level >= rule level, default 36 | * [=] log level == rule level 37 | * [!] log level != rule level 38 | */ 39 | int level; 40 | unsigned char level_bitmap[32]; /* for category determine whether output or not */ 41 | 42 | unsigned int file_perms; 43 | int file_open_flags; 44 | 45 | char file_path[MAXLEN_PATH + 1]; 46 | zc_arraylist_t *dynamic_specs; 47 | int static_fd; 48 | dev_t static_dev; 49 | ino_t static_ino; 50 | 51 | long archive_max_size; 52 | int archive_max_count; 53 | char archive_path[MAXLEN_PATH + 1]; 54 | zc_arraylist_t *archive_specs; 55 | 56 | FILE *pipe_fp; 57 | int pipe_fd; 58 | 59 | size_t fsync_period; 60 | size_t fsync_count; 61 | 62 | zc_arraylist_t *levels; 63 | int syslog_facility; 64 | 65 | zlog_format_t *format; 66 | zlog_rule_output_fn output; 67 | 68 | char record_name[MAXLEN_PATH + 1]; 69 | char record_path[MAXLEN_PATH + 1]; 70 | zlog_record_fn record_func; 71 | }; 72 | 73 | zlog_rule_t *zlog_rule_new(char * line, 74 | zc_arraylist_t * levels, 75 | zlog_format_t * default_format, 76 | zc_arraylist_t * formats, 77 | unsigned int file_perms, 78 | size_t fsync_period, 79 | int * time_cache_count); 80 | 81 | void zlog_rule_del(zlog_rule_t * a_rule); 82 | void zlog_rule_profile(zlog_rule_t * a_rule, int flag); 83 | int zlog_rule_match_category(zlog_rule_t * a_rule, char *category); 84 | int zlog_rule_is_wastebin(zlog_rule_t * a_rule); 85 | int zlog_rule_set_record(zlog_rule_t * a_rule, zc_hashtable_t *records); 86 | int zlog_rule_output(zlog_rule_t * a_rule, zlog_thread_t * a_thread); 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /test/test_hex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "zlog.h" 16 | #include "stdlib.h" 17 | 18 | static int ReadTotalFile( FILE * fp , char ** ptr , long * len ) 19 | { 20 | long fileLen ; 21 | int nret ; 22 | char * pStart ; 23 | 24 | *ptr = NULL; 25 | 26 | nret = fseek( fp , 0L , SEEK_END ); 27 | if( nret ) 28 | { 29 | return -1; 30 | } 31 | 32 | fileLen = ftell( fp ); 33 | if( fileLen < 0 ) 34 | { 35 | return -2; 36 | } 37 | 38 | if( ( pStart = calloc(1, fileLen+1) ) == NULL ) 39 | { 40 | return -3; 41 | } 42 | 43 | nret = fseek( fp , 0L , SEEK_SET ); 44 | if( nret ) 45 | { 46 | free( pStart ); 47 | return -4; 48 | } 49 | 50 | nret = fread( pStart , fileLen , 1 , fp ); 51 | if( ferror( fp ) ) 52 | { 53 | free( pStart ); 54 | return -5; 55 | } 56 | 57 | *ptr = pStart; 58 | *len = fileLen; 59 | 60 | return 0; 61 | } 62 | 63 | int main(int argc, char** argv) 64 | { 65 | int rc; 66 | 67 | FILE *fp; 68 | char *dmp; 69 | long dmp_len = 0; 70 | int ntimes; 71 | 72 | if (argc != 3) { 73 | printf("useage: test_hex [file] [ntimes]\n"); 74 | exit(1); 75 | } 76 | 77 | fp = fopen(argv[1], "r"); 78 | if (!fp) { 79 | printf("fopen[%s] fail\n", argv[1]); 80 | exit(1); 81 | } 82 | 83 | ntimes = atoi(argv[2]); 84 | 85 | zlog_category_t *zc; 86 | 87 | rc = zlog_init("test_hex.conf"); 88 | if (rc) { 89 | printf("init failed\n"); 90 | return -1; 91 | } 92 | 93 | zc = zlog_get_category("my_cat"); 94 | if (!zc) { 95 | printf("get category failed\n"); 96 | zlog_fini(); 97 | return -2; 98 | } 99 | 100 | 101 | rc = ReadTotalFile(fp, &dmp, &dmp_len); 102 | 103 | while(ntimes--) hzlog_debug(zc, dmp, dmp_len); 104 | 105 | fclose(fp); 106 | free(dmp); 107 | 108 | zlog_fini(); 109 | printf("hex log end\n"); 110 | 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /test/test_buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include "zc_defs.h" 11 | #include "buf.h" 12 | 13 | int main(int argc, char** argv) 14 | { 15 | zlog_buf_t *a_buf; 16 | char *aa; 17 | 18 | a_buf = zlog_buf_new(10, 20, "ABC"); 19 | if (!a_buf) { 20 | zc_error("zlog_buf_new fail"); 21 | return -1; 22 | } 23 | 24 | aa = "123456789"; 25 | zlog_buf_append(a_buf, aa, strlen(aa)); 26 | zc_error("a_buf->start[%s]", a_buf->start); 27 | fwrite(a_buf->start, zlog_buf_len(a_buf), 1, stdout); 28 | zc_error("------------"); 29 | 30 | aa = "0"; 31 | zlog_buf_append(a_buf, aa, strlen(aa)); 32 | zc_error("a_buf->start[%s]", a_buf->start); 33 | zc_error("------------"); 34 | 35 | aa = "12345"; 36 | zlog_buf_append(a_buf, aa, strlen(aa)); 37 | zc_error("a_buf->start[%s]", a_buf->start); 38 | zc_error("------------"); 39 | 40 | aa = "6789"; 41 | zlog_buf_append(a_buf, aa, strlen(aa)); 42 | zc_error("a_buf->start[%s]", a_buf->start); 43 | zc_error("------------"); 44 | 45 | aa = "0"; 46 | zlog_buf_append(a_buf, aa, strlen(aa)); 47 | zc_error("a_buf->start[%s]", a_buf->start); 48 | zc_error("------------"); 49 | 50 | aa = "22345"; 51 | zlog_buf_append(a_buf, aa, strlen(aa)); 52 | zc_error("a_buf->start[%s]", a_buf->start); 53 | zc_error("------------"); 54 | 55 | 56 | aa = "abc"; 57 | int i,j; 58 | for (i = 0; i <= 5; i++) { 59 | for (j = 0; j <= 5; j++) { 60 | zlog_buf_restart(a_buf); 61 | zc_error("left[1],max[%d],min[%d]", i, j); 62 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 1, 0, i, j); 63 | zc_error("a_buf->start[%s]", a_buf->start); 64 | 65 | zc_error("-----"); 66 | 67 | zlog_buf_restart(a_buf); 68 | zc_error("left[0],max[%d],min[%d]", i, j); 69 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 0, 0, i, j); 70 | zc_error("a_buf->start[%s]", a_buf->start); 71 | zc_error("------------"); 72 | } 73 | } 74 | 75 | aa = "1234567890"; 76 | zc_error("left[0],max[%d],min[%d]", 15, 5); 77 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 0, 0, 15, 5); 78 | zc_error("a_buf->start[%s]", a_buf->start); 79 | zc_error("------------"); 80 | 81 | aa = "1234567890"; 82 | zlog_buf_restart(a_buf); 83 | zc_error("left[0],max[%d],min[%d]", 25, 5); 84 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 1, 0, 25, 5); 85 | zc_error("a_buf->start[%s]", a_buf->start); 86 | zc_error("------------"); 87 | 88 | zlog_buf_restart(a_buf); 89 | zc_error("left[0],max[%d],min[%d]", 19, 5); 90 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 0, 0, 19, 5); 91 | zc_error("a_buf->start[%s]", a_buf->start); 92 | zc_error("------------"); 93 | 94 | zlog_buf_restart(a_buf); 95 | zc_error("left[0],max[%d],min[%d]", 20, 5); 96 | zlog_buf_adjust_append(a_buf, aa, strlen(aa), 0, 0, 20, 5); 97 | zc_error("a_buf->start[%s]", a_buf->start); 98 | zc_error("------------"); 99 | 100 | zlog_buf_del(a_buf); 101 | 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /doc/GettingStart-CN.txt: -------------------------------------------------------------------------------- 1 | 0. zlog是什么? 2 | 3 | zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库。 4 | 5 | 事实上,在C的世界里面没有特别好的日志函数库(就像JAVA里面的的log4j,或者C++的log4cxx)。C程序员都喜欢用自己的轮子。printf就是个挺好的轮子,但没办法通过配置改变日志的格式或者输出文件。syslog是个系统级别的轮子,不过速度慢,而且功能比较单调。 6 | 所以我写了zlog。 7 | zlog在效率、功能、安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性。 8 | 9 | 1.安装 10 | 11 | 下载:https://github.com/HardySimpson/zlog/releases 12 | 13 | $ tar -zxvf zlog-latest-stable.tar.gz 14 | $ cd zlog-latest-stable/ 15 | $ make 16 | $ sudo make install 17 | or 18 | $ make PREFIX=/usr/local/ 19 | $ sudo make PREFIX=/usr/local/ install 20 | 21 | PREFIX指明了安装的路径,安转完之后为了让你的程序能找到zlog动态库 22 | 23 | $ sudo vi /etc/ld.so.conf 24 | /usr/local/lib 25 | $ sudo ldconfig 26 | 27 | 在你的程序运行之前,保证libzlog.so在系统的动态链接库加载器可以找到的目录下。上面的命令适用于linux,别的系统自己想办法。 28 | 29 | 30 | 2.介绍一下配置文件 31 | 32 | zlog里面有三个重要的概念,category,format,rule 33 | 34 | 分类(Category)用于区分不同的输入,代码中的分类变量的名字是一个字符串,在一个程序里面可以通过获取不同的分类名的category用来后面输出不同分类的日志,用于不同的目的。 35 | 36 | 格式(Format)是用来描述输出日志的格式,比如是否有带有时间戳, 是否包含文件位置信息等,上面的例子里面的格式simple就配置成简单的用户输入的信息+换行符。 37 | 38 | 规则(Rule)则是把分类、级别、输出文件、格式组合起来,决定一条代码中的日志是否输出,输出到哪里,以什么格式输出。简单而言,规则里面的分类字符串和代码里面的分类变量的名字一样就匹配,当然还有更高级的纲目分类匹配。规则彻底解耦了各个元素之间的强绑定,例如log4j就必须为每个分类指定一个级别(或者从父分类那里继承),这在多层系统需要每一层都有自己的级别要求的时候非常不方便。 39 | 40 | 现在试着写配置文件,配置文件名无所谓,放在哪里也无所谓,反正在zlog_init()的时候可以指定 41 | $ cat /etc/zlog.conf 42 | 43 | [formats] 44 | simple = "%m%n" 45 | [rules] 46 | my_cat.DEBUG >stdout; simple 47 | 48 | 在目前的配置文件的例子里面,可以看到my_cat分类,>=debug等级的日志会被输出到stdout(标准输出),并且输出的格式是simple这个格式,也就是用户输入信息+换行符。如果要输出到文件并控制文件大小为1兆,规则的配置应该是 49 | my_cat.DEBUG "/var/log/aa.log", 1M; simple 50 | 51 | 3.在代码中使用 52 | $ vi test_hello.c 53 | 54 | #include 55 | 56 | #include "zlog.h" 57 | 58 | int main(int argc, char** argv) 59 | { 60 | int rc; 61 | zlog_category_t *c; 62 | 63 | rc = zlog_init("/etc/zlog.conf"); 64 | if (rc) { 65 | printf("init failed\n"); 66 | return -1; 67 | } 68 | 69 | c = zlog_get_category("my_cat"); 70 | if (!c) { 71 | printf("get cat fail\n"); 72 | zlog_fini(); 73 | return -2; 74 | } 75 | 76 | zlog_info(c, "hello, zlog"); 77 | 78 | zlog_fini(); 79 | 80 | return 0; 81 | } 82 | 83 | 4.编译、然后运行! 84 | 85 | $ cc -c -o test_hello.o test_hello.c -I/usr/local/include 86 | $ cc -o test_hello test_hello.o -L/usr/local/lib -lzlog -lpthread 87 | $ ./test_hello 88 | hello, zlog 89 | 90 | 5.高级使用 91 | * syslog分类模型,比log4j模型更加直接了当 92 | * 日志格式定制,类似于log4j的pattern layout 93 | * 多种输出,包括动态文件、静态文件、stdout、stderr、syslog、用户自定义输出函数 94 | * 运行时手动、自动刷新配置文件(同时保证安全) 95 | * 高性能,在我的笔记本上达到25万条日志每秒, 大概是syslog(3)配合rsyslogd的1000倍速度 96 | * 用户自定义等级 97 | * 多线程和多进程环境下保证安全转档 98 | * 精确到微秒 99 | * 简单调用包装dzlog(一个程序默认只用一个分类) 100 | * MDC,线程键-值对的表,可以扩展用户自定义的字段 101 | * 自诊断,可以在运行时输出zlog自己的日志和配置状态 102 | * 不依赖其他库,只要是个POSIX系统就成(当然还要一个C99兼容的vsnprintf) 103 | 104 | 6.相关链接 105 | 主页:http://hardysimpson.github.com/zlog/ 106 | 软件下载:https://github.com/HardySimpson/zlog/releases 107 | 作者邮箱:HardySimpson1984@gmail.com 108 | 109 | auto tools版本: https://github.com/bmanojlovic/zlog 110 | cmake版本: https://github.com/lisongmin/zlog 111 | windows版本: https://github.com/lopsd07/WinZlog 112 | -------------------------------------------------------------------------------- /src/zc_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "zc_defs.h" 17 | 18 | size_t zc_parse_byte_size(char *astring) 19 | { 20 | /* Parse size in bytes depending on the suffix. Valid suffixes are KB, MB and GB */ 21 | char *p; 22 | char *q; 23 | size_t sz; 24 | long res; 25 | int c, m; 26 | 27 | zc_assert(astring, 0); 28 | 29 | /* clear space */ 30 | for (p = q = astring; *p != '\0'; p++) { 31 | if (isspace(*p)) { 32 | continue; 33 | } else { 34 | *q = *p; 35 | q++; 36 | } 37 | } 38 | *q = '\0'; 39 | 40 | sz = strlen(astring); 41 | res = strtol(astring, (char **)NULL, 10); 42 | 43 | if (res <= 0) 44 | return 0; 45 | 46 | if (astring[sz - 1] == 'B' || astring[sz - 1] == 'b') { 47 | c = astring[sz - 2]; 48 | m = 1024; 49 | } else { 50 | c = astring[sz - 1]; 51 | m = 1000; 52 | } 53 | 54 | switch (c) { 55 | case 'K': 56 | case 'k': 57 | res *= m; 58 | break; 59 | case 'M': 60 | case 'm': 61 | res *= m * m; 62 | break; 63 | case 'G': 64 | case 'g': 65 | res *= m * m * m; 66 | break; 67 | default: 68 | if (!isdigit(c)) { 69 | zc_error("Wrong suffix parsing " "size in bytes for string [%s], ignoring suffix", 70 | astring); 71 | } 72 | break; 73 | } 74 | 75 | return (res); 76 | } 77 | 78 | /*******************************************************************************/ 79 | int zc_str_replace_env(char *str, size_t str_size) 80 | { 81 | char *p; 82 | char *q; 83 | char fmt[MAXLEN_CFG_LINE + 1]; 84 | char env_key[MAXLEN_CFG_LINE + 1]; 85 | char env_value[MAXLEN_CFG_LINE + 1]; 86 | int str_len; 87 | int env_value_len; 88 | int nscan; 89 | int nread; 90 | 91 | str_len = strlen(str); 92 | q = str; 93 | 94 | do { 95 | p = strchr(q, '%'); 96 | if (!p) { 97 | /* can't find more % */ 98 | break; 99 | } 100 | 101 | memset(fmt, 0x00, sizeof(fmt)); 102 | memset(env_key, 0x00, sizeof(env_key)); 103 | memset(env_value, 0x00, sizeof(env_value)); 104 | nread = 0; 105 | nscan = sscanf(p + 1, "%[.0-9-]%n", fmt + 1, &nread); 106 | if (nscan == 1) { 107 | fmt[0] = '%'; 108 | fmt[nread + 1] = 's'; 109 | } else { 110 | nread = 0; 111 | strcpy(fmt, "%s"); 112 | } 113 | 114 | q = p + 1 + nread; 115 | 116 | nscan = sscanf(q, "E(%[^)])%n", env_key, &nread); 117 | if (nscan == 0) { 118 | continue; 119 | } 120 | 121 | q += nread; 122 | 123 | if (*(q - 1) != ')') { 124 | zc_error("in string[%s] can't find match )", p); 125 | return -1; 126 | } 127 | 128 | env_value_len = snprintf(env_value, sizeof(env_value), fmt, getenv(env_key)); 129 | if (env_value_len < 0 || env_value_len >= sizeof(env_value)) { 130 | zc_error("snprintf fail, errno[%d], evn_value_len[%d]", 131 | errno, env_value_len); 132 | return -1; 133 | } 134 | 135 | str_len = str_len - (q - p) + env_value_len; 136 | if (str_len > str_size - 1) { 137 | zc_error("repalce env_value[%s] cause overlap", env_value); 138 | return -1; 139 | } 140 | 141 | memmove(p + env_value_len, q, strlen(q) + 1); 142 | memcpy(p, env_value, env_value_len); 143 | 144 | } while (1); 145 | 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /src/zc_arraylist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "zc_defs.h" 15 | 16 | zc_arraylist_t *zc_arraylist_new(zc_arraylist_del_fn del) 17 | { 18 | zc_arraylist_t *a_list; 19 | 20 | a_list = (zc_arraylist_t *) calloc(1, sizeof(zc_arraylist_t)); 21 | if (!a_list) { 22 | zc_error("calloc fail, errno[%d]", errno); 23 | return NULL; 24 | } 25 | a_list->size = ARRAY_LIST_DEFAULT_SIZE; 26 | a_list->len = 0; 27 | 28 | /* this could be NULL */ 29 | a_list->del = del; 30 | a_list->array = (void **)calloc(a_list->size, sizeof(void *)); 31 | if (!a_list->array) { 32 | zc_error("calloc fail, errno[%d]", errno); 33 | free(a_list); 34 | return NULL; 35 | } 36 | 37 | return a_list; 38 | } 39 | 40 | void zc_arraylist_del(zc_arraylist_t * a_list) 41 | { 42 | int i; 43 | 44 | if (!a_list) 45 | return; 46 | if (a_list->del) { 47 | for (i = 0; i < a_list->len; i++) { 48 | if (a_list->array[i]) 49 | a_list->del(a_list->array[i]); 50 | } 51 | } 52 | if (a_list->array) 53 | free(a_list->array); 54 | free(a_list); 55 | return; 56 | } 57 | 58 | static int zc_arraylist_expand_inner(zc_arraylist_t * a_list, int max) 59 | { 60 | void *tmp; 61 | int new_size; 62 | int diff_size; 63 | 64 | new_size = zc_max(a_list->size * 2, max); 65 | tmp = realloc(a_list->array, new_size * sizeof(void *)); 66 | if (!tmp) { 67 | zc_error("realloc fail, errno[%d]", errno); 68 | return -1; 69 | } 70 | a_list->array = (void **)tmp; 71 | diff_size = new_size - a_list->size; 72 | if (diff_size) memset(a_list->array + a_list->size, 0x00, diff_size * sizeof(void *)); 73 | a_list->size = new_size; 74 | return 0; 75 | } 76 | 77 | int zc_arraylist_set(zc_arraylist_t * a_list, int idx, void *data) 78 | { 79 | if (idx > a_list->size - 1) { 80 | if (zc_arraylist_expand_inner(a_list, idx)) { 81 | zc_error("expand_internal fail"); 82 | return -1; 83 | } 84 | } 85 | if (a_list->array[idx] && a_list->del) a_list->del(a_list->array[idx]); 86 | a_list->array[idx] = data; 87 | if (a_list->len <= idx) 88 | a_list->len = idx + 1; 89 | return 0; 90 | } 91 | 92 | int zc_arraylist_add(zc_arraylist_t * a_list, void *data) 93 | { 94 | return zc_arraylist_set(a_list, a_list->len, data); 95 | } 96 | 97 | /* assum idx < len */ 98 | static int zc_arraylist_insert_inner(zc_arraylist_t * a_list, int idx, 99 | void *data) 100 | { 101 | if (a_list->array[idx] == NULL) { 102 | a_list->array[idx] = data; 103 | return 0; 104 | } 105 | if (a_list->len > a_list->size - 1) { 106 | if (zc_arraylist_expand_inner(a_list, 0)) { 107 | zc_error("expand_internal fail"); 108 | return -1; 109 | } 110 | } 111 | memmove(a_list->array + idx + 1, a_list->array + idx, 112 | (a_list->len - idx) * sizeof(void *)); 113 | a_list->array[idx] = data; 114 | a_list->len++; 115 | return 0; 116 | } 117 | 118 | int zc_arraylist_sortadd(zc_arraylist_t * a_list, zc_arraylist_cmp_fn cmp, 119 | void *data) 120 | { 121 | int i; 122 | 123 | for (i = 0; i < a_list->len; i++) { 124 | if ((*cmp) (a_list->array[i], data) > 0) 125 | break; 126 | } 127 | 128 | if (i == a_list->len) 129 | return zc_arraylist_add(a_list, data); 130 | else 131 | return zc_arraylist_insert_inner(a_list, i, data); 132 | } 133 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | --- 1.2.12 --- 2 | [o] bugfix for avoid segmentation fault if call zlog_init() many times 3 | [o] static file rule to emulate python's WatchedFileHandler mode when used with external log rotation 4 | --- 1.2.10 --- 5 | [o] bugfix, LGPL v3 -> LGPL v2.1 6 | --- 1.2.8 --- 7 | [o] gcc __attribute__宏,用于检查zlog的format输出格式 8 | [o] 支持配置文件行中带#注释 9 | --- 1.2.5 --- 10 | [o] 保证在单个线程退出的时候自动删除thread, 用atexit来注册函数解决主线程退出的问题 11 | [o] 缓存多个时间,保证所有的%d在strftime的时候都能每秒缓存,达到和原先%D一样的速度 12 | [o] 鉴于上面那点,去掉%D的使用,虽然库还支持,但文档和实例代码都用%d 13 | [o] 修复makefile静态链接zlog-chk-conf 14 | --- 1.2.4 --- 15 | [o] 不再维持thread_list链表,每次写日志时判断配置有无更新,来刷新每线程的缓存大小 16 | --- 1.2.0 --- 17 | [o] rotate和zip的方案 18 | [o] 把一部分static变量化为全局变量,减少接口参数 19 | [o] fstat64 20 | [o] pipe, cronolog 21 | [o] record忽略第二参数 22 | [o] __VA_ARGS__的跨平台 23 | [o] 增加git/版本在代码中的标志(redis) 24 | [o] 去除auto tools的使用,自行makefile[redis] 25 | [o] 宏都小写化 26 | [o] const 27 | [x] 每线程内置rule-> file fd write time 28 | [x] 用时间作为判断重载配置reload conf period,而不是次数,需要每次取时间计算,暂不考虑 29 | [x] zlog_set_conf("section", "command"); 30 | [x] format,spec,level采用直接数组的方式重写,性能提高不大 31 | [x] 增加manpage, df, 案例 32 | --- 1.1.3 --- 33 | [o] zlog_record动态一点 34 | --- 1.1.2 --- 35 | [o] 修正rule.c, path_buf封顶 36 | --- 1.1.1 --- 37 | [o] 修正rule.c, 不使用FILE*, 避免日志交错 38 | --- 1.1.0 --- 39 | [x] spec改为switch循环, 如果可能的话rule也照样--发现switch的效率不如函数指针 40 | [x] 把__LINE__ 变成string--需要改接口 41 | [o] 建立bit位来判断,无锁判断 42 | [o] 寻找快速的方法把us, srcline变成字符串 43 | [o] 在一开始就判断是否需要输出, 44 | [o] 使用pthread_key_t线程私有变量来存储zlog_thread_t,仅有1%不到的提高 45 | [o] 增加%D,缓存strftime的结果 46 | [o] 缓存pid, tid的字符串形式 47 | [o] 去掉rc的使用[redis] 48 | [o] 对ZLOG_FMT和ZLOG_HEX清算,部分成功 49 | --- 1.0.7 --- 50 | [x] 自己实现部分的strftime,进一步提高效率--替换后发现vsnprintf消耗增加,未能超越原有strftime的效率 51 | [o] %t显示为16进制 52 | [o] 零碎的性能优化,10%把 53 | --- 1.0.6 --- 54 | [o] 每秒取一次localtime_r,加速1倍以上 55 | --- 1.0.5 --- 56 | [o] 修复1.0.4的问题,reopen文件时用读写锁保护 57 | --- 1.0.4 --- 58 | [o] 测试多线程的效率 59 | [o] 缓存静态文件的FILE*和fd,优化,加速3倍 60 | --- 1.0.3 --- 61 | [o] 基于日志笔数自动刷新配置 62 | [o] 基于日志笔数自动做sync到硬盘操作 63 | --- 1.0.2 --- 64 | [o] 增加同步写入到硬盘选项,打开后极为费时 65 | --- 1.0.1 --- 66 | [o] 采用配置文件作为锁文件 67 | --- 1.0.0 --- 68 | [o] 改变配置文件的布局,去掉@ &这种符号,改用[global],[format]这样的形式来 69 | [o] 把reload改成原子性的,失败用旧的 70 | [o] 优化spec_gen_msg部分, spec内采用自己写的buf_append对齐来代替buf_sprintf 71 | [o] 引入__func__ 72 | [o] 文件的权限设置 73 | [o] 输出函数自定义 74 | --- 0.9 --- 75 | [o] 采用更加面向对象的方法来写 76 | [o] 使用arraylist来代替linklist为内部数据结构 77 | [o] 改进配置文件的格式 78 | [o] 打造线程安全的日志函数库 79 | [o] 解决微秒毫秒在配置中的表示 80 | [o] 把event并到thread内避免开内存 81 | [o] 增加init读取配置文件的api 82 | [o] default] format的解析,初始化全无的时候的输出,zlog_chk_conf的编写 83 | [o] 把category独立出来 84 | [o] 增加update接口 85 | [o] buf的大小无法通过zlog_init动态的改变,可以zlog_update重建所有缓存解决,呵呵 86 | [o] 调整文件创建权限,采用类似fopen的办法,为0666&(~umask) 87 | [o] syslog输出,搞定但发现syslog暴慢 88 | [o] 转档的模式,是否需要轮询等,解决为传统模式 89 | [o] 增加zlog_profile接口,诊断配置内存 90 | [o] 增加MDC,可配置的增加字段 91 | [o] 测试buf被重写的时候,是否会导致后面的\0没加 92 | [o] xlog要改名为zlog.... 93 | [o] 取一次ZLOG_ERROR_LOG和ZLOG_DEBUG_LOG,避免多次getenv 94 | [o] zc_assert一般关闭,调试打开 95 | [o] 增加!.*, 匹配未被匹配的分类 96 | [o] priority->level 97 | [o] level自定义 98 | [o] rule syslog open 99 | [o] default format移到全局配置 100 | [o] reset level, 用arraylist来做试试看 101 | [o] ylog, 更简单的接口, 改名为dzlog的一堆接口来解决 102 | [o] zlog-gen-conf 103 | [o] rotate控制个数 104 | --- 废弃想法 --- 105 | [x] 使用writev来写日志,提高效率,达到一次形成,多次输出的目的, writev内部也是开buffermemcpy 106 | [x] 尝试信号量的方法来打成线程安全的转档互斥问题 107 | [x] zlog.h变长参数宏的问题(参考glib的log解决) 108 | [x] rule的dynamic] file可以从format获取 109 | [x] 修改arraylist的读取长度,循环等 110 | [x] 运行期间指定是否采用线程 111 | [x] buf_append 优化——为了安全,不优化这个 112 | [x] 用某种自动编译器以及文档生成器 113 | [x] 输出到管道,有名管道和文件一样 114 | [x] 打印堆栈。。可能需要语言支持 115 | [x] zlog-input -c category -p priority -f conf 116 | [x] 采用精细的reo en方法来建立用fo en来智能判断需不需要重开文件,操作系统本身已经做得够好,无须做 117 | 118 | -------------------------------------------------------------------------------- /src/level.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "syslog.h" 13 | 14 | #include "zc_defs.h" 15 | #include "level.h" 16 | 17 | void zlog_level_profile(zlog_level_t *a_level, int flag) 18 | { 19 | zc_assert(a_level,); 20 | zc_profile(flag, "---level[%p][%d,%s,%s,%d,%d]---", 21 | a_level, 22 | a_level->int_level, 23 | a_level->str_uppercase, 24 | a_level->str_lowercase, 25 | (int) a_level->str_len, 26 | a_level->syslog_level); 27 | return; 28 | } 29 | 30 | /*******************************************************************************/ 31 | void zlog_level_del(zlog_level_t *a_level) 32 | { 33 | zc_assert(a_level,); 34 | zc_debug("zlog_level_del[%p]", a_level); 35 | free(a_level); 36 | return; 37 | } 38 | 39 | static int syslog_level_atoi(char *str) 40 | { 41 | /* guess no unix system will choose -187 42 | * as its syslog level, so it is a safe return value 43 | */ 44 | zc_assert(str, -187); 45 | 46 | if (STRICMP(str, ==, "LOG_EMERG")) 47 | return LOG_EMERG; 48 | if (STRICMP(str, ==, "LOG_ALERT")) 49 | return LOG_ALERT; 50 | if (STRICMP(str, ==, "LOG_CRIT")) 51 | return LOG_CRIT; 52 | if (STRICMP(str, ==, "LOG_ERR")) 53 | return LOG_ERR; 54 | if (STRICMP(str, ==, "LOG_WARNING")) 55 | return LOG_WARNING; 56 | if (STRICMP(str, ==, "LOG_NOTICE")) 57 | return LOG_NOTICE; 58 | if (STRICMP(str, ==, "LOG_INFO")) 59 | return LOG_INFO; 60 | if (STRICMP(str, ==, "LOG_DEBUG")) 61 | return LOG_DEBUG; 62 | 63 | zc_error("wrong syslog level[%s]", str); 64 | return -187; 65 | } 66 | 67 | /* line: TRACE = 10, LOG_ERR */ 68 | zlog_level_t *zlog_level_new(char *line) 69 | { 70 | zlog_level_t *a_level = NULL; 71 | int i; 72 | int nscan; 73 | char str[MAXLEN_CFG_LINE + 1]; 74 | int l = 0; 75 | char sl[MAXLEN_CFG_LINE + 1]; 76 | 77 | zc_assert(line, NULL); 78 | 79 | memset(str, 0x00, sizeof(str)); 80 | memset(sl, 0x00, sizeof(sl)); 81 | 82 | nscan = sscanf(line, " %[^= \t] = %d ,%s", str, &l, sl); 83 | if (nscan < 2) { 84 | zc_error("level[%s], syntax wrong", line); 85 | return NULL; 86 | } 87 | 88 | /* check level and str */ 89 | if ((l < 0) || (l > 255)) { 90 | zc_error("l[%d] not in [0,255], wrong", l); 91 | return NULL; 92 | } 93 | 94 | if (str[0] == '\0') { 95 | zc_error("str[0] = 0"); 96 | return NULL; 97 | } 98 | 99 | a_level = calloc(1, sizeof(zlog_level_t)); 100 | if (!a_level) { 101 | zc_error("calloc fail, errno[%d]", errno); 102 | return NULL; 103 | } 104 | 105 | a_level->int_level = l; 106 | 107 | /* fill syslog level */ 108 | if (sl[0] == '\0') { 109 | a_level->syslog_level = LOG_DEBUG; 110 | } else { 111 | a_level->syslog_level = syslog_level_atoi(sl); 112 | if (a_level->syslog_level == -187) { 113 | zc_error("syslog_level_atoi fail"); 114 | goto err; 115 | } 116 | } 117 | 118 | /* strncpy and toupper(str) */ 119 | for (i = 0; (i < sizeof(a_level->str_uppercase) - 1) && str[i] != '\0'; i++) { 120 | (a_level->str_uppercase)[i] = toupper(str[i]); 121 | (a_level->str_lowercase)[i] = tolower(str[i]); 122 | } 123 | 124 | if (str[i] != '\0') { 125 | /* overflow */ 126 | zc_error("not enough space for str, str[%s] > %d", str, i); 127 | goto err; 128 | } else { 129 | (a_level->str_uppercase)[i] = '\0'; 130 | (a_level->str_lowercase)[i] = '\0'; 131 | } 132 | 133 | a_level->str_len = i; 134 | 135 | //zlog_level_profile(a_level, ZC_DEBUG); 136 | return a_level; 137 | err: 138 | zc_error("line[%s]", line); 139 | zlog_level_del(a_level); 140 | return NULL; 141 | } 142 | -------------------------------------------------------------------------------- /src/mdc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "mdc.h" 14 | #include "zc_defs.h" 15 | 16 | void zlog_mdc_profile(zlog_mdc_t *a_mdc, int flag) 17 | { 18 | zc_hashtable_entry_t *a_entry; 19 | zlog_mdc_kv_t *a_mdc_kv; 20 | 21 | zc_assert(a_mdc,); 22 | zc_profile(flag, "---mdc[%p]---", a_mdc); 23 | 24 | zc_hashtable_foreach(a_mdc->tab, a_entry) { 25 | a_mdc_kv = a_entry->value; 26 | zc_profile(flag, "----mdc_kv[%p][%s]-[%s]----", 27 | a_mdc_kv, 28 | a_mdc_kv->key, a_mdc_kv->value); 29 | } 30 | return; 31 | } 32 | /*******************************************************************************/ 33 | void zlog_mdc_del(zlog_mdc_t * a_mdc) 34 | { 35 | zc_assert(a_mdc,); 36 | if (a_mdc->tab) zc_hashtable_del(a_mdc->tab); 37 | zc_debug("zlog_mdc_del[%p]", a_mdc); 38 | free(a_mdc); 39 | return; 40 | } 41 | 42 | static void zlog_mdc_kv_del(zlog_mdc_kv_t * a_mdc_kv) 43 | { 44 | zc_debug("zlog_mdc_kv_del[%p]", a_mdc_kv); 45 | free(a_mdc_kv); 46 | } 47 | 48 | static zlog_mdc_kv_t *zlog_mdc_kv_new(const char *key, const char *value) 49 | { 50 | zlog_mdc_kv_t *a_mdc_kv; 51 | 52 | a_mdc_kv = calloc(1, sizeof(zlog_mdc_kv_t)); 53 | if (!a_mdc_kv) { 54 | zc_error("calloc fail, errno[%d]", errno); 55 | return NULL; 56 | } 57 | 58 | snprintf(a_mdc_kv->key, sizeof(a_mdc_kv->key), "%s", key); 59 | a_mdc_kv->value_len = snprintf(a_mdc_kv->value, sizeof(a_mdc_kv->value), "%s", value); 60 | return a_mdc_kv; 61 | } 62 | 63 | zlog_mdc_t *zlog_mdc_new(void) 64 | { 65 | zlog_mdc_t *a_mdc; 66 | 67 | a_mdc = calloc(1, sizeof(zlog_mdc_t)); 68 | if (!a_mdc) { 69 | zc_error("calloc fail, errno[%d]", errno); 70 | return NULL; 71 | } 72 | 73 | a_mdc->tab = zc_hashtable_new(20, 74 | zc_hashtable_str_hash, 75 | zc_hashtable_str_equal, NULL, 76 | (zc_hashtable_del_fn) zlog_mdc_kv_del); 77 | if (!a_mdc->tab) { 78 | zc_error("zc_hashtable_new fail"); 79 | goto err; 80 | } 81 | 82 | //zlog_mdc_profile(a_mdc, ZC_DEBUG); 83 | return a_mdc; 84 | err: 85 | zlog_mdc_del(a_mdc); 86 | return NULL; 87 | } 88 | 89 | /*******************************************************************************/ 90 | int zlog_mdc_put(zlog_mdc_t * a_mdc, const char *key, const char *value) 91 | { 92 | zlog_mdc_kv_t *a_mdc_kv; 93 | 94 | a_mdc_kv = zlog_mdc_kv_new(key, value); 95 | if (!a_mdc_kv) { 96 | zc_error("zlog_mdc_kv_new failed"); 97 | return -1; 98 | } 99 | 100 | if (zc_hashtable_put(a_mdc->tab, a_mdc_kv->key, a_mdc_kv)) { 101 | zc_error("zc_hashtable_put fail"); 102 | zlog_mdc_kv_del(a_mdc_kv); 103 | return -1; 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | void zlog_mdc_clean(zlog_mdc_t * a_mdc) 110 | { 111 | zc_hashtable_clean(a_mdc->tab); 112 | return; 113 | } 114 | 115 | char *zlog_mdc_get(zlog_mdc_t * a_mdc, const char *key) 116 | { 117 | zlog_mdc_kv_t *a_mdc_kv; 118 | 119 | a_mdc_kv = zc_hashtable_get(a_mdc->tab, key); 120 | if (!a_mdc_kv) { 121 | zc_error("zc_hashtable_get fail"); 122 | return NULL; 123 | } else { 124 | return a_mdc_kv->value; 125 | } 126 | } 127 | 128 | zlog_mdc_kv_t *zlog_mdc_get_kv(zlog_mdc_t * a_mdc, const char *key) 129 | { 130 | zlog_mdc_kv_t *a_mdc_kv; 131 | 132 | a_mdc_kv = zc_hashtable_get(a_mdc->tab, key); 133 | if (!a_mdc_kv) { 134 | zc_error("zc_hashtable_get fail"); 135 | return NULL; 136 | } else { 137 | return a_mdc_kv; 138 | } 139 | } 140 | 141 | void zlog_mdc_remove(zlog_mdc_t * a_mdc, const char *key) 142 | { 143 | zc_hashtable_remove(a_mdc->tab, key); 144 | return; 145 | } 146 | -------------------------------------------------------------------------------- /src/category_table.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zc_defs.h" 14 | #include "category_table.h" 15 | 16 | void zlog_category_table_profile(zc_hashtable_t * categories, int flag) 17 | { 18 | zc_hashtable_entry_t *a_entry; 19 | zlog_category_t *a_category; 20 | 21 | zc_assert(categories,); 22 | zc_profile(flag, "-category_table[%p]-", categories); 23 | zc_hashtable_foreach(categories, a_entry) { 24 | a_category = (zlog_category_t *) a_entry->value; 25 | zlog_category_profile(a_category, flag); 26 | } 27 | return; 28 | } 29 | 30 | /*******************************************************************************/ 31 | 32 | void zlog_category_table_del(zc_hashtable_t * categories) 33 | { 34 | zc_assert(categories,); 35 | zc_hashtable_del(categories); 36 | zc_debug("zlog_category_table_del[%p]", categories); 37 | return; 38 | } 39 | 40 | zc_hashtable_t *zlog_category_table_new(void) 41 | { 42 | zc_hashtable_t *categories; 43 | 44 | categories = zc_hashtable_new(20, 45 | (zc_hashtable_hash_fn) zc_hashtable_str_hash, 46 | (zc_hashtable_equal_fn) zc_hashtable_str_equal, 47 | NULL, (zc_hashtable_del_fn) zlog_category_del); 48 | if (!categories) { 49 | zc_error("zc_hashtable_new fail"); 50 | return NULL; 51 | } else { 52 | zlog_category_table_profile(categories, ZC_DEBUG); 53 | return categories; 54 | } 55 | } 56 | /*******************************************************************************/ 57 | int zlog_category_table_update_rules(zc_hashtable_t * categories, zc_arraylist_t * new_rules) 58 | { 59 | zc_hashtable_entry_t *a_entry; 60 | zlog_category_t *a_category; 61 | 62 | zc_assert(categories, -1); 63 | zc_hashtable_foreach(categories, a_entry) { 64 | a_category = (zlog_category_t *) a_entry->value; 65 | if (zlog_category_update_rules(a_category, new_rules)) { 66 | zc_error("zlog_category_update_rules fail, try rollback"); 67 | return -1; 68 | } 69 | } 70 | return 0; 71 | } 72 | 73 | void zlog_category_table_commit_rules(zc_hashtable_t * categories) 74 | { 75 | zc_hashtable_entry_t *a_entry; 76 | zlog_category_t *a_category; 77 | 78 | zc_assert(categories,); 79 | zc_hashtable_foreach(categories, a_entry) { 80 | a_category = (zlog_category_t *) a_entry->value; 81 | zlog_category_commit_rules(a_category); 82 | } 83 | return; 84 | } 85 | 86 | void zlog_category_table_rollback_rules(zc_hashtable_t * categories) 87 | { 88 | zc_hashtable_entry_t *a_entry; 89 | zlog_category_t *a_category; 90 | 91 | zc_assert(categories,); 92 | zc_hashtable_foreach(categories, a_entry) { 93 | a_category = (zlog_category_t *) a_entry->value; 94 | zlog_category_rollback_rules(a_category); 95 | } 96 | return; 97 | } 98 | 99 | /*******************************************************************************/ 100 | zlog_category_t *zlog_category_table_fetch_category(zc_hashtable_t * categories, 101 | const char *category_name, zc_arraylist_t * rules) 102 | { 103 | zlog_category_t *a_category; 104 | 105 | zc_assert(categories, NULL); 106 | 107 | /* 1st find category in global category map */ 108 | a_category = zc_hashtable_get(categories, category_name); 109 | if (a_category) return a_category; 110 | 111 | /* else not found, create one */ 112 | a_category = zlog_category_new(category_name, rules); 113 | if (!a_category) { 114 | zc_error("zc_category_new fail"); 115 | return NULL; 116 | } 117 | 118 | if(zc_hashtable_put(categories, a_category->name, a_category)) { 119 | zc_error("zc_hashtable_put fail"); 120 | goto err; 121 | } 122 | 123 | return a_category; 124 | err: 125 | zlog_category_del(a_category); 126 | return NULL; 127 | } 128 | 129 | /*******************************************************************************/ 130 | -------------------------------------------------------------------------------- /src/level_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "syslog.h" 13 | 14 | #include "zc_defs.h" 15 | #include "level.h" 16 | #include "level_list.h" 17 | 18 | /* zlog_level_list == zc_arraylist_t */ 19 | 20 | void zlog_level_list_profile(zc_arraylist_t *levels, int flag) 21 | { 22 | int i; 23 | zlog_level_t *a_level; 24 | 25 | zc_assert(levels,); 26 | zc_profile(flag, "--level_list[%p]--", levels); 27 | zc_arraylist_foreach(levels, i, a_level) { 28 | /* skip empty slots */ 29 | if (a_level) zlog_level_profile(a_level, flag); 30 | } 31 | return; 32 | } 33 | 34 | /*******************************************************************************/ 35 | void zlog_level_list_del(zc_arraylist_t *levels) 36 | { 37 | zc_assert(levels,); 38 | zc_arraylist_del(levels); 39 | zc_debug("zc_level_list_del[%p]", levels); 40 | return; 41 | } 42 | 43 | static int zlog_level_list_set_default(zc_arraylist_t *levels) 44 | { 45 | return zlog_level_list_set(levels, "* = 0, LOG_INFO") 46 | || zlog_level_list_set(levels, "DEBUG = 20, LOG_DEBUG") 47 | || zlog_level_list_set(levels, "INFO = 40, LOG_INFO") 48 | || zlog_level_list_set(levels, "NOTICE = 60, LOG_NOTICE") 49 | || zlog_level_list_set(levels, "WARN = 80, LOG_WARNING") 50 | || zlog_level_list_set(levels, "ERROR = 100, LOG_ERR") 51 | || zlog_level_list_set(levels, "FATAL = 120, LOG_ALERT") 52 | || zlog_level_list_set(levels, "UNKNOWN = 254, LOG_ERR") 53 | || zlog_level_list_set(levels, "! = 255, LOG_INFO"); 54 | } 55 | 56 | zc_arraylist_t *zlog_level_list_new(void) 57 | { 58 | zc_arraylist_t *levels; 59 | 60 | levels = zc_arraylist_new((zc_arraylist_del_fn)zlog_level_del); 61 | if (!levels) { 62 | zc_error("zc_arraylist_new fail"); 63 | return NULL; 64 | } 65 | 66 | if (zlog_level_list_set_default(levels)) { 67 | zc_error("zlog_level_set_default fail"); 68 | goto err; 69 | } 70 | 71 | //zlog_level_list_profile(levels, ZC_DEBUG); 72 | return levels; 73 | err: 74 | zc_arraylist_del(levels); 75 | return NULL; 76 | } 77 | 78 | /*******************************************************************************/ 79 | int zlog_level_list_set(zc_arraylist_t *levels, char *line) 80 | { 81 | zlog_level_t *a_level; 82 | 83 | a_level = zlog_level_new(line); 84 | if (!a_level) { 85 | zc_error("zlog_level_new fail"); 86 | return -1; 87 | } 88 | 89 | if (zc_arraylist_set(levels, a_level->int_level, a_level)) { 90 | zc_error("zc_arraylist_set fail"); 91 | goto err; 92 | } 93 | 94 | return 0; 95 | err: 96 | zc_error("line[%s]", line); 97 | zlog_level_del(a_level); 98 | return -1; 99 | } 100 | 101 | zlog_level_t *zlog_level_list_get(zc_arraylist_t *levels, int l) 102 | { 103 | zlog_level_t *a_level; 104 | 105 | #if 0 106 | if ((l <= 0) || (l > 254)) { 107 | /* illegal input from zlog() */ 108 | zc_error("l[%d] not in (0,254), set to UNKOWN", l); 109 | l = 254; 110 | } 111 | #endif 112 | 113 | a_level = zc_arraylist_get(levels, l); 114 | if (a_level) { 115 | return a_level; 116 | } else { 117 | /* empty slot */ 118 | zc_error("l[%d] not in (0,254), or has no level defined," 119 | "see configure file define, set to UNKOWN", l); 120 | return zc_arraylist_get(levels, 254); 121 | } 122 | } 123 | 124 | /*******************************************************************************/ 125 | 126 | int zlog_level_list_atoi(zc_arraylist_t *levels, char *str) 127 | { 128 | int i; 129 | zlog_level_t *a_level; 130 | 131 | if (str == NULL || *str == '\0') { 132 | zc_error("str is [%s], can't find level", str); 133 | return -1; 134 | } 135 | 136 | zc_arraylist_foreach(levels, i, a_level) { 137 | if (a_level && STRICMP(str, ==, a_level->str_uppercase)) { 138 | return i; 139 | } 140 | } 141 | 142 | zc_error("str[%s] can't found in level list", str); 143 | return -1; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /src/format.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "zc_defs.h" 17 | #include "thread.h" 18 | #include "spec.h" 19 | #include "format.h" 20 | 21 | void zlog_format_profile(zlog_format_t * a_format, int flag) 22 | { 23 | 24 | zc_assert(a_format,); 25 | zc_profile(flag, "---format[%p][%s = %s(%p)]---", 26 | a_format, 27 | a_format->name, 28 | a_format->pattern, 29 | a_format->pattern_specs); 30 | 31 | #if 0 32 | int i; 33 | zlog_spec_t *a_spec; 34 | zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) { 35 | zlog_spec_profile(a_spec, flag); 36 | } 37 | #endif 38 | 39 | return; 40 | } 41 | 42 | /*******************************************************************************/ 43 | void zlog_format_del(zlog_format_t * a_format) 44 | { 45 | zc_assert(a_format,); 46 | if (a_format->pattern_specs) { 47 | zc_arraylist_del(a_format->pattern_specs); 48 | } 49 | zc_debug("zlog_format_del[%p]", a_format); 50 | free(a_format); 51 | return; 52 | } 53 | 54 | zlog_format_t *zlog_format_new(char *line, int * time_cache_count) 55 | { 56 | int nscan = 0; 57 | zlog_format_t *a_format = NULL; 58 | int nread = 0; 59 | const char *p_start; 60 | const char *p_end; 61 | char *p; 62 | char *q; 63 | zlog_spec_t *a_spec; 64 | 65 | zc_assert(line, NULL); 66 | 67 | a_format = calloc(1, sizeof(zlog_format_t)); 68 | if (!a_format) { 69 | zc_error("calloc fail, errno[%d]", errno); 70 | return NULL; 71 | } 72 | 73 | /* line default = "%d(%F %X.%l) %-6V (%c:%F:%L) - %m%n" 74 | * name default 75 | * pattern %d(%F %X.%l) %-6V (%c:%F:%L) - %m%n 76 | */ 77 | memset(a_format->name, 0x00, sizeof(a_format->name)); 78 | nread = 0; 79 | nscan = sscanf(line, " %[^= \t] = %n", a_format->name, &nread); 80 | if (nscan != 1) { 81 | zc_error("format[%s], syntax wrong", line); 82 | goto err; 83 | } 84 | 85 | if (*(line + nread) != '"') { 86 | zc_error("the 1st char of pattern is not \", line+nread[%s]", line+nread); 87 | goto err; 88 | } 89 | 90 | for (p = a_format->name; *p != '\0'; p++) { 91 | if ((!isalnum(*p)) && (*p != '_')) { 92 | zc_error("a_format->name[%s] character is not in [a-Z][0-9][_]", a_format->name); 93 | goto err; 94 | } 95 | } 96 | 97 | p_start = line + nread + 1; 98 | p_end = strrchr(p_start, '"'); 99 | if (!p_end) { 100 | zc_error("there is no \" at end of pattern, line[%s]", line); 101 | goto err; 102 | } 103 | 104 | if (p_end - p_start > sizeof(a_format->pattern) - 1) { 105 | zc_error("pattern is too long"); 106 | goto err; 107 | } 108 | memset(a_format->pattern, 0x00, sizeof(a_format->pattern)); 109 | memcpy(a_format->pattern, p_start, p_end - p_start); 110 | 111 | if (zc_str_replace_env(a_format->pattern, sizeof(a_format->pattern))) { 112 | zc_error("zc_str_replace_env fail"); 113 | goto err; 114 | } 115 | 116 | a_format->pattern_specs = 117 | zc_arraylist_new((zc_arraylist_del_fn) zlog_spec_del); 118 | if (!(a_format->pattern_specs)) { 119 | zc_error("zc_arraylist_new fail"); 120 | goto err; 121 | } 122 | 123 | for (p = a_format->pattern; *p != '\0'; p = q) { 124 | a_spec = zlog_spec_new(p, &q, time_cache_count); 125 | if (!a_spec) { 126 | zc_error("zlog_spec_new fail"); 127 | goto err; 128 | } 129 | 130 | if (zc_arraylist_add(a_format->pattern_specs, a_spec)) { 131 | zlog_spec_del(a_spec); 132 | zc_error("zc_arraylist_add fail"); 133 | goto err; 134 | } 135 | } 136 | 137 | zlog_format_profile(a_format, ZC_DEBUG); 138 | return a_format; 139 | err: 140 | zlog_format_del(a_format); 141 | return NULL; 142 | } 143 | 144 | /*******************************************************************************/ 145 | /* return 0 success, or buf is full 146 | * return -1 fail 147 | */ 148 | int zlog_format_gen_msg(zlog_format_t * a_format, zlog_thread_t * a_thread) 149 | { 150 | int i; 151 | zlog_spec_t *a_spec; 152 | 153 | zlog_buf_restart(a_thread->msg_buf); 154 | 155 | zc_arraylist_foreach(a_format->pattern_specs, i, a_spec) { 156 | if (zlog_spec_gen_msg(a_spec, a_thread) == 0) { 157 | continue; 158 | } else { 159 | return -1; 160 | } 161 | } 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /doc/GettingStart-EN.txt: -------------------------------------------------------------------------------- 1 | 0. What is zlog? 2 | 3 | zlog is a reliable, high-performance, thread safe, flexible, clear-model, pure C logging library. 4 | 5 | Actually, in the C world there was NO good logging library for applications like logback in java or log4cxx in c++. Using printf can work, but can not be redirected or reformatted easily. syslog is slow and is designed for system use. 6 | So I wrote zlog. 7 | It is faster, safer and more powerful than log4c. So it can be widely used. 8 | 9 | 1. Install 10 | 11 | Downloads: https://github.com/HardySimpson/zlog/releases 12 | 13 | $ tar -zxvf zlog-latest-stable.tar.gz 14 | $ cd zlog-latest-stable/ 15 | $ make 16 | $ sudo make install 17 | or 18 | $ make PREFIX=/usr/local/ 19 | $ sudo make PREFIX=/usr/local/ install 20 | 21 | PREFIX indicates the installation destination for zlog. After installation, refresh your dynamic linker to make sure your program can find zlog library. 22 | 23 | $ sudo vi /etc/ld.so.conf 24 | /usr/local/lib 25 | $ sudo ldconfig 26 | 27 | Before running a real program, make sure libzlog.so is in the directory where the system's dynamic lib loader can find it. The command metioned above are for linux. Other systems will need a similar set of actions. 28 | 29 | 30 | 2. Introduce configure file 31 | 32 | There are 3 important concepts in zlog: categories, formats and rules. 33 | 34 | Categories specify different kinds of log entries. In the zlog source code, category is a (zlog_cateogory_t *) variable. In your program, different categories for the log entries will distinguish them from each other. 35 | 36 | Formats describe log patterns, such as: with or without time stamp, source file, source line. 37 | 38 | Rules consist of category, level, output file (or other channel) and format. In brief, if the category string in a rule in the configuration file equals the name of a category variable in the source, then they match. Still there is complex match range of category. Rule decouples variable conditions. For example, log4j must specify a level for each logger(or inherit from father logger). That's not convenient when each grade of logger has its own level for output(child logger output at the level of debug, when father logger output at the level of error) 39 | 40 | Now create a configuration file. The function zlog_init takes the files path as its only argument. 41 | $ cat /etc/zlog.conf 42 | 43 | [formats] 44 | simple = "%m%n" 45 | [rules] 46 | my_cat.DEBUG >stdout; simple 47 | 48 | In the configuration file log messages in the category "my_cat" and a level of DEBUG or higher are output to standard output, with the format of simple(%m - usermessage %n - newline). If you want to direct out to a file and limit the files maximum size, use this configuration 49 | 50 | my_cat.DEBUG "/var/log/aa.log", 1M; simple 51 | 52 | 3. Using zlog API in C source file 53 | $ vi test_hello.c 54 | 55 | #include 56 | 57 | #include "zlog.h" 58 | 59 | int main(int argc, char** argv) 60 | { 61 | int rc; 62 | zlog_category_t *c; 63 | 64 | rc = zlog_init("/etc/zlog.conf"); 65 | if (rc) { 66 | printf("init failed\n"); 67 | return -1; 68 | } 69 | 70 | c = zlog_get_category("my_cat"); 71 | if (!c) { 72 | printf("get cat fail\n"); 73 | zlog_fini(); 74 | return -2; 75 | } 76 | 77 | zlog_info(c, "hello, zlog"); 78 | 79 | zlog_fini(); 80 | 81 | return 0; 82 | } 83 | 84 | 4. Complie, and run it!s 85 | 86 | $ cc -c -o test_hello.o test_hello.c -I/usr/local/include 87 | $ cc -o test_hello test_hello.o -L/usr/local/lib -lzlog -lpthread 88 | $ ./test_hello 89 | hello, zlog 90 | 91 | 5. Advanced Usage 92 | * syslog model, better than log4j model 93 | * log format customization 94 | * multiple output destinations including static file path, dynamic file path, stdout, stderr, syslog, user-defined ouput 95 | * runtime manually or automatically refresh configure(safely) 96 | * high-performance, 250'000 logs/second on my laptop, about 1000 times faster than syslog(3) with rsyslogd 97 | * user-defined log level 98 | * thread-safe and process-safe log file rotation 99 | * microsecond accuracy 100 | * dzlog, a default category log API for easy use 101 | * MDC, a log4j style key-value map 102 | * self debuggable, can output zlog's self debug&error log at runtime 103 | * No external dependencies, just based on a POSIX system and a C99 compliant vsnprintf. 104 | 105 | 106 | 6. Links: 107 | 108 | Homepage: http://hardysimpson.github.com/zlog 109 | Downloads: https://github.com/HardySimpson/zlog/releases 110 | Author's Email: HardySimpson1984@gmail.com 111 | 112 | auto tools version: https://github.com/bmanojlovic/zlog 113 | cmake verion: https://github.com/lisongmin/zlog 114 | windows version: https://github.com/lopsd07/WinZlog 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 0. What is zlog? 2 | ------------- 3 | 4 | zlog is a reliable, high-performance, thread safe, flexible, clear-model, pure C logging library. 5 | 6 | Actually, in the C world there was NO good logging library for applications like logback in java or log4cxx in c++. Using printf can work, but can not be redirected or reformatted easily. syslog is slow and is designed for system use. 7 | So I wrote zlog. 8 | It is faster, safer and more powerful than log4c. So it can be widely used. 9 | 10 | 1. Install 11 | ------------- 12 | 13 | Downloads: https://github.com/HardySimpson/zlog/releases 14 | 15 | $ tar -zxvf zlog-latest-stable.tar.gz 16 | $ cd zlog-latest-stable/ 17 | $ make 18 | $ sudo make install 19 | 20 | or 21 | 22 | $ make PREFIX=/usr/local/ 23 | $ sudo make PREFIX=/usr/local/ install 24 | 25 | PREFIX indicates the installation destination for zlog. After installation, refresh your dynamic linker to make sure your program can find zlog library. 26 | 27 | $ sudo vi /etc/ld.so.conf 28 | /usr/local/lib 29 | $ sudo ldconfig 30 | 31 | Before running a real program, make sure libzlog.so is in the directory where the system's dynamic lib loader can find it. The command metioned above are for linux. Other systems will need a similar set of actions. 32 | 33 | 34 | 2. Introduce configure file 35 | ------------- 36 | 37 | There are 3 important concepts in zlog: categories, formats and rules. 38 | 39 | Categories specify different kinds of log entries. In the zlog source code, category is a (zlog_cateogory_t *) variable. In your program, different categories for the log entries will distinguish them from each other. 40 | 41 | Formats describe log patterns, such as: with or without time stamp, source file, source line. 42 | 43 | Rules consist of category, level, output file (or other channel) and format. In brief, if the category string in a rule in the configuration file equals the name of a category variable in the source, then they match. Still there is complex match range of category. Rule decouples variable conditions. For example, log4j must specify a level for each logger(or inherit from father logger). That's not convenient when each grade of logger has its own level for output(child logger output at the level of debug, when father logger output at the level of error) 44 | 45 | Now create a configuration file. The function zlog_init takes the files path as its only argument. 46 | $ cat /etc/zlog.conf 47 | 48 | [formats] 49 | simple = "%m%n" 50 | [rules] 51 | my_cat.DEBUG >stdout; simple 52 | 53 | In the configuration file log messages in the category "my_cat" and a level of DEBUG or higher are output to standard output, with the format of simple(%m - usermessage %n - newline). If you want to direct out to a file and limit the files maximum size, use this configuration 54 | 55 | my_cat.DEBUG "/var/log/aa.log", 1M; simple 56 | 57 | 3. Using zlog API in C source file 58 | ------------- 59 | $ vi test_hello.c 60 | 61 | #include 62 | 63 | #include "zlog.h" 64 | 65 | int main(int argc, char** argv) 66 | { 67 | int rc; 68 | zlog_category_t *c; 69 | 70 | rc = zlog_init("/etc/zlog.conf"); 71 | if (rc) { 72 | printf("init failed\n"); 73 | return -1; 74 | } 75 | 76 | c = zlog_get_category("my_cat"); 77 | if (!c) { 78 | printf("get cat fail\n"); 79 | zlog_fini(); 80 | return -2; 81 | } 82 | 83 | zlog_info(c, "hello, zlog"); 84 | 85 | zlog_fini(); 86 | 87 | return 0; 88 | } 89 | 90 | 4. Compile, and run it! 91 | ------------- 92 | $ cc -c -o test_hello.o test_hello.c -I/usr/local/include 93 | $ cc -o test_hello test_hello.o -L/usr/local/lib -lzlog -lpthread 94 | $ ./test_hello 95 | hello, zlog 96 | 97 | 5. Advanced Usage 98 | ------------- 99 | * syslog model, better than log4j model 100 | * log format customization 101 | * multiple output destinations including static file path, dynamic file path, stdout, stderr, syslog, user-defined output 102 | * runtime manually or automatically refresh configure(safely) 103 | * high-performance, 250'000 logs/second on my laptop, about 1000 times faster than syslog(3) with rsyslogd 104 | * user-defined log level 105 | * thread-safe and process-safe log file rotation 106 | * microsecond accuracy 107 | * dzlog, a default category log API for easy use 108 | * MDC, a log4j style key-value map 109 | * self debuggable, can output zlog's self debug&error log at runtime 110 | * No external dependencies, just based on a POSIX system and a C99 compliant vsnprintf. 111 | 112 | 6.Links: 113 | ------------- 114 | * Homepage: http://hardysimpson.github.com/zlog 115 | * Downloads: https://github.com/HardySimpson/zlog/releases 116 | * Author's Email: HardySimpson1984@gmail.com 117 | * auto tools version: https://github.com/bmanojlovic/zlog 118 | * cmake verion: https://github.com/lisongmin/zlog 119 | * windows version: https://github.com/lopsd07/WinZlog 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/thread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "zc_defs.h" 13 | #include "event.h" 14 | #include "buf.h" 15 | #include "thread.h" 16 | #include "mdc.h" 17 | 18 | void zlog_thread_profile(zlog_thread_t * a_thread, int flag) 19 | { 20 | zc_assert(a_thread,); 21 | zc_profile(flag, "--thread[%p][%p][%p][%p,%p,%p,%p,%p]--", 22 | a_thread, 23 | a_thread->mdc, 24 | a_thread->event, 25 | a_thread->pre_path_buf, 26 | a_thread->path_buf, 27 | a_thread->archive_path_buf, 28 | a_thread->pre_msg_buf, 29 | a_thread->msg_buf); 30 | 31 | zlog_mdc_profile(a_thread->mdc, flag); 32 | zlog_event_profile(a_thread->event, flag); 33 | zlog_buf_profile(a_thread->pre_path_buf, flag); 34 | zlog_buf_profile(a_thread->path_buf, flag); 35 | zlog_buf_profile(a_thread->archive_path_buf, flag); 36 | zlog_buf_profile(a_thread->pre_msg_buf, flag); 37 | zlog_buf_profile(a_thread->msg_buf, flag); 38 | return; 39 | } 40 | /*******************************************************************************/ 41 | void zlog_thread_del(zlog_thread_t * a_thread) 42 | { 43 | zc_assert(a_thread,); 44 | if (a_thread->mdc) 45 | zlog_mdc_del(a_thread->mdc); 46 | if (a_thread->event) 47 | zlog_event_del(a_thread->event); 48 | if (a_thread->pre_path_buf) 49 | zlog_buf_del(a_thread->pre_path_buf); 50 | if (a_thread->path_buf) 51 | zlog_buf_del(a_thread->path_buf); 52 | if (a_thread->archive_path_buf) 53 | zlog_buf_del(a_thread->archive_path_buf); 54 | if (a_thread->pre_msg_buf) 55 | zlog_buf_del(a_thread->pre_msg_buf); 56 | if (a_thread->msg_buf) 57 | zlog_buf_del(a_thread->msg_buf); 58 | 59 | zc_debug("zlog_thread_del[%p]", a_thread); 60 | free(a_thread); 61 | return; 62 | } 63 | 64 | zlog_thread_t *zlog_thread_new(int init_version, size_t buf_size_min, size_t buf_size_max, int time_cache_count) 65 | { 66 | zlog_thread_t *a_thread; 67 | 68 | a_thread = calloc(1, sizeof(zlog_thread_t)); 69 | if (!a_thread) { 70 | zc_error("calloc fail, errno[%d]", errno); 71 | return NULL; 72 | } 73 | 74 | a_thread->init_version = init_version; 75 | 76 | a_thread->mdc = zlog_mdc_new(); 77 | if (!a_thread->mdc) { 78 | zc_error("zlog_mdc_new fail"); 79 | goto err; 80 | } 81 | 82 | a_thread->event = zlog_event_new(time_cache_count); 83 | if (!a_thread->event) { 84 | zc_error("zlog_event_new fail"); 85 | goto err; 86 | } 87 | 88 | a_thread->pre_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); 89 | if (!a_thread->pre_path_buf) { 90 | zc_error("zlog_buf_new fail"); 91 | goto err; 92 | } 93 | 94 | a_thread->path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); 95 | if (!a_thread->path_buf) { 96 | zc_error("zlog_buf_new fail"); 97 | goto err; 98 | } 99 | 100 | a_thread->archive_path_buf = zlog_buf_new(MAXLEN_PATH + 1, MAXLEN_PATH + 1, NULL); 101 | if (!a_thread->archive_path_buf) { 102 | zc_error("zlog_buf_new fail"); 103 | goto err; 104 | } 105 | 106 | a_thread->pre_msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); 107 | if (!a_thread->pre_msg_buf) { 108 | zc_error("zlog_buf_new fail"); 109 | goto err; 110 | } 111 | 112 | a_thread->msg_buf = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); 113 | if (!a_thread->msg_buf) { 114 | zc_error("zlog_buf_new fail"); 115 | goto err; 116 | } 117 | 118 | 119 | //zlog_thread_profile(a_thread, ZC_DEBUG); 120 | return a_thread; 121 | err: 122 | zlog_thread_del(a_thread); 123 | return NULL; 124 | } 125 | 126 | /*******************************************************************************/ 127 | int zlog_thread_rebuild_msg_buf(zlog_thread_t * a_thread, size_t buf_size_min, size_t buf_size_max) 128 | { 129 | zlog_buf_t *pre_msg_buf_new = NULL; 130 | zlog_buf_t *msg_buf_new = NULL; 131 | zc_assert(a_thread, -1); 132 | 133 | if ( (a_thread->msg_buf->size_min == buf_size_min) 134 | && (a_thread->msg_buf->size_max == buf_size_max)) { 135 | zc_debug("buf size not changed, no need rebuild"); 136 | return 0; 137 | } 138 | 139 | pre_msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); 140 | if (!pre_msg_buf_new) { 141 | zc_error("zlog_buf_new fail"); 142 | goto err; 143 | } 144 | 145 | msg_buf_new = zlog_buf_new(buf_size_min, buf_size_max, "..." FILE_NEWLINE); 146 | if (!msg_buf_new) { 147 | zc_error("zlog_buf_new fail"); 148 | goto err; 149 | } 150 | 151 | zlog_buf_del(a_thread->pre_msg_buf); 152 | a_thread->pre_msg_buf = pre_msg_buf_new; 153 | 154 | zlog_buf_del(a_thread->msg_buf); 155 | a_thread->msg_buf = msg_buf_new; 156 | 157 | return 0; 158 | err: 159 | if (pre_msg_buf_new) zlog_buf_del(pre_msg_buf_new); 160 | if (msg_buf_new) zlog_buf_del(msg_buf_new); 161 | return -1; 162 | } 163 | 164 | int zlog_thread_rebuild_event(zlog_thread_t * a_thread, int time_cache_count) 165 | { 166 | zlog_event_t *event_new = NULL; 167 | zc_assert(a_thread, -1); 168 | 169 | event_new = zlog_event_new(time_cache_count); 170 | if (!event_new) { 171 | zc_error("zlog_event_new fail"); 172 | goto err; 173 | } 174 | 175 | zlog_event_del(a_thread->event); 176 | a_thread->event = event_new; 177 | return 0; 178 | err: 179 | if (event_new) zlog_event_del(event_new); 180 | return -1; 181 | } 182 | 183 | 184 | /*******************************************************************************/ 185 | -------------------------------------------------------------------------------- /src/event.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #define _GNU_SOURCE // For distros like Centos for syscall interface 10 | 11 | #include "fmacros.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include "zc_defs.h" 26 | #include "event.h" 27 | 28 | void zlog_event_profile(zlog_event_t * a_event, int flag) 29 | { 30 | zc_assert(a_event,); 31 | zc_profile(flag, "---event[%p][%s,%s][%s(%ld),%s(%ld),%ld,%d][%p,%s][%ld,%ld][%ld,%ld][%d]---", 32 | a_event, 33 | a_event->category_name, a_event->host_name, 34 | a_event->file, a_event->file_len, 35 | a_event->func, a_event->func_len, 36 | a_event->line, a_event->level, 37 | a_event->hex_buf, a_event->str_format, 38 | a_event->time_stamp.tv_sec, a_event->time_stamp.tv_usec, 39 | (long)a_event->pid, (long)a_event->tid, 40 | a_event->time_cache_count); 41 | return; 42 | } 43 | 44 | /*******************************************************************************/ 45 | 46 | void zlog_event_del(zlog_event_t * a_event) 47 | { 48 | zc_assert(a_event,); 49 | if (a_event->time_caches) free(a_event->time_caches); 50 | zc_debug("zlog_event_del[%p]", a_event); 51 | free(a_event); 52 | return; 53 | } 54 | 55 | zlog_event_t *zlog_event_new(int time_cache_count) 56 | { 57 | zlog_event_t *a_event; 58 | 59 | a_event = calloc(1, sizeof(zlog_event_t)); 60 | if (!a_event) { 61 | zc_error("calloc fail, errno[%d]", errno); 62 | return NULL; 63 | } 64 | 65 | a_event->time_caches = calloc(time_cache_count, sizeof(zlog_time_cache_t)); 66 | if (!a_event->time_caches) { 67 | zc_error("calloc fail, errno[%d]", errno); 68 | free(a_event); 69 | return NULL; 70 | } 71 | a_event->time_cache_count = time_cache_count; 72 | 73 | /* 74 | * at the zlog_init we gethostname, 75 | * u don't always change your hostname, eh? 76 | */ 77 | if (gethostname(a_event->host_name, sizeof(a_event->host_name) - 1)) { 78 | zc_error("gethostname fail, errno[%d]", errno); 79 | goto err; 80 | } 81 | 82 | a_event->host_name_len = strlen(a_event->host_name); 83 | 84 | /* tid is bound to a_event 85 | * as in whole lifecycle event persists 86 | * even fork to oth pid, tid not change 87 | */ 88 | a_event->tid = pthread_self(); 89 | 90 | a_event->tid_str_len = sprintf(a_event->tid_str, "%lu", (unsigned long)a_event->tid); 91 | a_event->tid_hex_str_len = sprintf(a_event->tid_hex_str, "%x", (unsigned int)a_event->tid); 92 | 93 | #ifdef __linux__ 94 | a_event->ktid = syscall(SYS_gettid); 95 | #elif __APPLE__ 96 | uint64_t tid64; 97 | pthread_threadid_np(NULL, &tid64); 98 | a_event->tid = (pid_t)tid64; 99 | #endif 100 | 101 | #if defined __linux__ || __APPLE__ 102 | a_event->ktid_str_len = sprintf(a_event->ktid_str, "%u", (unsigned int)a_event->ktid); 103 | #endif 104 | 105 | //zlog_event_profile(a_event, ZC_DEBUG); 106 | return a_event; 107 | err: 108 | zlog_event_del(a_event); 109 | return NULL; 110 | } 111 | 112 | /*******************************************************************************/ 113 | void zlog_event_set_fmt(zlog_event_t * a_event, 114 | char *category_name, size_t category_name_len, 115 | const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, 116 | const char *str_format, va_list str_args) 117 | { 118 | /* 119 | * category_name point to zlog_category_output's category.name 120 | */ 121 | a_event->category_name = category_name; 122 | a_event->category_name_len = category_name_len; 123 | 124 | a_event->file = (char *) file; 125 | a_event->file_len = file_len; 126 | a_event->func = (char *) func; 127 | a_event->func_len = func_len; 128 | a_event->line = line; 129 | a_event->level = level; 130 | 131 | a_event->generate_cmd = ZLOG_FMT; 132 | a_event->str_format = str_format; 133 | va_copy(a_event->str_args, str_args); 134 | 135 | /* pid should fetch eveytime, as no one knows, 136 | * when does user fork his process 137 | * so clean here, and fetch at spec.c 138 | */ 139 | a_event->pid = (pid_t) 0; 140 | 141 | /* in a event's life cycle, time will be get when spec need, 142 | * and keep unchange though all event's life cycle 143 | * zlog_spec_write_time gettimeofday 144 | */ 145 | a_event->time_stamp.tv_sec = 0; 146 | return; 147 | } 148 | 149 | void zlog_event_set_hex(zlog_event_t * a_event, 150 | char *category_name, size_t category_name_len, 151 | const char *file, size_t file_len, const char *func, size_t func_len, long line, int level, 152 | const void *hex_buf, size_t hex_buf_len) 153 | { 154 | /* 155 | * category_name point to zlog_category_output's category.name 156 | */ 157 | a_event->category_name = category_name; 158 | a_event->category_name_len = category_name_len; 159 | 160 | a_event->file = (char *) file; 161 | a_event->file_len = file_len; 162 | a_event->func = (char *) func; 163 | a_event->func_len = func_len; 164 | a_event->line = line; 165 | a_event->level = level; 166 | 167 | a_event->generate_cmd = ZLOG_HEX; 168 | a_event->hex_buf = hex_buf; 169 | a_event->hex_buf_len = hex_buf_len; 170 | 171 | /* pid should fetch eveytime, as no one knows, 172 | * when does user fork his process 173 | * so clean here, and fetch at spec.c 174 | */ 175 | a_event->pid = (pid_t) 0; 176 | 177 | /* in a event's life cycle, time will be get when spec need, 178 | * and keep unchange though all event's life cycle 179 | */ 180 | a_event->time_stamp.tv_sec = 0; 181 | return; 182 | } 183 | -------------------------------------------------------------------------------- /test/test_multithread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2017 by Philippe Corbes 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | * 8 | * This test programm start NB_THREADS threads. 9 | * Each thread loop and log an Info message every THREAD_LOOP_DELAY us (=10ms). 10 | * The main loop check configuration file modification every seconds and reload configuration on file update. 11 | * The main loop force reload configuration every RELOAD_DELAY " (=10"). 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "zlog.h" 22 | 23 | #define CONFIG "test_multithread.conf" 24 | #define NB_THREADS 200 25 | #define THREAD_LOOP_DELAY 10000 /* 0.01" */ 26 | #define RELOAD_DELAY 10 27 | 28 | enum { 29 | ZLOG_LEVEL_TRACE = 10, 30 | ZLOG_LEVEL_SECURITY = 150, 31 | /* must equals conf file setting */ 32 | }; 33 | 34 | #define zlog_trace(cat, format, args...) \ 35 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 36 | ZLOG_LEVEL_TRACE, format, ##args) 37 | 38 | #define zlog_security(cat, format, args...) \ 39 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 40 | ZLOG_LEVEL_SECURITY, format, ##args) 41 | 42 | 43 | struct thread_info { /* Used as argument to thread_start() */ 44 | pthread_t thread_id; /* ID returned by pthread_create() */ 45 | int thread_num; /* Application-defined thread # */ 46 | zlog_category_t *zc; /* The logger category struc address; (All threads will use the same category, so he same address) */ 47 | long long int loop; /* Counter incremented to check the thread's health */ 48 | }; 49 | 50 | struct thread_info *tinfo; 51 | 52 | 53 | void intercept(int sig) 54 | { 55 | int i; 56 | 57 | printf("\nIntercept signal %d\n\n", sig); 58 | 59 | signal (sig, SIG_DFL); 60 | raise (sig); 61 | 62 | printf("You can import datas below in a spreadsheat and check if any thread stopped increment the Loop counter during the test.\n\n"); 63 | printf("Thread;Loop\n"); 64 | for (i=0; izc = zlog_get_category("thrd"); 79 | if (!tinfo->zc) { 80 | printf("get thrd %d cat fail\n", tinfo->thread_num); 81 | } 82 | else 83 | { 84 | while(1) 85 | { 86 | usleep(THREAD_LOOP_DELAY); 87 | zlog_info(tinfo->zc, "%d;%lld", tinfo->thread_num, tinfo->loop++); 88 | } 89 | } 90 | 91 | return NULL; 92 | } 93 | 94 | int main(int argc, char** argv) 95 | { 96 | int rc; 97 | zlog_category_t *zc; 98 | zlog_category_t *mc; 99 | zlog_category_t *hl; 100 | int i = 0; 101 | struct stat stat_0, stat_1; 102 | 103 | /* Create the logging directory if not yet ceated */ 104 | mkdir("./test_multithread-logs", 0777); 105 | 106 | if (stat(CONFIG, &stat_0)) 107 | { 108 | printf("Configuration file not found\n"); 109 | return -1; 110 | } 111 | 112 | rc = zlog_init(CONFIG); 113 | if (rc) { 114 | printf("main init failed\n"); 115 | return -2; 116 | } 117 | 118 | zc = zlog_get_category("main"); 119 | if (!zc) { 120 | printf("main get cat fail\n"); 121 | zlog_fini(); 122 | return -3; 123 | } 124 | 125 | mc = zlog_get_category("clsn"); 126 | if (!mc) { 127 | printf("clsn get cat fail\n"); 128 | zlog_fini(); 129 | return -3; 130 | } 131 | 132 | hl = zlog_get_category("high"); 133 | if (!hl) { 134 | printf("high get cat fail\n"); 135 | zlog_fini(); 136 | return -3; 137 | } 138 | 139 | /* Interrupt (ANSI). */ 140 | if (signal(SIGINT, intercept) == SIG_IGN ) 141 | { 142 | zlog_fatal(zc, "Can't caught the signal SIGINT, Interrupt (ANSI)"); 143 | signal(SIGINT, SIG_IGN ); 144 | return -4; 145 | } 146 | 147 | // start threads 148 | tinfo = calloc(NB_THREADS, sizeof(struct thread_info)); 149 | for (i=0; i 0) 197 | reload = (i % RELOAD_DELAY == 0); 198 | 199 | if (reload) 200 | { 201 | zlog_info(zc, "Will reload configuration..."); 202 | rc = zlog_reload(CONFIG); 203 | if (rc) { 204 | printf("main init failed\n"); 205 | return -6; 206 | } 207 | zlog_info(zc, "Configuration reloaded :)"); 208 | stat(CONFIG, &stat_0); 209 | } 210 | } 211 | 212 | exit(EXIT_SUCCESS); 213 | } 214 | -------------------------------------------------------------------------------- /src/category.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | #include "fmacros.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #include "category.h" 14 | #include "rule.h" 15 | #include "zc_defs.h" 16 | 17 | void zlog_category_profile(zlog_category_t *a_category, int flag) 18 | { 19 | int i; 20 | zlog_rule_t *a_rule; 21 | 22 | zc_assert(a_category,); 23 | zc_profile(flag, "--category[%p][%s][%p]--", 24 | a_category, 25 | a_category->name, 26 | a_category->fit_rules); 27 | if (a_category->fit_rules) { 28 | zc_arraylist_foreach(a_category->fit_rules, i, a_rule) { 29 | zlog_rule_profile(a_rule, flag); 30 | } 31 | } 32 | return; 33 | } 34 | 35 | /*******************************************************************************/ 36 | void zlog_category_del(zlog_category_t * a_category) 37 | { 38 | zc_assert(a_category,); 39 | if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules); 40 | zc_debug("zlog_category_del[%p]", a_category); 41 | free(a_category); 42 | return; 43 | } 44 | 45 | /* overlap one rule's level bitmap to cateogry, 46 | * so category can judge whether a log level will be output by itself 47 | * It is safe when configure is reloaded, when rule will be released an recreated 48 | */ 49 | static void zlog_cateogry_overlap_bitmap(zlog_category_t * a_category, zlog_rule_t *a_rule) 50 | { 51 | int i; 52 | for(i = 0; i < sizeof(a_rule->level_bitmap); i++) { 53 | a_category->level_bitmap[i] |= a_rule->level_bitmap[i]; 54 | } 55 | } 56 | 57 | static int zlog_category_obtain_rules(zlog_category_t * a_category, zc_arraylist_t * rules) 58 | { 59 | int i; 60 | int count = 0; 61 | int fit = 0; 62 | zlog_rule_t *a_rule; 63 | zlog_rule_t *wastebin_rule = NULL; 64 | 65 | /* before set, clean last fit rules first */ 66 | if (a_category->fit_rules) zc_arraylist_del(a_category->fit_rules); 67 | 68 | memset(a_category->level_bitmap, 0x00, sizeof(a_category->level_bitmap)); 69 | 70 | a_category->fit_rules = zc_arraylist_new(NULL); 71 | if (!(a_category->fit_rules)) { 72 | zc_error("zc_arraylist_new fail"); 73 | return -1; 74 | } 75 | 76 | /* get match rules from all rules */ 77 | zc_arraylist_foreach(rules, i, a_rule) { 78 | fit = zlog_rule_match_category(a_rule, a_category->name); 79 | if (fit) { 80 | if (zc_arraylist_add(a_category->fit_rules, a_rule)) { 81 | zc_error("zc_arrylist_add fail"); 82 | goto err; 83 | } 84 | zlog_cateogry_overlap_bitmap(a_category, a_rule); 85 | count++; 86 | } 87 | 88 | if (zlog_rule_is_wastebin(a_rule)) { 89 | wastebin_rule = a_rule; 90 | } 91 | } 92 | 93 | if (count == 0) { 94 | if (wastebin_rule) { 95 | zc_debug("category[%s], no match rules, use wastebin_rule", a_category->name); 96 | if (zc_arraylist_add(a_category->fit_rules, wastebin_rule)) { 97 | zc_error("zc_arrylist_add fail"); 98 | goto err; 99 | } 100 | zlog_cateogry_overlap_bitmap(a_category, wastebin_rule); 101 | count++; 102 | } else { 103 | zc_debug("category[%s], no match rules & no wastebin_rule", a_category->name); 104 | } 105 | } 106 | 107 | return 0; 108 | err: 109 | zc_arraylist_del(a_category->fit_rules); 110 | a_category->fit_rules = NULL; 111 | return -1; 112 | } 113 | 114 | zlog_category_t *zlog_category_new(const char *name, zc_arraylist_t * rules) 115 | { 116 | size_t len; 117 | zlog_category_t *a_category; 118 | 119 | zc_assert(name, NULL); 120 | zc_assert(rules, NULL); 121 | 122 | len = strlen(name); 123 | if (len > sizeof(a_category->name) - 1) { 124 | zc_error("name[%s] too long", name); 125 | return NULL; 126 | } 127 | a_category = calloc(1, sizeof(zlog_category_t)); 128 | if (!a_category) { 129 | zc_error("calloc fail, errno[%d]", errno); 130 | return NULL; 131 | } 132 | strcpy(a_category->name, name); 133 | a_category->name_len = len; 134 | if (zlog_category_obtain_rules(a_category, rules)) { 135 | zc_error("zlog_category_fit_rules fail"); 136 | goto err; 137 | } 138 | 139 | zlog_category_profile(a_category, ZC_DEBUG); 140 | return a_category; 141 | err: 142 | zlog_category_del(a_category); 143 | return NULL; 144 | } 145 | /*******************************************************************************/ 146 | /* update success: fit_rules 1, fit_rules_backup 1 */ 147 | /* update fail: fit_rules 0, fit_rules_backup 1 */ 148 | int zlog_category_update_rules(zlog_category_t * a_category, zc_arraylist_t * new_rules) 149 | { 150 | zc_assert(a_category, -1); 151 | zc_assert(new_rules, -1); 152 | 153 | /* 1st, mv fit_rules fit_rules_backup */ 154 | if (a_category->fit_rules_backup) zc_arraylist_del(a_category->fit_rules_backup); 155 | a_category->fit_rules_backup = a_category->fit_rules; 156 | a_category->fit_rules = NULL; 157 | 158 | memcpy(a_category->level_bitmap_backup, a_category->level_bitmap, 159 | sizeof(a_category->level_bitmap)); 160 | 161 | /* 2nd, obtain new_rules to fit_rules */ 162 | if (zlog_category_obtain_rules(a_category, new_rules)) { 163 | zc_error("zlog_category_obtain_rules fail"); 164 | a_category->fit_rules = NULL; 165 | return -1; 166 | } 167 | 168 | /* keep the fit_rules_backup not change, return */ 169 | return 0; 170 | } 171 | 172 | /* commit fail: fit_rules_backup != 0 */ 173 | /* commit success: fit_rules 1, fit_rules_backup 0 */ 174 | void zlog_category_commit_rules(zlog_category_t * a_category) 175 | { 176 | zc_assert(a_category,); 177 | if (!a_category->fit_rules_backup) { 178 | zc_warn("a_category->fit_rules_backup is NULL, never update before"); 179 | return; 180 | } 181 | 182 | zc_arraylist_del(a_category->fit_rules_backup); 183 | a_category->fit_rules_backup = NULL; 184 | memset(a_category->level_bitmap_backup, 0x00, 185 | sizeof(a_category->level_bitmap_backup)); 186 | return; 187 | } 188 | 189 | /* rollback fail: fit_rules_backup != 0 */ 190 | /* rollback success: fit_rules 1, fit_rules_backup 0 */ 191 | /* so whether update succes or not, make things back to old */ 192 | void zlog_category_rollback_rules(zlog_category_t * a_category) 193 | { 194 | zc_assert(a_category,); 195 | if (!a_category->fit_rules_backup) { 196 | zc_warn("a_category->fit_rules_backup in NULL, never update before"); 197 | return; 198 | } 199 | 200 | if (a_category->fit_rules) { 201 | /* update success, rm new and backup */ 202 | zc_arraylist_del(a_category->fit_rules); 203 | a_category->fit_rules = a_category->fit_rules_backup; 204 | a_category->fit_rules_backup = NULL; 205 | } else { 206 | /* update fail, just backup */ 207 | a_category->fit_rules = a_category->fit_rules_backup; 208 | a_category->fit_rules_backup = NULL; 209 | } 210 | 211 | memcpy(a_category->level_bitmap, a_category->level_bitmap_backup, 212 | sizeof(a_category->level_bitmap)); 213 | memset(a_category->level_bitmap_backup, 0x00, 214 | sizeof(a_category->level_bitmap_backup)); 215 | 216 | return; /* always success */ 217 | } 218 | 219 | /*******************************************************************************/ 220 | 221 | int zlog_category_output(zlog_category_t * a_category, zlog_thread_t * a_thread) 222 | { 223 | int i; 224 | int rc = 0; 225 | zlog_rule_t *a_rule; 226 | 227 | /* go through all match rules to output */ 228 | zc_arraylist_foreach(a_category->fit_rules, i, a_rule) { 229 | rc = zlog_rule_output(a_rule, a_thread); 230 | } 231 | 232 | return rc; 233 | } 234 | -------------------------------------------------------------------------------- /src/zc_hashtable.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "zc_defs.h" 14 | #include "zc_hashtable.h" 15 | 16 | struct zc_hashtable_s { 17 | size_t nelem; 18 | 19 | zc_hashtable_entry_t **tab; 20 | size_t tab_size; 21 | 22 | zc_hashtable_hash_fn hash; 23 | zc_hashtable_equal_fn equal; 24 | zc_hashtable_del_fn key_del; 25 | zc_hashtable_del_fn value_del; 26 | }; 27 | 28 | zc_hashtable_t *zc_hashtable_new(size_t a_size, 29 | zc_hashtable_hash_fn hash, 30 | zc_hashtable_equal_fn equal, 31 | zc_hashtable_del_fn key_del, 32 | zc_hashtable_del_fn value_del) 33 | { 34 | zc_hashtable_t *a_table; 35 | 36 | a_table = calloc(1, sizeof(*a_table)); 37 | if (!a_table) { 38 | zc_error("calloc fail, errno[%d]", errno); 39 | return NULL; 40 | } 41 | 42 | a_table->tab = calloc(a_size, sizeof(*(a_table->tab))); 43 | if (!a_table->tab) { 44 | zc_error("calloc fail, errno[%d]", errno); 45 | free(a_table); 46 | return NULL; 47 | } 48 | a_table->tab_size = a_size; 49 | 50 | a_table->nelem = 0; 51 | a_table->hash = hash; 52 | a_table->equal = equal; 53 | 54 | /* these two could be NULL */ 55 | a_table->key_del = key_del; 56 | a_table->value_del = value_del; 57 | 58 | return a_table; 59 | } 60 | 61 | void zc_hashtable_del(zc_hashtable_t * a_table) 62 | { 63 | size_t i; 64 | zc_hashtable_entry_t *p; 65 | zc_hashtable_entry_t *q; 66 | 67 | if (!a_table) { 68 | zc_error("a_table[%p] is NULL, just do nothing", a_table); 69 | return; 70 | } 71 | 72 | for (i = 0; i < a_table->tab_size; i++) { 73 | for (p = (a_table->tab)[i]; p; p = q) { 74 | q = p->next; 75 | if (a_table->key_del) { 76 | a_table->key_del(p->key); 77 | } 78 | if (a_table->value_del) { 79 | a_table->value_del(p->value); 80 | } 81 | free(p); 82 | } 83 | } 84 | if (a_table->tab) 85 | free(a_table->tab); 86 | free(a_table); 87 | 88 | return; 89 | } 90 | 91 | void zc_hashtable_clean(zc_hashtable_t * a_table) 92 | { 93 | size_t i; 94 | zc_hashtable_entry_t *p; 95 | zc_hashtable_entry_t *q; 96 | 97 | for (i = 0; i < a_table->tab_size; i++) { 98 | for (p = (a_table->tab)[i]; p; p = q) { 99 | q = p->next; 100 | if (a_table->key_del) { 101 | a_table->key_del(p->key); 102 | } 103 | if (a_table->value_del) { 104 | a_table->value_del(p->value); 105 | } 106 | free(p); 107 | } 108 | (a_table->tab)[i] = NULL; 109 | } 110 | a_table->nelem = 0; 111 | return; 112 | } 113 | 114 | static int zc_hashtable_rehash(zc_hashtable_t * a_table) 115 | { 116 | size_t i; 117 | size_t j; 118 | size_t tab_size; 119 | zc_hashtable_entry_t **tab; 120 | zc_hashtable_entry_t *p; 121 | zc_hashtable_entry_t *q; 122 | 123 | tab_size = 2 * a_table->tab_size; 124 | tab = calloc(tab_size, sizeof(*tab)); 125 | if (!tab) { 126 | zc_error("calloc fail, errno[%d]", errno); 127 | return -1; 128 | } 129 | 130 | for (i = 0; i < a_table->tab_size; i++) { 131 | for (p = (a_table->tab)[i]; p; p = q) { 132 | q = p->next; 133 | 134 | p->next = NULL; 135 | p->prev = NULL; 136 | j = p->hash_key % tab_size; 137 | if (tab[j]) { 138 | tab[j]->prev = p; 139 | p->next = tab[j]; 140 | } 141 | tab[j] = p; 142 | } 143 | } 144 | free(a_table->tab); 145 | a_table->tab = tab; 146 | a_table->tab_size = tab_size; 147 | 148 | return 0; 149 | } 150 | 151 | zc_hashtable_entry_t *zc_hashtable_get_entry(zc_hashtable_t * a_table, const void *a_key) 152 | { 153 | unsigned int i; 154 | zc_hashtable_entry_t *p; 155 | 156 | i = a_table->hash(a_key) % a_table->tab_size; 157 | for (p = (a_table->tab)[i]; p; p = p->next) { 158 | if (a_table->equal(a_key, p->key)) 159 | return p; 160 | } 161 | 162 | return NULL; 163 | } 164 | 165 | void *zc_hashtable_get(zc_hashtable_t * a_table, const void *a_key) 166 | { 167 | unsigned int i; 168 | zc_hashtable_entry_t *p; 169 | 170 | i = a_table->hash(a_key) % a_table->tab_size; 171 | for (p = (a_table->tab)[i]; p; p = p->next) { 172 | if (a_table->equal(a_key, p->key)) 173 | return p->value; 174 | } 175 | 176 | return NULL; 177 | } 178 | 179 | int zc_hashtable_put(zc_hashtable_t * a_table, void *a_key, void *a_value) 180 | { 181 | int rc = 0; 182 | unsigned int i; 183 | zc_hashtable_entry_t *p = NULL; 184 | 185 | i = a_table->hash(a_key) % a_table->tab_size; 186 | for (p = (a_table->tab)[i]; p; p = p->next) { 187 | if (a_table->equal(a_key, p->key)) 188 | break; 189 | } 190 | 191 | if (p) { 192 | if (a_table->key_del) { 193 | a_table->key_del(p->key); 194 | } 195 | if (a_table->value_del) { 196 | a_table->value_del(p->value); 197 | } 198 | p->key = a_key; 199 | p->value = a_value; 200 | return 0; 201 | } else { 202 | if (a_table->nelem > a_table->tab_size * 1.3) { 203 | rc = zc_hashtable_rehash(a_table); 204 | if (rc) { 205 | zc_error("rehash fail"); 206 | return -1; 207 | } 208 | } 209 | 210 | p = calloc(1, sizeof(*p)); 211 | if (!p) { 212 | zc_error("calloc fail, errno[%d]", errno); 213 | return -1; 214 | } 215 | 216 | p->hash_key = a_table->hash(a_key); 217 | p->key = a_key; 218 | p->value = a_value; 219 | p->next = NULL; 220 | p->prev = NULL; 221 | 222 | i = p->hash_key % a_table->tab_size; 223 | if ((a_table->tab)[i]) { 224 | (a_table->tab)[i]->prev = p; 225 | p->next = (a_table->tab)[i]; 226 | } 227 | (a_table->tab)[i] = p; 228 | a_table->nelem++; 229 | } 230 | 231 | return 0; 232 | } 233 | 234 | void zc_hashtable_remove(zc_hashtable_t * a_table, const void *a_key) 235 | { 236 | zc_hashtable_entry_t *p; 237 | unsigned int i; 238 | 239 | if (!a_table || !a_key) { 240 | zc_error("a_table[%p] or a_key[%p] is NULL, just do nothing", a_table, a_key); 241 | return; 242 | } 243 | 244 | i = a_table->hash(a_key) % a_table->tab_size; 245 | for (p = (a_table->tab)[i]; p; p = p->next) { 246 | if (a_table->equal(a_key, p->key)) 247 | break; 248 | } 249 | 250 | if (!p) { 251 | zc_error("p[%p] not found in hashtable", p); 252 | return; 253 | } 254 | 255 | if (a_table->key_del) { 256 | a_table->key_del(p->key); 257 | } 258 | if (a_table->value_del) { 259 | a_table->value_del(p->value); 260 | } 261 | 262 | if (p->next) { 263 | p->next->prev = p->prev; 264 | } 265 | if (p->prev) { 266 | p->prev->next = p->next; 267 | } else { 268 | unsigned int i; 269 | 270 | i = p->hash_key % a_table->tab_size; 271 | a_table->tab[i] = p->next; 272 | } 273 | 274 | free(p); 275 | a_table->nelem--; 276 | 277 | return; 278 | } 279 | 280 | zc_hashtable_entry_t *zc_hashtable_begin(zc_hashtable_t * a_table) 281 | { 282 | size_t i; 283 | zc_hashtable_entry_t *p; 284 | 285 | for (i = 0; i < a_table->tab_size; i++) { 286 | for (p = (a_table->tab)[i]; p; p = p->next) { 287 | if (p) 288 | return p; 289 | } 290 | } 291 | 292 | return NULL; 293 | } 294 | 295 | zc_hashtable_entry_t *zc_hashtable_next(zc_hashtable_t * a_table, zc_hashtable_entry_t * a_entry) 296 | { 297 | size_t i; 298 | size_t j; 299 | 300 | if (a_entry->next) 301 | return a_entry->next; 302 | 303 | i = a_entry->hash_key % a_table->tab_size; 304 | 305 | for (j = i + 1; j < a_table->tab_size; j++) { 306 | if ((a_table->tab)[j]) { 307 | return (a_table->tab)[j]; 308 | } 309 | } 310 | 311 | return NULL; 312 | } 313 | 314 | /*******************************************************************************/ 315 | 316 | unsigned int zc_hashtable_str_hash(const void *str) 317 | { 318 | unsigned int h = 5381; 319 | const char *p = (const char *)str; 320 | 321 | while (*p != '\0') 322 | h = ((h << 5) + h) + (*p++); /* hash * 33 + c */ 323 | 324 | return h; 325 | } 326 | 327 | int zc_hashtable_str_equal(const void *key1, const void *key2) 328 | { 329 | return (STRCMP((const char *)key1, ==, (const char *)key2)); 330 | } 331 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | # zlog makefile 2 | # Copyright (C) 2010-2012 Hardy Simpson 3 | # This file is released under the LGPL 2.1 license, see the COPYING file 4 | 5 | OBJ= \ 6 | buf.o \ 7 | category.o \ 8 | category_table.o \ 9 | conf.o \ 10 | event.o \ 11 | format.o \ 12 | level.o \ 13 | level_list.o \ 14 | mdc.o \ 15 | record.o \ 16 | record_table.o \ 17 | rotater.o \ 18 | rule.o \ 19 | spec.o \ 20 | thread.o \ 21 | zc_arraylist.o \ 22 | zc_hashtable.o \ 23 | zc_profile.o \ 24 | zc_util.o \ 25 | zlog.o 26 | BINS=zlog-chk-conf 27 | LIBNAME=libzlog 28 | 29 | ZLOG_MAJOR=1 30 | ZLOG_MINOR=2 31 | 32 | # Fallback to gcc when $CC is not in $PATH. 33 | CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') 34 | OPTIMIZATION?=-O2 35 | WARNINGS=-Wall -Wstrict-prototypes -fwrapv 36 | DEBUG?= -g -ggdb 37 | REAL_CFLAGS=$(OPTIMIZATION) -fPIC -pthread $(CFLAGS) $(WARNINGS) $(DEBUG) 38 | REAL_LDFLAGS=$(LDFLAGS) -pthread 39 | 40 | DYLIBSUFFIX=so 41 | STLIBSUFFIX=a 42 | DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR).$(ZLOG_MINOR) 43 | DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(ZLOG_MAJOR) 44 | DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) 45 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) 46 | STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) 47 | STLIB_MAKE_CMD=ar rcs $(STLIBNAME) 48 | 49 | # Installation related variables 50 | PREFIX?=/usr/local 51 | INCLUDE_PATH=include 52 | LIBRARY_PATH=lib 53 | BINARY_PATH=bin 54 | INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH) 55 | INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH) 56 | INSTALL_BINARY_PATH= $(PREFIX)/$(BINARY_PATH) 57 | 58 | # Platform-specific overrides 59 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 60 | compiler_platform := $(shell sh -c '$(CC) --version|grep -i apple') 61 | 62 | ifeq ($(uname_S),SunOS) 63 | # REAL_LDFLAGS+= -ldl -lnsl -lsocket 64 | DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) 65 | INSTALL= cp -r 66 | endif 67 | 68 | # For Darwin builds, check the compiler platform above is not empty. The covers cross compilation on Linux 69 | ifneq ($(compiler_platform),) 70 | DYLIBSUFFIX=dylib 71 | DYLIB_MINOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(ZLOG_MINOR).$(DYLIBSUFFIX) 72 | DYLIB_MAJOR_NAME=$(LIBNAME).$(ZLOG_MAJOR).$(DYLIBSUFFIX) 73 | DYLIB_MAKE_CMD=$(CC) -dynamiclib -install_name $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) 74 | endif 75 | 76 | ifeq ($(uname_S),AIX) 77 | # this logic of minor major is not relevant on AIX or at least not widely used 78 | # not to mention dynamic linker .a preference... 79 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-G,-b64 -maix64 -pthread -o $(DYLIBNAME) $(LDFLAGS) 80 | REAL_CFLAGS+= -maix64 81 | STLIB_MAKE_CMD=OBJECT_MODE=64 ar rcs $(STLIBNAME) $(DYLIB_MAJOR_NAME) 82 | endif 83 | 84 | all: $(DYLIBNAME) $(BINS) 85 | 86 | # Deps (use make dep to generate this) 87 | buf.o: buf.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 88 | zc_xplatform.h zc_util.h buf.h 89 | category.o: category.c fmacros.h category.h zc_defs.h zc_profile.h \ 90 | zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h thread.h event.h \ 91 | buf.h mdc.h rule.h format.h rotater.h record.h 92 | category_table.o: category_table.c zc_defs.h zc_profile.h zc_arraylist.h \ 93 | zc_hashtable.h zc_xplatform.h zc_util.h category_table.h category.h \ 94 | thread.h event.h buf.h mdc.h 95 | conf.o: conf.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ 96 | zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ 97 | mdc.h rotater.h rule.h record.h level_list.h level.h 98 | event.o: event.c fmacros.h zc_defs.h zc_profile.h zc_arraylist.h \ 99 | zc_hashtable.h zc_xplatform.h zc_util.h event.h 100 | format.o: format.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 101 | zc_xplatform.h zc_util.h thread.h event.h buf.h mdc.h spec.h format.h 102 | level.o: level.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 103 | zc_xplatform.h zc_util.h level.h 104 | level_list.o: level_list.c zc_defs.h zc_profile.h zc_arraylist.h \ 105 | zc_hashtable.h zc_xplatform.h zc_util.h level.h level_list.h 106 | mdc.o: mdc.c mdc.h zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 107 | zc_xplatform.h zc_util.h 108 | record.o: record.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 109 | zc_xplatform.h zc_util.h record.h 110 | record_table.o: record_table.c zc_defs.h zc_profile.h zc_arraylist.h \ 111 | zc_hashtable.h zc_xplatform.h zc_util.h record_table.h record.h 112 | rotater.o: rotater.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 113 | zc_xplatform.h zc_util.h rotater.h 114 | rule.o: rule.c fmacros.h rule.h zc_defs.h zc_profile.h zc_arraylist.h \ 115 | zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ 116 | mdc.h rotater.h record.h level_list.h level.h spec.h 117 | spec.o: spec.c fmacros.h spec.h event.h zc_defs.h zc_profile.h \ 118 | zc_arraylist.h zc_hashtable.h zc_xplatform.h zc_util.h buf.h thread.h \ 119 | mdc.h level_list.h level.h 120 | thread.o: thread.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 121 | zc_xplatform.h zc_util.h event.h buf.h thread.h mdc.h 122 | zc_arraylist.o: zc_arraylist.c zc_defs.h zc_profile.h zc_arraylist.h \ 123 | zc_hashtable.h zc_xplatform.h zc_util.h 124 | zc_hashtable.o: zc_hashtable.c zc_defs.h zc_profile.h zc_arraylist.h \ 125 | zc_hashtable.h zc_xplatform.h zc_util.h 126 | zc_profile.o: zc_profile.c fmacros.h zc_profile.h zc_xplatform.h 127 | zc_util.o: zc_util.c zc_defs.h zc_profile.h zc_arraylist.h zc_hashtable.h \ 128 | zc_xplatform.h zc_util.h 129 | zlog-chk-conf.o: zlog-chk-conf.c fmacros.h zlog.h 130 | zlog.o: zlog.c fmacros.h conf.h zc_defs.h zc_profile.h zc_arraylist.h \ 131 | zc_hashtable.h zc_xplatform.h zc_util.h format.h thread.h event.h buf.h \ 132 | mdc.h rotater.h category_table.h category.h record_table.h \ 133 | record.h rule.h 134 | 135 | $(DYLIBNAME): $(OBJ) 136 | $(DYLIB_MAKE_CMD) $(OBJ) $(REAL_LDFLAGS) 137 | # for use in test folder - linux and requirement for aix runtime 138 | # resolving 139 | cp -f $(DYLIBNAME) $(DYLIB_MAJOR_NAME) 140 | cp -f $(DYLIBNAME) $(DYLIB_MINOR_NAME) 141 | 142 | $(STLIBNAME): $(OBJ) 143 | $(STLIB_MAKE_CMD) $(OBJ) 144 | 145 | dynamic: $(DYLIBNAME) 146 | static: $(STLIBNAME) 147 | 148 | # Binaries: 149 | zlog-chk-conf: zlog-chk-conf.o $(STLIBNAME) $(DYLIBNAME) 150 | $(CC) -o $@ zlog-chk-conf.o -L. -lzlog $(REAL_LDFLAGS) 151 | 152 | .c.o: 153 | $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< 154 | 155 | clean: 156 | rm -rf $(DYLIBNAME) $(STLIBNAME) $(BINS) *.o *.gcda *.gcno *.gcov $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) 157 | 158 | dep: 159 | $(CC) -MM *.c 160 | 161 | # Installation target 162 | 163 | ifeq ($(uname_S),SunOS) 164 | INSTALL?= cp -r 165 | endif 166 | 167 | ifeq ($(uname_S),AIX) 168 | INSTALL?= cp -r 169 | endif 170 | 171 | 172 | INSTALL?= cp -a 173 | 174 | install: $(DYLIBNAME) $(STLIBNAME) 175 | mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) $(INSTALL_BINARY_PATH) 176 | $(INSTALL) zlog.h $(INSTALL_INCLUDE_PATH) 177 | $(INSTALL) zlog-chk-conf $(INSTALL_BINARY_PATH) 178 | $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) 179 | cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) 180 | cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) 181 | $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) 182 | 183 | 32bit: 184 | @echo "" 185 | @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" 186 | @echo "" 187 | $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" 188 | 189 | gprof: 190 | $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" 191 | 192 | gcov: 193 | $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" 194 | 195 | coverage: gcov 196 | make check 197 | mkdir -p tmp/lcov 198 | lcov -d . -c -o tmp/lcov/hiredis.info 199 | genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info 200 | 201 | noopt: 202 | $(MAKE) OPTIMIZATION="" 203 | 204 | .PHONY: all clean dep install 32bit gprof gcov noopt 205 | -------------------------------------------------------------------------------- /src/zlog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #ifndef __zlog_h 10 | #define __zlog_h 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | #include /* for va_list */ 17 | #include /* for size_t */ 18 | 19 | # if defined __GNUC__ 20 | # define ZLOG_CHECK_PRINTF(m,n) __attribute__((format(printf,m,n))) 21 | # else 22 | # define ZLOG_CHECK_PRINTF(m,n) 23 | # endif 24 | 25 | typedef struct zlog_category_s zlog_category_t; 26 | 27 | int zlog_init(const char *config); 28 | int zlog_reload(const char *config); 29 | void zlog_fini(void); 30 | 31 | void zlog_profile(void); 32 | 33 | zlog_category_t *zlog_get_category(const char *cname); 34 | int zlog_level_enabled(zlog_category_t *category, const int level); 35 | 36 | int zlog_put_mdc(const char *key, const char *value); 37 | char *zlog_get_mdc(const char *key); 38 | void zlog_remove_mdc(const char *key); 39 | void zlog_clean_mdc(void); 40 | 41 | int zlog_level_switch(zlog_category_t * category, int level); 42 | int zlog_level_enabled(zlog_category_t * category, int level); 43 | 44 | void zlog(zlog_category_t * category, 45 | const char *file, size_t filelen, 46 | const char *func, size_t funclen, 47 | long line, int level, 48 | const char *format, ...) ZLOG_CHECK_PRINTF(8,9); 49 | void vzlog(zlog_category_t * category, 50 | const char *file, size_t filelen, 51 | const char *func, size_t funclen, 52 | long line, int level, 53 | const char *format, va_list args); 54 | void hzlog(zlog_category_t * category, 55 | const char *file, size_t filelen, 56 | const char *func, size_t funclen, 57 | long line, int level, 58 | const void *buf, size_t buflen); 59 | 60 | int dzlog_init(const char *confpath, const char *cname); 61 | int dzlog_set_category(const char *cname); 62 | 63 | void dzlog(const char *file, size_t filelen, 64 | const char *func, size_t funclen, 65 | long line, int level, 66 | const char *format, ...) ZLOG_CHECK_PRINTF(7,8); 67 | void vdzlog(const char *file, size_t filelen, 68 | const char *func, size_t funclen, 69 | long line, int level, 70 | const char *format, va_list args); 71 | void hdzlog(const char *file, size_t filelen, 72 | const char *func, size_t funclen, 73 | long line, int level, 74 | const void *buf, size_t buflen); 75 | 76 | typedef struct zlog_msg_s { 77 | char *buf; 78 | size_t len; 79 | char *path; 80 | } zlog_msg_t; 81 | 82 | typedef int (*zlog_record_fn)(zlog_msg_t *msg); 83 | int zlog_set_record(const char *rname, zlog_record_fn record); 84 | 85 | const char *zlog_version(void); 86 | 87 | /******* useful macros, can be redefined at user's h file **********/ 88 | 89 | typedef enum { 90 | ZLOG_LEVEL_DEBUG = 20, 91 | ZLOG_LEVEL_INFO = 40, 92 | ZLOG_LEVEL_NOTICE = 60, 93 | ZLOG_LEVEL_WARN = 80, 94 | ZLOG_LEVEL_ERROR = 100, 95 | ZLOG_LEVEL_FATAL = 120 96 | } zlog_level; 97 | 98 | #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L 99 | # if defined __GNUC__ && __GNUC__ >= 2 100 | # define __func__ __FUNCTION__ 101 | # else 102 | # define __func__ "" 103 | # endif 104 | #endif 105 | 106 | #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L 107 | /* zlog macros */ 108 | #define zlog_fatal(cat, ...) \ 109 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 110 | ZLOG_LEVEL_FATAL, __VA_ARGS__) 111 | #define zlog_error(cat, ...) \ 112 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 113 | ZLOG_LEVEL_ERROR, __VA_ARGS__) 114 | #define zlog_warn(cat, ...) \ 115 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 116 | ZLOG_LEVEL_WARN, __VA_ARGS__) 117 | #define zlog_notice(cat, ...) \ 118 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 119 | ZLOG_LEVEL_NOTICE, __VA_ARGS__) 120 | #define zlog_info(cat, ...) \ 121 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 122 | ZLOG_LEVEL_INFO, __VA_ARGS__) 123 | #define zlog_debug(cat, ...) \ 124 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 125 | ZLOG_LEVEL_DEBUG, __VA_ARGS__) 126 | /* dzlog macros */ 127 | #define dzlog_fatal(...) \ 128 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 129 | ZLOG_LEVEL_FATAL, __VA_ARGS__) 130 | #define dzlog_error(...) \ 131 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 132 | ZLOG_LEVEL_ERROR, __VA_ARGS__) 133 | #define dzlog_warn(...) \ 134 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 135 | ZLOG_LEVEL_WARN, __VA_ARGS__) 136 | #define dzlog_notice(...) \ 137 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 138 | ZLOG_LEVEL_NOTICE, __VA_ARGS__) 139 | #define dzlog_info(...) \ 140 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 141 | ZLOG_LEVEL_INFO, __VA_ARGS__) 142 | #define dzlog_debug(...) \ 143 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 144 | ZLOG_LEVEL_DEBUG, __VA_ARGS__) 145 | #elif defined __GNUC__ 146 | /* zlog macros */ 147 | #define zlog_fatal(cat, format, args...) \ 148 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 149 | ZLOG_LEVEL_FATAL, format, ##args) 150 | #define zlog_error(cat, format, args...) \ 151 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 152 | ZLOG_LEVEL_ERROR, format, ##args) 153 | #define zlog_warn(cat, format, args...) \ 154 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 155 | ZLOG_LEVEL_WARN, format, ##args) 156 | #define zlog_notice(cat, format, args...) \ 157 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 158 | ZLOG_LEVEL_NOTICE, format, ##args) 159 | #define zlog_info(cat, format, args...) \ 160 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 161 | ZLOG_LEVEL_INFO, format, ##args) 162 | #define zlog_debug(cat, format, args...) \ 163 | zlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 164 | ZLOG_LEVEL_DEBUG, format, ##args) 165 | /* dzlog macros */ 166 | #define dzlog_fatal(format, args...) \ 167 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 168 | ZLOG_LEVEL_FATAL, format, ##args) 169 | #define dzlog_error(format, args...) \ 170 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 171 | ZLOG_LEVEL_ERROR, format, ##args) 172 | #define dzlog_warn(format, args...) \ 173 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 174 | ZLOG_LEVEL_WARN, format, ##args) 175 | #define dzlog_notice(format, args...) \ 176 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 177 | ZLOG_LEVEL_NOTICE, format, ##args) 178 | #define dzlog_info(format, args...) \ 179 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 180 | ZLOG_LEVEL_INFO, format, ##args) 181 | #define dzlog_debug(format, args...) \ 182 | dzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 183 | ZLOG_LEVEL_DEBUG, format, ##args) 184 | #endif 185 | 186 | /* vzlog macros */ 187 | #define vzlog_fatal(cat, format, args) \ 188 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 189 | ZLOG_LEVEL_FATAL, format, args) 190 | #define vzlog_error(cat, format, args) \ 191 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 192 | ZLOG_LEVEL_ERROR, format, args) 193 | #define vzlog_warn(cat, format, args) \ 194 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 195 | ZLOG_LEVEL_WARN, format, args) 196 | #define vzlog_notice(cat, format, args) \ 197 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 198 | ZLOG_LEVEL_NOTICE, format, args) 199 | #define vzlog_info(cat, format, args) \ 200 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 201 | ZLOG_LEVEL_INFO, format, args) 202 | #define vzlog_debug(cat, format, args) \ 203 | vzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 204 | ZLOG_LEVEL_DEBUG, format, args) 205 | 206 | /* hzlog macros */ 207 | #define hzlog_fatal(cat, buf, buf_len) \ 208 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 209 | ZLOG_LEVEL_FATAL, buf, buf_len) 210 | #define hzlog_error(cat, buf, buf_len) \ 211 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 212 | ZLOG_LEVEL_ERROR, buf, buf_len) 213 | #define hzlog_warn(cat, buf, buf_len) \ 214 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 215 | ZLOG_LEVEL_WARN, buf, buf_len) 216 | #define hzlog_notice(cat, buf, buf_len) \ 217 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 218 | ZLOG_LEVEL_NOTICE, buf, buf_len) 219 | #define hzlog_info(cat, buf, buf_len) \ 220 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 221 | ZLOG_LEVEL_INFO, buf, buf_len) 222 | #define hzlog_debug(cat, buf, buf_len) \ 223 | hzlog(cat, __FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 224 | ZLOG_LEVEL_DEBUG, buf, buf_len) 225 | 226 | 227 | /* vdzlog macros */ 228 | #define vdzlog_fatal(format, args) \ 229 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 230 | ZLOG_LEVEL_FATAL, format, args) 231 | #define vdzlog_error(format, args) \ 232 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 233 | ZLOG_LEVEL_ERROR, format, args) 234 | #define vdzlog_warn(format, args) \ 235 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 236 | ZLOG_LEVEL_WARN, format, args) 237 | #define vdzlog_notice(format, args) \ 238 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 239 | ZLOG_LEVEL_NOTICE, format, args) 240 | #define vdzlog_info(format, args) \ 241 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 242 | ZLOG_LEVEL_INFO, format, args) 243 | #define vdzlog_debug(format, args) \ 244 | vdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 245 | ZLOG_LEVEL_DEBUG, format, args) 246 | 247 | /* hdzlog macros */ 248 | #define hdzlog_fatal(buf, buf_len) \ 249 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 250 | ZLOG_LEVEL_FATAL, buf, buf_len) 251 | #define hdzlog_error(buf, buf_len) \ 252 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 253 | ZLOG_LEVEL_ERROR, buf, buf_len) 254 | #define hdzlog_warn(buf, buf_len) \ 255 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 256 | ZLOG_LEVEL_WARN, buf, buf_len) 257 | #define hdzlog_notice(buf, buf_len) \ 258 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 259 | ZLOG_LEVEL_NOTICE, buf, buf_len) 260 | #define hdzlog_info(buf, buf_len) \ 261 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 262 | ZLOG_LEVEL_INFO, buf, buf_len) 263 | #define hdzlog_debug(buf, buf_len) \ 264 | hdzlog(__FILE__, sizeof(__FILE__)-1, __func__, sizeof(__func__)-1, __LINE__, \ 265 | ZLOG_LEVEL_DEBUG, buf, buf_len) 266 | 267 | /* enabled macros */ 268 | #define zlog_fatal_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_FATAL) 269 | #define zlog_error_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_ERROR) 270 | #define zlog_warn_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_WARN) 271 | #define zlog_notice_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_NOTICE) 272 | #define zlog_info_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_INFO) 273 | #define zlog_debug_enabled(zc) zlog_level_enabled(zc, ZLOG_LEVEL_DEBUG) 274 | 275 | #ifdef __cplusplus 276 | } 277 | #endif 278 | 279 | #endif 280 | -------------------------------------------------------------------------------- /src/rotater.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "zc_defs.h" 22 | #include "rotater.h" 23 | 24 | #define ROLLING 1 /* aa.02->aa.03, aa.01->aa.02, aa->aa.01 */ 25 | #define SEQUENCE 2 /* aa->aa.03 */ 26 | 27 | typedef struct { 28 | int index; 29 | char path[MAXLEN_PATH + 1]; 30 | } zlog_file_t; 31 | 32 | void zlog_rotater_profile(zlog_rotater_t * a_rotater, int flag) 33 | { 34 | zc_assert(a_rotater,); 35 | zc_profile(flag, "--rotater[%p][%p,%s,%d][%s,%s,%s,%ld,%ld,%d,%d,%d]--", 36 | a_rotater, 37 | 38 | &(a_rotater->lock_mutex), 39 | a_rotater->lock_file, 40 | a_rotater->lock_fd, 41 | 42 | a_rotater->base_path, 43 | a_rotater->archive_path, 44 | a_rotater->glob_path, 45 | (long)a_rotater->num_start_len, 46 | (long)a_rotater->num_end_len, 47 | a_rotater->num_width, 48 | a_rotater->mv_type, 49 | a_rotater->max_count 50 | ); 51 | if (a_rotater->files) { 52 | int i; 53 | zlog_file_t *a_file; 54 | zc_arraylist_foreach(a_rotater->files, i, a_file) { 55 | zc_profile(flag, "[%s,%d]->", a_file->path, a_file->index); 56 | } 57 | } 58 | return; 59 | } 60 | 61 | /*******************************************************************************/ 62 | void zlog_rotater_del(zlog_rotater_t *a_rotater) 63 | { 64 | zc_assert(a_rotater,); 65 | 66 | if (a_rotater->lock_fd) { 67 | if (close(a_rotater->lock_fd)) { 68 | zc_error("close fail, errno[%d]", errno); 69 | } 70 | } 71 | 72 | if (pthread_mutex_destroy(&(a_rotater->lock_mutex))) { 73 | zc_error("pthread_mutex_destroy fail, errno[%d]", errno); 74 | } 75 | 76 | zc_debug("zlog_rotater_del[%p]", a_rotater); 77 | free(a_rotater); 78 | return; 79 | } 80 | 81 | zlog_rotater_t *zlog_rotater_new(char *lock_file) 82 | { 83 | int fd = 0; 84 | zlog_rotater_t *a_rotater; 85 | 86 | zc_assert(lock_file, NULL); 87 | 88 | a_rotater = calloc(1, sizeof(zlog_rotater_t)); 89 | if (!a_rotater) { 90 | zc_error("calloc fail, errno[%d]", errno); 91 | return NULL; 92 | } 93 | 94 | if (pthread_mutex_init(&(a_rotater->lock_mutex), NULL)) { 95 | zc_error("pthread_mutex_init fail, errno[%d]", errno); 96 | free(a_rotater); 97 | return NULL; 98 | } 99 | 100 | /* depends on umask of the user here 101 | * if user A create /tmp/zlog.lock 0600 102 | * user B is unable to read /tmp/zlog.lock 103 | * B has to choose another lock file except /tmp/zlog.lock 104 | */ 105 | fd = open(lock_file, O_RDWR | O_CREAT, 106 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 107 | if (fd < 0) { 108 | zc_error("open file[%s] fail, errno[%d]", lock_file, errno); 109 | goto err; 110 | } 111 | 112 | a_rotater->lock_fd = fd; 113 | a_rotater->lock_file = lock_file; 114 | 115 | //zlog_rotater_profile(a_rotater, ZC_DEBUG); 116 | return a_rotater; 117 | err: 118 | zlog_rotater_del(a_rotater); 119 | return NULL; 120 | } 121 | 122 | /*******************************************************************************/ 123 | 124 | static void zlog_file_del(zlog_file_t * a_file) 125 | { 126 | zc_debug("del onefile[%p]", a_file); 127 | zc_debug("a_file->path[%s]", a_file->path); 128 | free(a_file); 129 | } 130 | 131 | static zlog_file_t *zlog_file_check_new(zlog_rotater_t * a_rotater, const char *path) 132 | { 133 | int nwrite; 134 | int nread; 135 | zlog_file_t *a_file; 136 | 137 | /* base_path will not be in list */ 138 | if (STRCMP(a_rotater->base_path, ==, path)) { 139 | return NULL; 140 | } 141 | 142 | /* omit dirs */ 143 | if ((path)[strlen(path) - 1] == '/') { 144 | return NULL; 145 | } 146 | 147 | a_file = calloc(1, sizeof(zlog_file_t)); 148 | if (!a_file) { 149 | zc_error("calloc fail, errno[%d]", errno); 150 | return NULL; 151 | } 152 | 153 | nwrite = snprintf(a_file->path, sizeof(a_file->path), "%s", path); 154 | if (nwrite < 0 || nwrite >= sizeof(a_file->path)) { 155 | zc_error("snprintf fail or overflow, nwrite=[%d], errno[%d]", nwrite, errno); 156 | goto err; 157 | } 158 | 159 | nread = 0; 160 | sscanf(a_file->path + a_rotater->num_start_len, "%d%n", &(a_file->index), &(nread)); 161 | 162 | if (a_rotater->num_width != 0) { 163 | if (nread < a_rotater->num_width) { 164 | zc_warn("aa.1.log is not expect, need aa.01.log"); 165 | goto err; 166 | } 167 | } /* else all file is ok */ 168 | 169 | return a_file; 170 | err: 171 | free(a_file); 172 | return NULL; 173 | } 174 | 175 | 176 | static int zlog_file_cmp(zlog_file_t * a_file_1, zlog_file_t * a_file_2) 177 | { 178 | return (a_file_1->index > a_file_2->index); 179 | } 180 | 181 | static int zlog_rotater_add_archive_files(zlog_rotater_t * a_rotater) 182 | { 183 | int rc = 0; 184 | glob_t glob_buf; 185 | size_t pathc; 186 | char **pathv; 187 | zlog_file_t *a_file; 188 | 189 | a_rotater->files = zc_arraylist_new((zc_arraylist_del_fn)zlog_file_del); 190 | if (!a_rotater->files) { 191 | zc_error("zc_arraylist_new fail"); 192 | return -1; 193 | } 194 | 195 | /* scan file which is aa.*.log and aa */ 196 | rc = glob(a_rotater->glob_path, GLOB_ERR | GLOB_MARK | GLOB_NOSORT, NULL, &glob_buf); 197 | if (rc == GLOB_NOMATCH) { 198 | goto exit; 199 | } else if (rc) { 200 | zc_error("glob err, rc=[%d], errno[%d]", rc, errno); 201 | return -1; 202 | } 203 | 204 | pathv = glob_buf.gl_pathv; 205 | pathc = glob_buf.gl_pathc; 206 | 207 | /* check and find match aa.[0-9]*.log, depend on num_width */ 208 | for (; pathc-- > 0; pathv++) { 209 | a_file = zlog_file_check_new(a_rotater, *pathv); 210 | if (!a_file) { 211 | zc_warn("not the expect pattern file"); 212 | continue; 213 | } 214 | 215 | /* file in list aa.00, aa.01, aa.02... */ 216 | rc = zc_arraylist_sortadd(a_rotater->files, 217 | (zc_arraylist_cmp_fn)zlog_file_cmp, a_file); 218 | if (rc) { 219 | zc_error("zc_arraylist_sortadd fail"); 220 | goto err; 221 | } 222 | } 223 | 224 | exit: 225 | globfree(&glob_buf); 226 | return 0; 227 | err: 228 | globfree(&glob_buf); 229 | return -1; 230 | } 231 | 232 | static int zlog_rotater_seq_files(zlog_rotater_t * a_rotater) 233 | { 234 | int rc = 0; 235 | int nwrite = 0; 236 | int i, j; 237 | zlog_file_t *a_file; 238 | char new_path[MAXLEN_PATH + 1]; 239 | 240 | zc_arraylist_foreach(a_rotater->files, i, a_file) { 241 | if (a_rotater->max_count > 0 242 | && i < zc_arraylist_len(a_rotater->files) - a_rotater->max_count) { 243 | /* unlink aa.0 aa.1 .. aa.(n-c) */ 244 | rc = unlink(a_file->path); 245 | if (rc) { 246 | zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno); 247 | return -1; 248 | } 249 | continue; 250 | } 251 | } 252 | 253 | if (zc_arraylist_len(a_rotater->files) > 0) { /* list is not empty */ 254 | a_file = zc_arraylist_get(a_rotater->files, zc_arraylist_len(a_rotater->files)-1); 255 | if (!a_file) { 256 | zc_error("zc_arraylist_get fail"); 257 | return -1; 258 | } 259 | 260 | j = zc_max(zc_arraylist_len(a_rotater->files)-1, a_file->index) + 1; 261 | } else { 262 | j = 0; 263 | } 264 | 265 | /* do the base_path mv */ 266 | memset(new_path, 0x00, sizeof(new_path)); 267 | nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", 268 | (int) a_rotater->num_start_len, a_rotater->glob_path, 269 | a_rotater->num_width, j, 270 | a_rotater->glob_path + a_rotater->num_end_len); 271 | if (nwrite < 0 || nwrite >= sizeof(new_path)) { 272 | zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); 273 | return -1; 274 | } 275 | 276 | if (rename(a_rotater->base_path, new_path)) { 277 | zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno); 278 | return -1; 279 | } 280 | 281 | return 0; 282 | } 283 | 284 | 285 | static int zlog_rotater_roll_files(zlog_rotater_t * a_rotater) 286 | { 287 | int i; 288 | int rc = 0; 289 | int nwrite; 290 | char new_path[MAXLEN_PATH + 1]; 291 | zlog_file_t *a_file; 292 | 293 | /* now in the list, aa.0 aa.1 aa.2 aa.02... */ 294 | for (i = zc_arraylist_len(a_rotater->files) - 1; i > -1; i--) { 295 | a_file = zc_arraylist_get(a_rotater->files, i); 296 | if (!a_file) { 297 | zc_error("zc_arraylist_get fail"); 298 | return -1; 299 | } 300 | 301 | if (a_rotater->max_count > 0 && i >= a_rotater->max_count - 1) { 302 | /* remove file.3 >= 3*/ 303 | rc = unlink(a_file->path); 304 | if (rc) { 305 | zc_error("unlink[%s] fail, errno[%d]",a_file->path , errno); 306 | return -1; 307 | } 308 | continue; 309 | } 310 | 311 | /* begin rename aa.01.log -> aa.02.log , using i, as index in list maybe repeat */ 312 | memset(new_path, 0x00, sizeof(new_path)); 313 | nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", 314 | (int) a_rotater->num_start_len, a_rotater->glob_path, 315 | a_rotater->num_width, i + 1, 316 | a_rotater->glob_path + a_rotater->num_end_len); 317 | if (nwrite < 0 || nwrite >= sizeof(new_path)) { 318 | zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); 319 | return -1; 320 | } 321 | 322 | if (rename(a_file->path, new_path)) { 323 | zc_error("rename[%s]->[%s] fail, errno[%d]", a_file->path, new_path, errno); 324 | return -1; 325 | } 326 | } 327 | 328 | /* do the base_path mv */ 329 | memset(new_path, 0x00, sizeof(new_path)); 330 | nwrite = snprintf(new_path, sizeof(new_path), "%.*s%0*d%s", 331 | (int) a_rotater->num_start_len, a_rotater->glob_path, 332 | a_rotater->num_width, 0, 333 | a_rotater->glob_path + a_rotater->num_end_len); 334 | if (nwrite < 0 || nwrite >= sizeof(new_path)) { 335 | zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); 336 | return -1; 337 | } 338 | 339 | if (rename(a_rotater->base_path, new_path)) { 340 | zc_error("rename[%s]->[%s] fail, errno[%d]", a_rotater->base_path, new_path, errno); 341 | return -1; 342 | } 343 | 344 | return 0; 345 | } 346 | 347 | 348 | static int zlog_rotater_parse_archive_path(zlog_rotater_t * a_rotater) 349 | { 350 | int nwrite; 351 | int nread; 352 | char *p; 353 | size_t len; 354 | 355 | /* no archive path is set */ 356 | if (a_rotater->archive_path[0] == '\0') { 357 | nwrite = snprintf(a_rotater->glob_path, sizeof(a_rotater->glob_path), 358 | "%s.*", a_rotater->base_path); 359 | if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path)) { 360 | zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); 361 | return -1; 362 | } 363 | 364 | a_rotater->mv_type = ROLLING; 365 | a_rotater->num_width = 0; 366 | a_rotater->num_start_len = strlen(a_rotater->base_path) + 1; 367 | a_rotater->num_end_len = strlen(a_rotater->base_path) + 2; 368 | return 0; 369 | } else { 370 | 371 | /* find the 1st # */ 372 | p = strchr(a_rotater->archive_path, '#'); 373 | if (!p) { 374 | zc_error("no # in archive_path[%s]", a_rotater->archive_path); 375 | return -1; 376 | } 377 | 378 | nread = 0; 379 | sscanf(p, "#%d%n", &(a_rotater->num_width), &nread); 380 | if (nread == 0) nread = 1; 381 | if (*(p+nread) == 'r') { 382 | a_rotater->mv_type = ROLLING; 383 | } else if (*(p+nread) == 's') { 384 | a_rotater->mv_type = SEQUENCE; 385 | } else { 386 | zc_error("#r or #s not found"); 387 | return -1; 388 | } 389 | 390 | /* copy and substitue #i to * in glob_path*/ 391 | len = p - a_rotater->archive_path; 392 | if (len > sizeof(a_rotater->glob_path) - 1) { 393 | zc_error("sizeof glob_path not enough,len[%ld]", (long) len); 394 | return -1; 395 | } 396 | memcpy(a_rotater->glob_path, a_rotater->archive_path, len); 397 | 398 | nwrite = snprintf(a_rotater->glob_path + len, sizeof(a_rotater->glob_path) - len, 399 | "*%s", p + nread + 1); 400 | if (nwrite < 0 || nwrite > sizeof(a_rotater->glob_path) - len) { 401 | zc_error("nwirte[%d], overflow or errno[%d]", nwrite, errno); 402 | return -1; 403 | } 404 | 405 | a_rotater->num_start_len = len; 406 | a_rotater->num_end_len = len + 1; 407 | } 408 | 409 | return 0; 410 | } 411 | 412 | static void zlog_rotater_clean(zlog_rotater_t *a_rotater) 413 | { 414 | a_rotater->base_path = NULL; 415 | a_rotater->archive_path = NULL; 416 | a_rotater->max_count = 0; 417 | a_rotater->mv_type = 0; 418 | a_rotater->num_width = 0; 419 | a_rotater->num_start_len = 0; 420 | a_rotater->num_end_len = 0; 421 | memset(a_rotater->glob_path, 0x00, sizeof(a_rotater->glob_path)); 422 | 423 | if (a_rotater->files) zc_arraylist_del(a_rotater->files); 424 | a_rotater->files = NULL; 425 | } 426 | 427 | static int zlog_rotater_lsmv(zlog_rotater_t *a_rotater, 428 | char *base_path, char *archive_path, int archive_max_count) 429 | { 430 | int rc = 0; 431 | 432 | a_rotater->base_path = base_path; 433 | a_rotater->archive_path = archive_path; 434 | a_rotater->max_count = archive_max_count; 435 | rc = zlog_rotater_parse_archive_path(a_rotater); 436 | if (rc) { 437 | zc_error("zlog_rotater_parse_archive_path fail"); 438 | goto err; 439 | } 440 | 441 | rc = zlog_rotater_add_archive_files(a_rotater); 442 | if (rc) { 443 | zc_error("zlog_rotater_add_archive_files fail"); 444 | goto err; 445 | } 446 | 447 | if (a_rotater->mv_type == ROLLING) { 448 | rc = zlog_rotater_roll_files(a_rotater); 449 | if (rc) { 450 | zc_error("zlog_rotater_roll_files fail"); 451 | goto err; 452 | } 453 | } else if (a_rotater->mv_type == SEQUENCE) { 454 | rc = zlog_rotater_seq_files(a_rotater); 455 | if (rc) { 456 | zc_error("zlog_rotater_seq_files fail"); 457 | goto err; 458 | } 459 | } 460 | 461 | zlog_rotater_clean(a_rotater); 462 | return 0; 463 | err: 464 | zlog_rotater_clean(a_rotater); 465 | return -1; 466 | } 467 | /*******************************************************************************/ 468 | 469 | static int zlog_rotater_trylock(zlog_rotater_t *a_rotater) 470 | { 471 | int rc; 472 | struct flock fl; 473 | 474 | fl.l_type = F_WRLCK; 475 | fl.l_start = 0; 476 | fl.l_whence = SEEK_SET; 477 | fl.l_len = 0; 478 | 479 | rc = pthread_mutex_trylock(&(a_rotater->lock_mutex)); 480 | if (rc == EBUSY) { 481 | zc_warn("pthread_mutex_trylock fail, as lock_mutex is locked by other threads"); 482 | return -1; 483 | } else if (rc != 0) { 484 | zc_error("pthread_mutex_trylock fail, rc[%d]", rc); 485 | return -1; 486 | } 487 | 488 | if (fcntl(a_rotater->lock_fd, F_SETLK, &fl)) { 489 | if (errno == EAGAIN || errno == EACCES) { 490 | /* lock by other process, that's right, go on */ 491 | /* EAGAIN on linux */ 492 | /* EACCES on AIX */ 493 | zc_warn("fcntl lock fail, as file is lock by other process"); 494 | } else { 495 | zc_error("lock fd[%d] fail, errno[%d]", a_rotater->lock_fd, errno); 496 | } 497 | if (pthread_mutex_unlock(&(a_rotater->lock_mutex))) { 498 | zc_error("pthread_mutex_unlock fail, errno[%d]", errno); 499 | } 500 | return -1; 501 | } 502 | 503 | return 0; 504 | } 505 | 506 | static int zlog_rotater_unlock(zlog_rotater_t *a_rotater) 507 | { 508 | int rc = 0; 509 | struct flock fl; 510 | 511 | fl.l_type = F_UNLCK; 512 | fl.l_start = 0; 513 | fl.l_whence = SEEK_SET; 514 | fl.l_len = 0; 515 | 516 | if (fcntl(a_rotater->lock_fd, F_SETLK, &fl)) { 517 | rc = -1; 518 | zc_error("unlock fd[%s] fail, errno[%d]", a_rotater->lock_fd, errno); 519 | } 520 | 521 | if (pthread_mutex_unlock(&(a_rotater->lock_mutex))) { 522 | rc = -1; 523 | zc_error("pthread_mutext_unlock fail, errno[%d]", errno); 524 | } 525 | 526 | return rc; 527 | } 528 | 529 | int zlog_rotater_rotate(zlog_rotater_t *a_rotater, 530 | char *base_path, size_t msg_len, 531 | char *archive_path, long archive_max_size, int archive_max_count) 532 | { 533 | int rc = 0; 534 | struct zlog_stat info; 535 | 536 | zc_assert(base_path, -1); 537 | 538 | if (zlog_rotater_trylock(a_rotater)) { 539 | zc_warn("zlog_rotater_trylock fail, maybe lock by other process or threads"); 540 | return 0; 541 | } 542 | 543 | if (stat(base_path, &info)) { 544 | rc = -1; 545 | zc_error("stat [%s] fail, errno[%d]", base_path, errno); 546 | goto exit; 547 | } 548 | 549 | if (info.st_size + msg_len <= archive_max_size) { 550 | /* file not so big, 551 | * may alread rotate by oth process or thread, 552 | * return */ 553 | rc = 0; 554 | goto exit; 555 | } 556 | 557 | /* begin list and move files */ 558 | rc = zlog_rotater_lsmv(a_rotater, base_path, archive_path, archive_max_count); 559 | if (rc) { 560 | zc_error("zlog_rotater_lsmv [%s] fail, return", base_path); 561 | rc = -1; 562 | } /* else if (rc == 0) */ 563 | 564 | //zc_debug("zlog_rotater_file_ls_mv success"); 565 | 566 | exit: 567 | /* unlock file */ 568 | if (zlog_rotater_unlock(a_rotater)) { 569 | zc_error("zlog_rotater_unlock fail"); 570 | } 571 | 572 | return rc; 573 | } 574 | 575 | /*******************************************************************************/ 576 | -------------------------------------------------------------------------------- /src/conf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the zlog Library. 3 | * 4 | * Copyright (C) 2011 by Hardy Simpson 5 | * 6 | * Licensed under the LGPL v2.1, see the file COPYING in base directory. 7 | */ 8 | 9 | #include "fmacros.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "conf.h" 21 | #include "rule.h" 22 | #include "format.h" 23 | #include "level_list.h" 24 | #include "rotater.h" 25 | #include "zc_defs.h" 26 | 27 | /*******************************************************************************/ 28 | #define ZLOG_CONF_DEFAULT_FORMAT "default = \"%D %V [%p:%F:%L] %m%n\"" 29 | #define ZLOG_CONF_DEFAULT_RULE "*.* >stdout" 30 | #define ZLOG_CONF_DEFAULT_BUF_SIZE_MIN 1024 31 | #define ZLOG_CONF_DEFAULT_BUF_SIZE_MAX (2 * 1024 * 1024) 32 | #define ZLOG_CONF_DEFAULT_FILE_PERMS 0600 33 | #define ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD 0 34 | #define ZLOG_CONF_DEFAULT_FSYNC_PERIOD 0 35 | #define ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE "/tmp/zlog.lock" 36 | /*******************************************************************************/ 37 | 38 | void zlog_conf_profile(zlog_conf_t * a_conf, int flag) 39 | { 40 | int i; 41 | zlog_rule_t *a_rule; 42 | zlog_format_t *a_format; 43 | 44 | zc_assert(a_conf,); 45 | zc_profile(flag, "-conf[%p]-", a_conf); 46 | zc_profile(flag, "--global--"); 47 | zc_profile(flag, "---file[%s],mtime[%s]---", a_conf->file, a_conf->mtime); 48 | zc_profile(flag, "---in-memory conf[%s]---", a_conf->cfg_ptr); 49 | zc_profile(flag, "---strict init[%d]---", a_conf->strict_init); 50 | zc_profile(flag, "---buffer min[%ld]---", a_conf->buf_size_min); 51 | zc_profile(flag, "---buffer max[%ld]---", a_conf->buf_size_max); 52 | if (a_conf->default_format) { 53 | zc_profile(flag, "---default_format---"); 54 | zlog_format_profile(a_conf->default_format, flag); 55 | } 56 | zc_profile(flag, "---file perms[0%o]---", a_conf->file_perms); 57 | zc_profile(flag, "---reload conf period[%ld]---", a_conf->reload_conf_period); 58 | zc_profile(flag, "---fsync period[%ld]---", a_conf->fsync_period); 59 | 60 | zc_profile(flag, "---rotate lock file[%s]---", a_conf->rotate_lock_file); 61 | if (a_conf->rotater) zlog_rotater_profile(a_conf->rotater, flag); 62 | 63 | if (a_conf->levels) zlog_level_list_profile(a_conf->levels, flag); 64 | 65 | if (a_conf->formats) { 66 | zc_profile(flag, "--format list[%p]--", a_conf->formats); 67 | zc_arraylist_foreach(a_conf->formats, i, a_format) { 68 | zlog_format_profile(a_format, flag); 69 | } 70 | } 71 | 72 | if (a_conf->rules) { 73 | zc_profile(flag, "--rule_list[%p]--", a_conf->rules); 74 | zc_arraylist_foreach(a_conf->rules, i, a_rule) { 75 | zlog_rule_profile(a_rule, flag); 76 | } 77 | } 78 | 79 | return; 80 | } 81 | /*******************************************************************************/ 82 | void zlog_conf_del(zlog_conf_t * a_conf) 83 | { 84 | zc_assert(a_conf,); 85 | if (a_conf->rotater) zlog_rotater_del(a_conf->rotater); 86 | if (a_conf->levels) zlog_level_list_del(a_conf->levels); 87 | if (a_conf->default_format) zlog_format_del(a_conf->default_format); 88 | if (a_conf->formats) zc_arraylist_del(a_conf->formats); 89 | if (a_conf->rules) zc_arraylist_del(a_conf->rules); 90 | free(a_conf); 91 | zc_debug("zlog_conf_del[%p]"); 92 | return; 93 | } 94 | 95 | static int zlog_conf_build_without_file(zlog_conf_t * a_conf); 96 | static int zlog_conf_build_with_file(zlog_conf_t * a_conf); 97 | static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf); 98 | 99 | enum{ 100 | NO_CFG, 101 | FILE_CFG, 102 | IN_MEMORY_CFG 103 | }; 104 | 105 | zlog_conf_t *zlog_conf_new(const char *config) 106 | { 107 | int nwrite = 0; 108 | int cfg_source = 0; 109 | zlog_conf_t *a_conf = NULL; 110 | 111 | a_conf = calloc(1, sizeof(zlog_conf_t)); 112 | if (!a_conf) { 113 | zc_error("calloc fail, errno[%d]", errno); 114 | return NULL; 115 | } 116 | 117 | // Find content of pointer. If it starts with '[' then content are configurations. 118 | if (config && config[0] != '\0' && config[0] != '[') { 119 | nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", config); 120 | cfg_source = FILE_CFG; 121 | } else if (getenv("ZLOG_CONF_PATH") != NULL) { 122 | nwrite = snprintf(a_conf->file, sizeof(a_conf->file), "%s", getenv("ZLOG_CONF_PATH")); 123 | cfg_source = FILE_CFG; 124 | } else if (config[0]=='[') { 125 | memset(a_conf->file, 0x00, sizeof(a_conf->file)); 126 | nwrite = snprintf(a_conf->cfg_ptr, sizeof(a_conf->cfg_ptr), "%s", config); 127 | cfg_source = IN_MEMORY_CFG; 128 | if (nwrite < 0 || nwrite >= sizeof(a_conf->file)) { 129 | zc_error("not enough space for configurations, nwrite=[%d], errno[%d]", nwrite, errno); 130 | goto err; 131 | } 132 | } else { 133 | memset(a_conf->file, 0x00, sizeof(a_conf->file)); 134 | cfg_source = NO_CFG; 135 | } 136 | if (nwrite < 0 || nwrite >= sizeof(a_conf->file) && cfg_source == FILE_CFG) { 137 | zc_error("not enough space for path name, nwrite=[%d], errno[%d]", nwrite, errno); 138 | goto err; 139 | } 140 | 141 | /* set default configuration start */ 142 | a_conf->strict_init = 1; 143 | a_conf->buf_size_min = ZLOG_CONF_DEFAULT_BUF_SIZE_MIN; 144 | a_conf->buf_size_max = ZLOG_CONF_DEFAULT_BUF_SIZE_MAX; 145 | if (cfg_source == FILE_CFG) { 146 | /* configure file as default lock file */ 147 | strcpy(a_conf->rotate_lock_file, a_conf->file); 148 | } else { 149 | strcpy(a_conf->rotate_lock_file, ZLOG_CONF_BACKUP_ROTATE_LOCK_FILE); 150 | } 151 | strcpy(a_conf->default_format_line, ZLOG_CONF_DEFAULT_FORMAT); 152 | a_conf->file_perms = ZLOG_CONF_DEFAULT_FILE_PERMS; 153 | a_conf->reload_conf_period = ZLOG_CONF_DEFAULT_RELOAD_CONF_PERIOD; 154 | a_conf->fsync_period = ZLOG_CONF_DEFAULT_FSYNC_PERIOD; 155 | /* set default configuration end */ 156 | 157 | a_conf->levels = zlog_level_list_new(); 158 | if (!a_conf->levels) { 159 | zc_error("zlog_level_list_new fail"); 160 | goto err; 161 | } 162 | 163 | a_conf->formats = zc_arraylist_new((zc_arraylist_del_fn) zlog_format_del); 164 | if (!a_conf->formats) { 165 | zc_error("zc_arraylist_new fail"); 166 | goto err; 167 | } 168 | 169 | a_conf->rules = zc_arraylist_new((zc_arraylist_del_fn) zlog_rule_del); 170 | if (!a_conf->rules) { 171 | zc_error("init rule_list fail"); 172 | goto err; 173 | } 174 | 175 | if (cfg_source == FILE_CFG) { 176 | if (zlog_conf_build_with_file(a_conf)) { 177 | zc_error("zlog_conf_build_with_file fail"); 178 | goto err; 179 | } 180 | } else if (cfg_source == IN_MEMORY_CFG) { 181 | if(zlog_conf_build_with_in_memory(a_conf)){ 182 | zc_error("zlog_conf_build_with_in_memory fail"); 183 | goto err; 184 | } 185 | } else { 186 | if (zlog_conf_build_without_file(a_conf)) { 187 | zc_error("zlog_conf_build_without_file fail"); 188 | goto err; 189 | } 190 | } 191 | 192 | zlog_conf_profile(a_conf, ZC_DEBUG); 193 | return a_conf; 194 | err: 195 | zlog_conf_del(a_conf); 196 | return NULL; 197 | } 198 | /*******************************************************************************/ 199 | static int zlog_conf_build_without_file(zlog_conf_t * a_conf) 200 | { 201 | zlog_rule_t *default_rule; 202 | 203 | a_conf->default_format = zlog_format_new(a_conf->default_format_line, &(a_conf->time_cache_count)); 204 | if (!a_conf->default_format) { 205 | zc_error("zlog_format_new fail"); 206 | return -1; 207 | } 208 | 209 | a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file); 210 | if (!a_conf->rotater) { 211 | zc_error("zlog_rotater_new fail"); 212 | return -1; 213 | } 214 | 215 | default_rule = zlog_rule_new( 216 | ZLOG_CONF_DEFAULT_RULE, 217 | a_conf->levels, 218 | a_conf->default_format, 219 | a_conf->formats, 220 | a_conf->file_perms, 221 | a_conf->fsync_period, 222 | &(a_conf->time_cache_count)); 223 | if (!default_rule) { 224 | zc_error("zlog_rule_new fail"); 225 | return -1; 226 | } 227 | 228 | /* add default rule */ 229 | if (zc_arraylist_add(a_conf->rules, default_rule)) { 230 | zlog_rule_del(default_rule); 231 | zc_error("zc_arraylist_add fail"); 232 | return -1; 233 | } 234 | 235 | return 0; 236 | } 237 | /*******************************************************************************/ 238 | static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section); 239 | 240 | static int zlog_conf_build_with_file(zlog_conf_t * a_conf) 241 | { 242 | int rc = 0; 243 | struct zlog_stat a_stat; 244 | struct tm local_time; 245 | FILE *fp = NULL; 246 | 247 | char line[MAXLEN_CFG_LINE + 1]; 248 | size_t line_len; 249 | char *pline = NULL; 250 | char *p = NULL; 251 | int line_no = 0; 252 | int i = 0; 253 | int in_quotation = 0; 254 | 255 | int section = 0; 256 | /* [global:1] [levels:2] [formats:3] [rules:4] */ 257 | 258 | if (lstat(a_conf->file, &a_stat)) { 259 | zc_error("lstat conf file[%s] fail, errno[%d]", a_conf->file, 260 | errno); 261 | return -1; 262 | } 263 | localtime_r(&(a_stat.st_mtime), &local_time); 264 | strftime(a_conf->mtime, sizeof(a_conf->mtime), "%F %T", &local_time); 265 | 266 | if ((fp = fopen(a_conf->file, "r")) == NULL) { 267 | zc_error("open configure file[%s] fail", a_conf->file); 268 | return -1; 269 | } 270 | 271 | /* Now process the file. 272 | */ 273 | pline = line; 274 | memset(&line, 0x00, sizeof(line)); 275 | while (fgets((char *)pline, sizeof(line) - (pline - line), fp) != NULL) { 276 | ++line_no; 277 | line_len = strlen(pline); 278 | if (0 == line_len) { 279 | continue; 280 | } 281 | 282 | if (pline[line_len - 1] == '\n') { 283 | pline[line_len - 1] = '\0'; 284 | } 285 | 286 | /* check for end-of-section, comments, strip off trailing 287 | * spaces and newline character. 288 | */ 289 | p = pline; 290 | while (*p && isspace((int)*p)) 291 | ++p; 292 | if (*p == '\0' || *p == '#') 293 | continue; 294 | 295 | for (i = 0; p[i] != '\0'; ++i) { 296 | pline[i] = p[i]; 297 | } 298 | pline[i] = '\0'; 299 | 300 | for (p = pline + strlen(pline) - 1; isspace((int)*p); --p) 301 | /*EMPTY*/; 302 | 303 | if (*p == '\\') { 304 | if ((p - line) > MAXLEN_CFG_LINE - 30) { 305 | /* Oops the buffer is full - what now? */ 306 | pline = line; 307 | } else { 308 | for (p--; isspace((int)*p); --p) 309 | /*EMPTY*/; 310 | p++; 311 | *p = 0; 312 | pline = p; 313 | continue; 314 | } 315 | } else 316 | pline = line; 317 | 318 | *++p = '\0'; 319 | 320 | /* clean the tail comments start from # and not in quotation */ 321 | in_quotation = 0; 322 | for (p = line; *p != '\0'; p++) { 323 | if (*p == '"') { 324 | in_quotation ^= 1; 325 | continue; 326 | } 327 | 328 | if (*p == '#' && !in_quotation) { 329 | *p = '\0'; 330 | break; 331 | } 332 | } 333 | 334 | /* we now have the complete line, 335 | * and are positioned at the first non-whitespace 336 | * character. So let's process it 337 | */ 338 | rc = zlog_conf_parse_line(a_conf, line, §ion); 339 | if (rc < 0) { 340 | zc_error("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no); 341 | zc_error("line[%s]", line); 342 | goto exit; 343 | } else if (rc > 0) { 344 | zc_warn("parse configure file[%s]line_no[%ld] fail", a_conf->file, line_no); 345 | zc_warn("line[%s]", line); 346 | zc_warn("as strict init is set to false, ignore and go on"); 347 | rc = 0; 348 | continue; 349 | } 350 | } 351 | 352 | exit: 353 | fclose(fp); 354 | return rc; 355 | } 356 | /**********************************************************************/ 357 | static int zlog_conf_build_with_in_memory(zlog_conf_t * a_conf) 358 | { 359 | int rc = 0; 360 | char line[MAXLEN_CFG_LINE + 1]; 361 | char *pline = NULL; 362 | int section = 0; 363 | pline = line; 364 | memset(&line, 0x00, sizeof(line)); 365 | pline = strtok((char *)a_conf->cfg_ptr, "\n"); 366 | 367 | while (pline != NULL) { 368 | rc = zlog_conf_parse_line(a_conf, pline, §ion); 369 | if (rc < 0) { 370 | zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline); 371 | break; 372 | } else if (rc > 0) { 373 | zc_error("parse in-memory configurations[%s] line [%s] fail", a_conf->cfg_ptr, pline); 374 | zc_warn("as strict init is set to false, ignore and go on"); 375 | rc = 0; 376 | continue; 377 | } 378 | pline = strtok(NULL, "\n"); 379 | } 380 | return rc; 381 | } 382 | /* section [global:1] [levels:2] [formats:3] [rules:4] */ 383 | static int zlog_conf_parse_line(zlog_conf_t * a_conf, char *line, int *section) 384 | { 385 | int nscan; 386 | int nread; 387 | char name[MAXLEN_CFG_LINE + 1]; 388 | char word_1[MAXLEN_CFG_LINE + 1]; 389 | char word_2[MAXLEN_CFG_LINE + 1]; 390 | char word_3[MAXLEN_CFG_LINE + 1]; 391 | char value[MAXLEN_CFG_LINE + 1]; 392 | zlog_format_t *a_format = NULL; 393 | zlog_rule_t *a_rule = NULL; 394 | 395 | if (strlen(line) > MAXLEN_CFG_LINE) { 396 | zc_error ("line_len[%ld] > MAXLEN_CFG_LINE[%ld], may cause overflow", 397 | strlen(line), MAXLEN_CFG_LINE); 398 | return -1; 399 | } 400 | 401 | /* get and set outer section flag, so it is a closure? haha */ 402 | if (line[0] == '[') { 403 | int last_section = *section; 404 | nscan = sscanf(line, "[ %[^] \t]", name); 405 | if (STRCMP(name, ==, "global")) { 406 | *section = 1; 407 | } else if (STRCMP(name, ==, "levels")) { 408 | *section = 2; 409 | } else if (STRCMP(name, ==, "formats")) { 410 | *section = 3; 411 | } else if (STRCMP(name, ==, "rules")) { 412 | *section = 4; 413 | } else { 414 | zc_error("wrong section name[%s]", name); 415 | return -1; 416 | } 417 | /* check the sequence of section, must increase */ 418 | if (last_section >= *section) { 419 | zc_error("wrong sequence of section, must follow global->levels->formats->rules"); 420 | return -1; 421 | } 422 | 423 | if (*section == 4) { 424 | if (a_conf->reload_conf_period != 0 425 | && a_conf->fsync_period >= a_conf->reload_conf_period) { 426 | /* as all rule will be rebuilt when conf is reload, 427 | * so fsync_period > reload_conf_period will never 428 | * cause rule to fsync it's file. 429 | * fsync_period will be meaningless and down speed, 430 | * so make it zero. 431 | */ 432 | zc_warn("fsync_period[%ld] >= reload_conf_period[%ld]," 433 | "set fsync_period to zero"); 434 | a_conf->fsync_period = 0; 435 | } 436 | 437 | /* now build rotater and default_format 438 | * from the unchanging global setting, 439 | * for zlog_rule_new() */ 440 | a_conf->rotater = zlog_rotater_new(a_conf->rotate_lock_file); 441 | if (!a_conf->rotater) { 442 | zc_error("zlog_rotater_new fail"); 443 | return -1; 444 | } 445 | 446 | a_conf->default_format = zlog_format_new(a_conf->default_format_line, 447 | &(a_conf->time_cache_count)); 448 | if (!a_conf->default_format) { 449 | zc_error("zlog_format_new fail"); 450 | return -1; 451 | } 452 | } 453 | return 0; 454 | } 455 | 456 | /* process detail */ 457 | switch (*section) { 458 | case 1: 459 | memset(name, 0x00, sizeof(name)); 460 | memset(value, 0x00, sizeof(value)); 461 | nscan = sscanf(line, " %[^=]= %s ", name, value); 462 | if (nscan != 2) { 463 | zc_error("sscanf [%s] fail, name or value is null", line); 464 | return -1; 465 | } 466 | 467 | memset(word_1, 0x00, sizeof(word_1)); 468 | memset(word_2, 0x00, sizeof(word_2)); 469 | memset(word_3, 0x00, sizeof(word_3)); 470 | nread = 0; 471 | nscan = sscanf(name, "%s%n%s%s", word_1, &nread, word_2, word_3); 472 | 473 | if (STRCMP(word_1, ==, "strict") && STRCMP(word_2, ==, "init")) { 474 | /* if environment variable ZLOG_STRICT_INIT is set 475 | * then always make it strict 476 | */ 477 | if (STRICMP(value, ==, "false") && !getenv("ZLOG_STRICT_INIT")) { 478 | a_conf->strict_init = 0; 479 | } else { 480 | a_conf->strict_init = 1; 481 | } 482 | } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "min")) { 483 | a_conf->buf_size_min = zc_parse_byte_size(value); 484 | } else if (STRCMP(word_1, ==, "buffer") && STRCMP(word_2, ==, "max")) { 485 | a_conf->buf_size_max = zc_parse_byte_size(value); 486 | } else if (STRCMP(word_1, ==, "file") && STRCMP(word_2, ==, "perms")) { 487 | sscanf(value, "%o", &(a_conf->file_perms)); 488 | } else if (STRCMP(word_1, ==, "rotate") && 489 | STRCMP(word_2, ==, "lock") && STRCMP(word_3, ==, "file")) { 490 | /* may overwrite the inner default value, or last value */ 491 | if (STRCMP(value, ==, "self")) { 492 | strcpy(a_conf->rotate_lock_file, a_conf->file); 493 | } else { 494 | strcpy(a_conf->rotate_lock_file, value); 495 | } 496 | } else if (STRCMP(word_1, ==, "default") && STRCMP(word_2, ==, "format")) { 497 | /* so the input now is [format = "xxyy"], fit format's style */ 498 | strcpy(a_conf->default_format_line, line + nread); 499 | } else if (STRCMP(word_1, ==, "reload") && 500 | STRCMP(word_2, ==, "conf") && STRCMP(word_3, ==, "period")) { 501 | a_conf->reload_conf_period = zc_parse_byte_size(value); 502 | } else if (STRCMP(word_1, ==, "fsync") && STRCMP(word_2, ==, "period")) { 503 | a_conf->fsync_period = zc_parse_byte_size(value); 504 | } else { 505 | zc_error("name[%s] is not any one of global options", name); 506 | if (a_conf->strict_init) return -1; 507 | } 508 | break; 509 | case 2: 510 | if (zlog_level_list_set(a_conf->levels, line)) { 511 | zc_error("zlog_level_list_set fail"); 512 | if (a_conf->strict_init) return -1; 513 | } 514 | break; 515 | case 3: 516 | a_format = zlog_format_new(line, &(a_conf->time_cache_count)); 517 | if (!a_format) { 518 | zc_error("zlog_format_new fail [%s]", line); 519 | if (a_conf->strict_init) return -1; 520 | else break; 521 | } 522 | if (zc_arraylist_add(a_conf->formats, a_format)) { 523 | zlog_format_del(a_format); 524 | zc_error("zc_arraylist_add fail"); 525 | return -1; 526 | } 527 | break; 528 | case 4: 529 | a_rule = zlog_rule_new(line, 530 | a_conf->levels, 531 | a_conf->default_format, 532 | a_conf->formats, 533 | a_conf->file_perms, 534 | a_conf->fsync_period, 535 | &(a_conf->time_cache_count)); 536 | 537 | if (!a_rule) { 538 | zc_error("zlog_rule_new fail [%s]", line); 539 | if (a_conf->strict_init) return -1; 540 | else break; 541 | } 542 | if (zc_arraylist_add(a_conf->rules, a_rule)) { 543 | zlog_rule_del(a_rule); 544 | zc_error("zc_arraylist_add fail"); 545 | return -1; 546 | } 547 | break; 548 | default: 549 | zc_error("not in any section"); 550 | return -1; 551 | } 552 | 553 | return 0; 554 | } 555 | /*******************************************************************************/ 556 | --------------------------------------------------------------------------------