#LyX 2.3 created this file. For more info see http://www.lyx.org/ \lyxformat 544 \begin_document \begin_header \save_transient_properties true \origin unavailable \textclass extbook \use_default_options true \begin_modules theorems-ams eqs-within-sections figs-within-sections \end_modules \maintain_unincluded_children false \language english \language_package default \inputencoding auto \fontencoding global \font_roman "default" "default" \font_sans "default" "default" \font_typewriter "default" "default" \font_math "auto" "auto" \font_default_family default \use_non_tex_fonts false \font_sc false \font_osf false \font_sf_scale 100 100 \font_tt_scale 100 100 \use_microtype false \use_dash_ligatures true \graphics default \default_output_format default \output_sync 0 \bibtex_command default \index_command default \paperfontsize 12 \spacing single \use_hyperref true \pdf_title "zlog Users Guide EN" \pdf_author "Hardy Simpson" \pdf_bookmarks true \pdf_bookmarksnumbered true \pdf_bookmarksopen true \pdf_bookmarksopenlevel 1 \pdf_breaklinks true \pdf_pdfborder true \pdf_colorlinks true \pdf_backref false \pdf_pdfusetitle true \papersize default \use_geometry true \use_package amsmath 1 \use_package amssymb 1 \use_package cancel 1 \use_package esint 1 \use_package mathdots 1 \use_package mathtools 1 \use_package mhchem 1 \use_package stackrel 1 \use_package stmaryrd 1 \use_package undertilde 1 \cite_engine basic \cite_engine_type default \biblio_style plain \use_bibtopic false \use_indices false \paperorientation portrait \suppress_date false \justification true \use_refstyle 0 \use_minted 0 \index 索引 \shortcut idx \color #008000 \end_index \secnumdepth 3 \tocdepth 3 \paragraph_separation indent \paragraph_indentation default \is_math_indent 0 \math_numbering_side default \quotes_style english \dynamic_quotes 0 \papercolumns 1 \papersides 1 \paperpagestyle default \tracking_changes false \output_changes false \html_math_output 0 \html_css_as_file 0 \html_be_strict false \end_header \begin_body \begin_layout Title zlog \begin_inset Foot status collapsed \begin_layout Plain Layout A single spark can start a prairie fire – Mao Zedong \end_layout \end_inset User's Guide \end_layout \begin_layout Author Hardy Simpson \begin_inset Foot status collapsed \begin_layout Plain Layout This Guide is for zlog v1.2.* \end_layout \end_inset \begin_inset Foot status collapsed \begin_layout Plain Layout If you have comments or error corrections, post \begin_inset CommandInset href LatexCommand href name "a issue" target "https://github.com/HardySimpson/zlog/issues/new" literal "false" \end_inset on github, or write email to \begin_inset CommandInset href LatexCommand href name "HardySimpson1984@gmail.com" target "HardySimpson1984@gmail.com" type "mailto:" literal "false" \end_inset \end_layout \end_inset \end_layout \begin_layout Standard \begin_inset CommandInset toc LatexCommand tableofcontents \end_inset \end_layout \begin_layout Chapter What is zlog? \end_layout \begin_layout Standard zlog is a reliable, high-performance, thread safe, flexible, clear-model, pure C logging library. \end_layout \begin_layout Standard Actually, in the C world there was NO good logging library for applications like logback in java or log4cxx in c++. printf can work, but can not be redirected easily nor be reformatted. syslog is slow and is designed for system use. \end_layout \begin_layout Standard So I wrote zlog. \end_layout \begin_layout Standard It is faster, safer and more powerful than log4c. So it can be widely used. \end_layout \begin_layout Standard zlog has these features: \end_layout \begin_layout Itemize syslog model, better than log4j model \end_layout \begin_layout Itemize log format customization \end_layout \begin_layout Itemize multiple output, include static file path, dynamic file path, stdout, stderr, syslog, user-defined ouput \end_layout \begin_layout Itemize runtime with manual or automatic refresh of configuration (done safely) \end_layout \begin_layout Itemize high-performance, 250'000 logs/second on my laptop, about 1000 times faster than syslog(3) with rsyslogd \end_layout \begin_layout Itemize user-defined log level \end_layout \begin_layout Itemize safely rotate log file under multiple-process or multiple-thread conditions \end_layout \begin_layout Itemize accurate to microseconds \end_layout \begin_layout Itemize dzlog, a default category log API for easy use \end_layout \begin_layout Itemize MDC, a log4j style key-value map \end_layout \begin_layout Itemize self debuggable, can output zlog's self debug and error log at runtime \end_layout \begin_layout Itemize Does not depend on any other 3rd party library, just base on POSIX system (including pthread) and a C99 compliant vsnprintf. \end_layout \begin_layout Standard Links: \end_layout \begin_layout Standard Homepage: \begin_inset CommandInset href LatexCommand href name "http://hardysimpson.github.com/zlog" target "http://hardysimpson.github.com/zlog" literal "false" \end_inset \end_layout \begin_layout Standard Downloads: \begin_inset CommandInset href LatexCommand href target "https://github.com/HardySimpson/zlog/releases" literal "false" \end_inset \end_layout \begin_layout Standard Author's Email: \begin_inset CommandInset href LatexCommand href name "HardySimpson1984@gmail.com" target "HardySimpson1984@gmail.com" type "mailto:" literal "false" \end_inset \end_layout \begin_layout Section Compatibility Notes \end_layout \begin_layout Enumerate zlog is based on POSIX-compatible systems. I have just GNU/linux and AIX environments to compile, test and run zlog. Still, I think zlog will work well on FreeBSD, NetBSD, OpenBSD, OpenSolaris, Mac OS X etc. Test runs of zlog on any system are welcome. \end_layout \begin_layout Enumerate zlog uses a feature of C99 compliant vsnprintf. That is, if the buffer size of destination is not long enough, vsnprintf will return the number of characters (not including the trailing ' \backslash 0') which would have been written to the final string if enough space had been available. If the vsnprintf on your system does not work like that, zlog can not know the right buffer size when a single log is longer than the buffer. Fortunately, glibc 2.1, libc on AIX, and libc on freebsd work correctly, while glibc 2.0 does not. In this case, user should crack zlog himself with a C99 compliant vsnprintf. I suggest \begin_inset CommandInset href LatexCommand href name "ctrio" target "http://sourceforge.net/projects/ctrio/" literal "false" \end_inset , or \begin_inset CommandInset href LatexCommand href name "C99-snprintf" target "http://www.jhweiss.de/software/snprintf.html" literal "false" \end_inset . The file buf.c should be cracked, good luck! \end_layout \begin_layout Enumerate Some people offer versions of zlog for other platforms. Thanks! \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard auto tools version: \begin_inset CommandInset href LatexCommand href target "https://github.com/bmanojlovic/zlog" literal "false" \end_inset \end_layout \begin_layout Standard cmake verion: \begin_inset CommandInset href LatexCommand href target "https://github.com/lisongmin/zlog" literal "false" \end_inset \end_layout \begin_layout Standard windows version: \begin_inset CommandInset href LatexCommand href target "https://github.com/lopsd07/WinZlog" literal "false" \end_inset \end_layout \end_deeper \begin_layout Section zlog 1.2 Release Notes \end_layout \begin_layout Enumerate zlog 1.2 provides these features: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Enumerate support for pipeline. Now zlog can send ouput log through programs like cronolog \end_layout \begin_layout Enumerate Full rotation support, see \begin_inset CommandInset ref LatexCommand ref reference "sec:Rotation" \end_inset \end_layout \begin_layout Enumerate Other code compatible details, bug fixes. \end_layout \end_deeper \begin_layout Enumerate zlog 1.2 is binary compatible with zlog 1.0. The differences are: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Enumerate All zlog macros like ZLOG_INFO are shifted to lowercase versions, zlog_info. This big change is because I think it is easier for people to type. If you are using a previous version of zlog, please use a script to substitute all macros, and re-compile your program. Here is an example: \end_layout \begin_layout LyX-Code sed -i -e 's/ \backslash b \backslash w*ZLOG \backslash w* \backslash b/ \backslash L& \backslash E/g' aa.c \end_layout \begin_layout Enumerate Auto tools compile is abandoned. Auto tools is ugly so I dropped it. A simple makefile is in use, which requires gcc and gnu make. If this makefile does not work in your environment, you will need to write a suitable makefile for yourself. It should be quite easy for a geek. \end_layout \end_deeper \begin_layout Chapter What zlog is not \end_layout \begin_layout Standard The goal of zlog is to be a simple, fast log library for applications. It does not support output like sending the log to another machine through the net or saving it to database. It will not parse content of log and filter them. \end_layout \begin_layout Standard The reason is obvious: the library is called by an application, so all time taken by the log library is part of the application's time. And database inserting or log content parsing takes a long time. These will slow down the application. These operation should be done in a different process or on a different machine. \end_layout \begin_layout Standard If you want all these features, I recommend rsyslog, zLogFabric, Logstash. These have independent processes to receive logs from another process or machine, and to parse and store logs. These functions are separated from the user application. \end_layout \begin_layout Standard Now \begin_inset CommandInset ref LatexCommand ref reference "sec:User-defined-Output" \end_inset is supported by zlog. Just one output function need to be implemented: to transfer the log to the other process or machine. The work of category matching and log generating is left with the zlog library. \end_layout \begin_layout Standard One possibility is to write a zlog-redis client. It send logs to redis on local or remote machines by user defined output. Then other processes can read logs from redis and write to disk. What do you think about this idea? I will be happy to discuss it with you. \end_layout \begin_layout Chapter Hello World \end_layout \begin_layout Section Build and Installation zlog \end_layout \begin_layout Standard Download: \begin_inset CommandInset href LatexCommand href target "https://github.com/HardySimpson/zlog/archive/latest-stable.tar.gz" literal "false" \end_inset \end_layout \begin_layout LyX-Code $ tar -zxvf zlog-latest-stable.tar.gz \end_layout \begin_layout LyX-Code $ cd zlog-latest-stable/ \end_layout \begin_layout LyX-Code $ make \end_layout \begin_layout LyX-Code $ sudo make install \end_layout \begin_layout LyX-Code or \end_layout \begin_layout LyX-Code $ sudo make PREFIX=/usr/local/ install \end_layout \begin_layout Standard PREFIX indicates where zlog is installed. After installation, change system settings to make sure your program can find the zlog library \end_layout \begin_layout LyX-Code $ sudo vi /etc/ld.so.conf \end_layout \begin_layout LyX-Code /usr/local/lib \end_layout \begin_layout LyX-Code $ sudo ldconfig \end_layout \begin_layout Standard Before running a real program, make sure libzlog.so is in the directory where the system's dynamic lib loader can find it. The commands mentioned above are for linux. Other systems will need a similar set of actions. \end_layout \begin_layout Itemize Beside the normal make, these are also available: \end_layout \begin_layout LyX-Code $ make 32bit # 32bit version on 64bit machine, libc6-dev-i386 is needed \end_layout \begin_layout LyX-Code $ make noopt # without gcc optimization \end_layout \begin_layout LyX-Code $ make doc # lyx and hevea is needed \end_layout \begin_layout LyX-Code $ make test # test code, which is also good example for zlog \end_layout \begin_layout Itemize makefile of zlog is written in gnu make style. So if your platform is not linux, install a gnu make and gcc before trying to build zlog. Another way is to write a makefile in your platform's make style. This should be quite easy as zlog is not complicated. \end_layout \begin_layout Section Call and Link zlog in User's application \end_layout \begin_layout Standard To use zlog, add one line to the source c file or cpp file: \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout Standard zlog needs the pthread library. The link command is: \end_layout \begin_layout LyX-Code $ cc -c -o app.o app.c -I/usr/local/include \end_layout \begin_layout LyX-Code # -I[where zlog.h is put] \end_layout \begin_layout LyX-Code $ cc -o app app.o -L/usr/local/lib -lzlog -lpthread \end_layout \begin_layout LyX-Code # -L[where libzlog.so] \end_layout \begin_layout Section Hello World Example \begin_inset CommandInset label LatexCommand label name "sec:Hello-World-Example" \end_inset \end_layout \begin_layout Standard This example can be found in $(top_builddir)/test/test_hello.c, test_hello.conf \end_layout \begin_layout Enumerate Write a new c source file: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ vi test_hello.c \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code zlog_category_t *c; \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code rc = zlog_init("test_hello.conf"); \end_layout \begin_layout LyX-Code if (rc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code c = zlog_get_category("my_cat"); \end_layout \begin_layout LyX-Code if (!c) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("get cat fail \backslash n"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return -2; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code zlog_info(c, "hello, zlog"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \end_deeper \begin_layout Enumerate Write a configuration file in the same path as test_hello.c: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ vi test_hello.conf \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code simple = "%m%n" \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.DEBUG >stdout; simple \end_layout \end_deeper \begin_layout Enumerate Compile and run it: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ cc -c -o test_hello.o test_hello.c -I/usr/local/include \end_layout \begin_layout LyX-Code $ cc -o test_hello test_hello.o -L/usr/local/lib -lzlog \end_layout \begin_layout LyX-Code $ ./test_hello \end_layout \begin_layout LyX-Code hello, zlog \end_layout \end_deeper \begin_layout Section Simpler Hello World Example \end_layout \begin_layout Standard This example can be found in $(top_builddir)/test/test_default.c, test_default.con f. The source code is \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code rc = dzlog_init("test_default.conf", "my_cat"); \end_layout \begin_layout LyX-Code if (rc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code dzlog_info("hello, zlog"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout Standard The configure file test_default.conf is the same as test_hello.conf, and the output of test_default is the same as that of test_hello. The difference is that test_default uses the dzlog API, which has a default \emph on zlog_category_t \emph default inside and is easier to use. See \begin_inset CommandInset ref LatexCommand ref reference "sec:dzlog-API" \end_inset for more details. \end_layout \begin_layout Chapter Syslog model \end_layout \begin_layout Section Category, Rule and Format \end_layout \begin_layout Standard In zlog, there are 3 important concepts: category, rule and format. \end_layout \begin_layout Standard Category specifies 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. \end_layout \begin_layout Standard Format describes detail log patterns, such as: with or without time stamp, source file, source line. \end_layout \begin_layout Standard Rule consists 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. \end_layout \begin_layout Standard So when this sentence in the source file is executed: \end_layout \begin_layout LyX-Code zlog_category_t *c; \end_layout \begin_layout LyX-Code c = zlog_get_category("my_cat"); \end_layout \begin_layout LyX-Code zlog_info(c, "hello, zlog"); \end_layout \begin_layout Standard zlog library uses the category name "my_cat" to match one rule in the configurat ion file. That is \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.DEBUG >stdout; simple \end_layout \begin_layout Standard Then the library will check if level is correct to decide whether the log will be output or not. As INFO>=DEBUG the log will be output, and as the rule says, it will be sent to stdout (standard output) in the format of simple, which is described as \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code simple = "%m%n" \end_layout \begin_layout Standard Lastly, zlog will show the zlog_info() content on the screen \end_layout \begin_layout LyX-Code hello, zlog \end_layout \begin_layout Standard That's the whole story. The only thing a user need to do is to write the messages. Where the log will be output, or in which format, is done by zlog library. \end_layout \begin_layout Section Differences between syslog model and log4j model \end_layout \begin_layout Standard Does zLog have anything to do with syslog? Until now, the model is more like log4j. As in log4j, there are concepts of logger, appender and layout. The difference is that in log4j, each logger in source code must correspond to one logger in the configuration file and has just one definite level. One-to-one relationship is the only choice for log4j, log4cxx, log4cpp, log4cplus log4net and etc... \end_layout \begin_layout Standard But the log4j model is NOT flexible, they invent filters to make up for it, and that make things more worse. So let's get back to syslog model, which has an excellent design. \end_layout \begin_layout Standard Continuing our example from the last section, if the zlog configuration file has 2 rules: \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.DEBUG >stdout; simple \end_layout \begin_layout LyX-Code my_cat.INFO >stdout; \end_layout \begin_layout Standard Then they will generate 2 log outputs to stdout: \end_layout \begin_layout LyX-Code hello, zlog \end_layout \begin_layout LyX-Code 2012-05-29 10:41:36 INFO [11288:test_hello.c:41] hello, zlog \end_layout \begin_layout Standard You see that one category in the source code corresponds to two rules in the configuration file. Maybe log4j's user will say, "That's good, but 2 appender for one logger will do the same thing". So, let's see the next example of configure file: \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.WARN "/var/log/aa.log" \end_layout \begin_layout LyX-Code my_cat.DEBUG "/var/log/bb.log" \end_layout \begin_layout Standard And the source code is: \end_layout \begin_layout LyX-Code zlog_info(c, "info, zlog"); \end_layout \begin_layout LyX-Code zlog_debug(c, "debug, zlog"); \end_layout \begin_layout Standard Then, in aa.log, there is just one log \end_layout \begin_layout LyX-Code 2012-05-29 10:41:36 INFO [11288:test_hello.c:41] info, zlog \end_layout \begin_layout Standard But in bb.log, there will be two \end_layout \begin_layout LyX-Code 2012-05-29 10:41:36 INFO [11288:test_hello.c:41] info, zlog \end_layout \begin_layout LyX-Code 2012-05-29 10:41:36 DEBUG [11288:test_hello.c:42] debug, zlog \end_layout \begin_layout Standard From this example, you see the difference. Log4j can not do it easily. In zlog, one category may correspond to mutiple rules, and rules can have different level, output, and format combinations. The user has an easy, clear way to filter and multi-ouput all logs on demand. \end_layout \begin_layout Section Expand syslog model \end_layout \begin_layout Standard You can see that category in zlog is more like facility in syslog. Unfortunately, facility in sylog is an int, and the value of facility must be chosen from a limited system-defined range. zlog does better, making it a string variable. \end_layout \begin_layout Standard In syslog, there is a special wildcard "*", which matches all facilities. It does the same thing in zlog. "*" matches all categories. That is a convenient way to make all errors generated by multiple components in your system redirect to one log file. Just write in the configuration file like this: \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code *.error "/var/log/error.log" \end_layout \begin_layout Standard A unique feature of zlog is sub-category matching. If your source code has: \end_layout \begin_layout LyX-Code c = zlog_get_category("my_cat"); \end_layout \begin_layout Standard And the configuration file has rules : \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.* "/var/log/my_cat.log" \end_layout \begin_layout LyX-Code my_.NOTICE "/var/log/my.log" \end_layout \begin_layout Standard These 2 rules match category "c" with the name "my_cat". The wildcard "_" is the way to represent a super category. "my_" is a super category for "my_cat" and "my_dog". There is also another wildcard "!". See \begin_inset CommandInset ref LatexCommand ref reference "subsec:Category-Matching" \end_inset for more detail. \end_layout \begin_layout Chapter Configure File \end_layout \begin_layout Standard Most actions of zlog library are dependent upon the configuration file: where to output the log, how to rotate the log files, how to format the output, etc. The configuration file uses a domain specific language to control the library actions. Here is an example of zlog.conf: \end_layout \begin_layout LyX-Code # comments \end_layout \begin_layout LyX-Code [global] \end_layout \begin_layout LyX-Code strict init = true \end_layout \begin_layout LyX-Code reload conf period = 1M \end_layout \begin_layout LyX-Code buffer min = 1024 \end_layout \begin_layout LyX-Code buffer max = 2MB \end_layout \begin_layout LyX-Code rotate lock file = /tmp/zlog.lock \end_layout \begin_layout LyX-Code default format = "%d.%ms %-6V (%c:%F:%L) - %m%n" \end_layout \begin_layout LyX-Code file perms = 600 \end_layout \begin_layout LyX-Code fsync period = 1K \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code [levels] \end_layout \begin_layout LyX-Code TRACE = 10 \end_layout \begin_layout LyX-Code CRIT = 130, LOG_CRIT \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code simple = "%m%n" \end_layout \begin_layout LyX-Code normal = "%d(%F %T) %m%n" \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code default.* >stdout; simple \end_layout \begin_layout LyX-Code *.* "%12.2E(HOME)/log/%c.log", 1MB*12; simple \end_layout \begin_layout LyX-Code my_.INFO >stderr; \end_layout \begin_layout LyX-Code my_cat.!ERROR "/var/log/aa.log" \end_layout \begin_layout LyX-Code my_dog.=DEBUG >syslog, LOG_LOCAL0; simple \end_layout \begin_layout LyX-Code my_mice.* $user_define; \end_layout \begin_layout Standard [] means a section's beginning, and the order of sections is fixed, using the sequence global-levels-formats-rules. \end_layout \begin_layout Standard Note on units: when memory size or large number is needed, it is possible to specify it in the usual form of 1k 5GB 4M and so forth: \end_layout \begin_layout LyX-Code # 1k => 1000 bytes \end_layout \begin_layout LyX-Code # 1kb => 1024 bytes \end_layout \begin_layout LyX-Code # 1m => 1000000 bytes \end_layout \begin_layout LyX-Code # 1mb => 1024*1024 bytes \end_layout \begin_layout LyX-Code # 1g => 1000000000 bytes \end_layout \begin_layout LyX-Code # 1gb => 1024*1024*1024 byte \end_layout \begin_layout Standard units are case insensitive so 1GB 1Gb 1gB are all the same. \end_layout \begin_layout Section Global \end_layout \begin_layout Standard Global section begins with [global]. This section can be omitted.The syntax is \end_layout \begin_layout LyX-Code (key) = (value) \end_layout \begin_layout Itemize strict init \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard If "strict init = true \begin_inset Quotes erd \end_inset , zlog_init() will check syntax of all formats and rules strictly, and any error will cause zlog_init() to fail and return -1. When "strict init = false \begin_inset Quotes erd \end_inset , zlog_init() will ignore syntax errors for formats and rules. The default is true. \end_layout \end_deeper \begin_layout Itemize reload conf period \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard This parameter causes the zlog library to reload the configuration file automatically after a period, which is measured by number of log times per process. When the number reaches the value, it calls zlog_reload() internally. The number is reset to zero at the last zlog_reload() or zlog_init(). As zlog_reload() is atomic, if zlog_reload() fails, zlog still runs with the current configuration. So reloading automatically the configuration is safe. The default is 0, which means never reload automatically. \end_layout \end_deeper \begin_layout Itemize buffer min \end_layout \begin_layout Itemize buffer max \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard zlog allocates a log buffer in each thread. "buffer min" indicates size of buffer malloc'ed at init time. While logging, if one single log's content is longer than buffer size now, zlog will expand buffer automatically until "buffer max". Then, if the size is still longer than "buffer max", the log content will be truncated. If "buffer max" is 0, it means buffer size is unlimited, and each time zlog will expand buffer by twice its size, until the process uses all available memory. The value of these 2 parameters can appended with unit KB, MB or GB suffix, where 1024 equals 1KB. As default, "buffer min" is 1K and "buffer max" is 2MB. \end_layout \end_deeper \begin_layout Itemize rotate lock file \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard This specifies a lock file for rotating a log safely in multi-process situations. zlog will open the file at zlog_init() with the permission of read-write. The pseudo-code for rotating a log file is: \end_layout \begin_layout LyX-Code write(log_file, a_log) \end_layout \begin_layout LyX-Code if (log_file > 1M) \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code if (pthread_mutex_lock succ && fcntl_lock(lock_file) succ) \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code if (log_file > 1M) rotate(log_file); \end_layout \begin_layout LyX-Code fcntl_unlock(lock_file); \end_layout \begin_layout LyX-Code pthread_mutex_unlock; \end_layout \end_deeper \end_deeper \begin_layout Standard mutex_lock is for multi-thread and fcntl_lock is for multi-process. fcntl_lock is the POSIX advisory record locking. See man 3 fcntl for details. The lock is system-wide, and when a process dies unexpectedly, the operating system releases all locks owned by the process. That's why I chose fcntl lock for rotating log safely. The process needs read-write permisson for lock_file to lock it. \end_layout \begin_layout Standard By default, rotate lock file = self. This way, zlog does not create any lock file and sets the configuration file as the lock file. As fcntl is advisory, it does not really forbid programmers to change and store the configuration file. Generally speaking, one log file will not be rotated by processes run by different operating system users, so using the configuration file as lock file is safe. \end_layout \begin_layout Standard If you choose another path as lock file, for example, /tmp/zlog.lock, zlog will create it at zlog_init(). Make sure your program has permission to create and read-write the file. If processes run by different operating system users need to write and rotate the same log file, make sure that each program has permission to create and read-write the same lock file. \end_layout \end_deeper \begin_layout Itemize default format \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard This parameter is used by rules without format specified. The default is \end_layout \begin_layout LyX-Code "%d %V [%p:%F:%L] %m%n" \end_layout \begin_layout Standard It will yield output like this: \end_layout \begin_layout LyX-Code 2012-02-14 17:03:12 INFO [3758:test_hello.c:39] hello, zlog \end_layout \end_deeper \begin_layout Itemize file perms \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard This specifies all log file permissions when they are created. Note that it is affected by user's umask. The final file permission will be "file perms" & ~umask. The default is 600, which just allows user read and write. \end_layout \end_deeper \begin_layout Itemize fsync period \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard After a number of log times per rule (to file only), zlog will call fsync(3) after write() to tell the Operating System to write data to disk immediately from any internal system buffers. The number is incremented by each rule and will be reset to 0 after zlog_reload (). Note that when the file's path is generated dynamically or is rotated, zlog does not guarantee fsync() touch all files. It just does fsync() against the file descriptors that have have seen write() prior to the boundary time. It offers a balance between speed and data safety. An example: \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 1 10 100000 \end_layout \begin_layout LyX-Code real 0m1.806s \end_layout \begin_layout LyX-Code user 0m3.060s \end_layout \begin_layout LyX-Code sys 0m0.270s \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code $ wc -l press.log \end_layout \begin_layout LyX-Code 1000000 press.log \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 1 10 100000 #fsync period = 1K \end_layout \begin_layout LyX-Code real 0m41.995s \end_layout \begin_layout LyX-Code user 0m7.920s \end_layout \begin_layout LyX-Code sys 0m0.990s \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 1 10 100000 #fsync period = 10K \end_layout \begin_layout LyX-Code real 0m6.856s \end_layout \begin_layout LyX-Code user 0m4.360s \end_layout \begin_layout LyX-Code sys 0m0.550s \end_layout \begin_layout Standard If you want extreme safety but do not care about speed, use synchronous file I/O, see \begin_inset CommandInset ref LatexCommand ref reference "ite:synchronous-I/O-file" \end_inset .The defualt is 0, which means let the operating system flush the output buffer when it wants. \end_layout \end_deeper \begin_layout Section Levels \end_layout \begin_layout Standard This section begins with [levels] and allows the user to define application levels. You should match these values with user-defined macros in the source file. This section can be omitted. \end_layout \begin_layout Standard The syntax is \end_layout \begin_layout LyX-Code (level string) = (level int), (syslog level, optional) \end_layout \begin_layout Standard level int should in [1,253], higher numbers mean more important. syslog level is optional, if not set, use LOG_DEBUG \end_layout \begin_layout Standard see \begin_inset CommandInset ref LatexCommand ref reference "sec:User-defined-Level" \end_inset for more details. \end_layout \begin_layout Section Formats \end_layout \begin_layout Standard This section begins with [formats], where the user can define preferred log patterns. The syntax is \end_layout \begin_layout LyX-Code (name) = "(actual formats)" \end_layout \begin_layout Standard It is easy to understand, (name) will be used in the next section [rules]. The format (name) consists of letters and digits plus underscore "_". The (actual format) should be put in double quotes. It can be built up with conversion patterns, as described below. \end_layout \begin_layout Section Conversion pattern \begin_inset CommandInset label LatexCommand label name "sec:Conversion-pattern" \end_inset \end_layout \begin_layout Standard The conversion pattern is closely related to the conversion pattern of the C printf function. A conversion pattern is composed of literal text and format control expressions called conversion specifiers. \end_layout \begin_layout Standard Conversion pattern is used in both filepath of rule and pattern of format. \end_layout \begin_layout Standard You are free to insert any literal text within the conversion pattern. \end_layout \begin_layout Standard Each conversion specifier starts with a percent sign (%) and is followed by optional format modifiers and a conversion character. The conversion character specifies the type of data, e.g. category, level, date, thread id. The format modifiers control such things as field width, padding, left and right justification. The following is a simple example. \end_layout \begin_layout Standard Let the conversion pattern be \end_layout \begin_layout LyX-Code "%d(%m-%d %T) %-5V [%p:%F:%L] %m%n". \end_layout \begin_layout Standard Then the statement \end_layout \begin_layout LyX-Code zlog_info(c, "hello, zlog"); \end_layout \begin_layout Standard would yield the output \end_layout \begin_layout LyX-Code 02-14 17:17:42 INFO [4935:test_hello.c:39] hello, zlog \end_layout \begin_layout Standard Note that there is no explicit separator between text and conversion specifiers. The pattern parser knows when it has reached the end of a conversion specifier when it reads a conversion character. In the example above the conversion specifier %-5p means the level of the logging event should be left justified to a width of five characters. \end_layout \begin_layout Subsection Conversion Characters \end_layout \begin_layout Standard The recognized conversion characters are \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout conversion char \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout effect \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout example \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the category of the logging event. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa_bb \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %d() \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the date of the logging event. The date conversion specifier may be followed by a date format specifier enclosed between parentheses. For example, %d(%F) or %d(%m-%d %T). If no date format specifier is given then %d(%F %T) format is assumed. The date format specifier permits the same syntax as the strftime(2). see \begin_inset CommandInset ref LatexCommand ref reference "subsec:Time-Character" \end_inset for more detail. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %d(%F) 2011-12-01 \end_layout \begin_layout Plain Layout %d(%m-%d %T) 12-01 17:17:42 \end_layout \begin_layout Plain Layout %d(%T).%ms 17:17:42.035 \end_layout \begin_layout Plain Layout %d 2012-02-14 17:03:12 \end_layout \begin_layout Plain Layout %d() 2012-02-14 17:03:12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %E() \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Value of environment variables \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %E(LOGNAME) simpson \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %ms \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The millisecond, 3-digit integer string \end_layout \begin_layout Plain Layout comes from gettimeofday(2) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 013 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %us \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The microsecond, 6-digit integer string \end_layout \begin_layout Plain Layout comes from gettimeofday(2) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 002323 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %F \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the file name where the logging request was issued. The file name comes from __FILE__ macro. Some compilers supply __FILE__ as the absolute path. Use %f to strip path and keep the file name. Some compilers have an option to control this feature. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout test_hello.c \end_layout \begin_layout Plain Layout or, under some compiler \end_layout \begin_layout Plain Layout /home/zlog/src/test/test_hello.c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %f \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the source file name, the string after the last '/' of $F. It will cause a little performance loss in each log event. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout test_hello.c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %g() \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the date of the logging event in UTC in stead of local time. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %g(%F) 2011-12-01 \end_layout \begin_layout Plain Layout %g(%m-%d %T) 12-01 15:17:42 \end_layout \begin_layout Plain Layout %g(%T.ms) 15:17:42.035 \end_layout \begin_layout Plain Layout %g 2012-02-14 15:03:12 \end_layout \begin_layout Plain Layout %g() 2012-02-14 15:03:12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %H \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the hostname of system, which is from gethostname(2) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout zlog-dev \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %k \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the kernel thread id. On Linux, that's the LWP using syscall(SYS_gettid) and on OSX, pthread_threadid _np. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 2136 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %L \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the line number from where the logging request was issued, which comes from __LINE__ macro \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 135 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %m \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the application supplied message associated with the logging event. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout hello, zlog \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %M \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the MDC (mapped diagnostic context) associated with the thread that generated the logging event. The M conversion character must be followed by the key for the map placed between parenthesis, as in %M(clientNumber) where clientNumber is the key. The value in the MDC corresponding to the key will be output.See \begin_inset CommandInset ref LatexCommand ref reference "sec:MDC" \end_inset for more detail. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %M(clientNumber) 12345 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %n \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Outputs unix newline character, zLog does not support the MS-Windows line separator at this time. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout \backslash n \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %p \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the id of the process that generated the logging event, which comes from getpid(). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 2134 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %U \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the function name where the logging request was issued. It comes from __func__(C99) or __FUNCTION__(gcc) macro, with the support of the compiler. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout main \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %V \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the level of the logging event, uppercase. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout INFO \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %v \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the level of the logging event, lowercase. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout info \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %t \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Used to output the hexadecimal form of the thread id that generated the logging event, which comes from pthread_self(). \end_layout \begin_layout Plain Layout "%x",(unsigned int) pthread_t \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout ba01e700 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %T \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Equivalent to %t, but the long form \end_layout \begin_layout Plain Layout "%lu", (unsigned long) pthread_t \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 140633234859776 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %% \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout the sequence %% outputs a single percent sign. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout % \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %[other char] \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout parsed as a wrong syntax, will cause zlog_init() fail \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout \end_layout \end_inset \end_inset \end_layout \begin_layout Subsection Format Modifier \end_layout \begin_layout Standard By default, the relevant information is output as-is. However, with the aid of format modifiers it is possible to change the minimum field width, the maximum field width, and justification. It will cause a little performance loss in each log event. \end_layout \begin_layout Standard The optional format modifier is placed between the percent sign and the conversion character. \end_layout \begin_layout Standard The first optional format modifier is the left justification flag which is just the minus (-) character. Then comes the optional minimum field width modifier. This is a decimal constant that represents the minimum number of characters to output. If the data item requires fewer characters, it is padded on either the left or the right until the minimum width is reached. The default is to pad on the left (right justify) but you can specify right padding with the left justification flag. The padding character is space. If the data item is larger than the minimum field width, the field is expanded to accommodate the data. The value is never truncated. \end_layout \begin_layout Standard This behavior can be changed using the maximum field width modifier which is designated by a period followed by a decimal constant. If the data item is longer than the maximum field, then the extra characters are removed from the beginning of the data item and not from the end. For example, if the maximum field width is eight and the data item is ten characters long, then the last two characters of the data item are dropped. This behavior equals the printf function in C where truncation is done from the end. \end_layout \begin_layout Standard Below are various format modifier examples for the category conversion specifier. \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout format modifier \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout left justify \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout minimum width \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout maximum width \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout comment \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %20c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout false \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout none \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Left pad with spaces if the category name is less than 20 characters long. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %-20c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout true \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout none \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Right pad with spaces if the category name is less than 20 characters long. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %020c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout false \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout none \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Left pad with 0's if the category name is less than 20 characters long. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %.30c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout NA \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout none \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 30 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Truncate from the end if the category name is longer than 30 characters. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %20.30c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout false \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 30 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Left pad with spaces if the category name is shorter than 20 characters. However, if category name is longer than 30 characters, then truncate from the end. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %-20.30c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout true \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 30 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Right pad with spaces if the category name is shorter than 20 characters. However, if category name is longer than 30 characters, then truncate from the end. \end_layout \end_inset \end_inset \end_layout \begin_layout Subsection Time Character \begin_inset CommandInset label LatexCommand label name "subsec:Time-Character" \end_inset \end_layout \begin_layout Standard Here is the Time Character support by Conversion Character \emph on d. \emph default \end_layout \begin_layout Standard All Character is supported by strftime(3) in library. The Character supported on my linux system are \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout character \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout effect \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout example \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %a \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The abbreviated weekday name according to the current locale. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Wed \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %A \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The full weekday name according to the current locale. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Wednesday \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %b \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The abbreviated month name according to the current locale. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Mar \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %B \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The full month name according to the current locale. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout March \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %c \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The preferred date and time representation for the current locale. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Thu Feb 16 14:16:35 2012 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %C \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The century number (year/100) as a 2-digit integer. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 20 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %d \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The day of the month as a decimal number (range 01 to 31). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 06 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %D \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Equivalent to %m/%d/%y. (for Americans only. Americans should note that in other countries %d/%m/%y is more common. This means that in an international context this format is ambiguous and should not be used.) (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 02/16/12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %e \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 6 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %F \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 2012-02-16 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %G \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The ISO 8601 week-based year (see NOTES) with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead. (TZ) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 2012 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %g \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Like %G, but without century, that is, with a 2-digit year (00-99). (TZ) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %h \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Equivalent to %b. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Feb \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %H \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The hour as a decimal number using a 24-hour clock (range 00 to 23). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 14 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %I \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The hour as a decimal number using a 12-hour clock (range 01 to 12). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 02 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %j \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The day of the year as a decimal number (range 001 to 366). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 047 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %k \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H.) (TZ) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 15 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %l \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I.) (TZ) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 3 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %m \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The month as a decimal number (range 01 to 12). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 02 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %M \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The minute as a decimal number (range 00 to 59). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 11 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %n \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout A newline character. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout \backslash n \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %p \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM". \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout PM \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %P \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. (GNU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout pm \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %r \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 03:11:54 PM \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %R \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The time in 24-hour notation (%H:%M). (SU) For a version including the seconds, see %T below. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 15:11 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %s \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The number of seconds since the Epoch, that is, since 1970-01-01 00:00:00 UTC. (TZ) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 1329376487 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %S \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds.) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 54 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %t \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout A tab character. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %T \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The time in 24-hour notation (%H:%M:%S). (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 15:14:47 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %u \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 4 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %U \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The week number of the current year as a decimal number, range 00 to 53, starting with the first Sun‐ day as the first day of week 01. See also %V and %W. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 07 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %V \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. (SU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 07 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %w \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 4 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %W \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The week number of the current year as a decimal number, range 00 to 53, starting with the first Mon‐ day as the first day of week 01. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 07 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %x \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The preferred date representation for the current locale without the time. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 02/16/12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %X \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The preferred time representation for the current locale without the date. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 15:14:47 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %y \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The year as a decimal number without a century (range 00 to 99). \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 12 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %Y \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The year as a decimal number including the century. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout 2012 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %z \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The time-zone as hour offset from GMT. Required to emit RFC 822-conformant dates (using "%a, %d %b %Y %H:%M:%S %z"). (GNU) \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout +0800 \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %Z \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout The timezone or name or abbreviation. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout CST \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout %% \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout A literal '%' character. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout % \end_layout \end_inset \end_inset \end_layout \begin_layout Standard \end_layout \begin_layout Section Rules \end_layout \begin_layout Standard This section begins with [rules]. It decides how log actions are filtered, formatted and output. This section can be omitted, but there will result in no log output. The syntax is \end_layout \begin_layout LyX-Code (category).(level) (output), (option,optional); (format name, optional) \end_layout \begin_layout Standard When zlog_init() is called, all rules will be read into memory. When zlog_get_category() is called, mutiple rules will be assigned to each category, in the way \begin_inset CommandInset ref LatexCommand ref reference "subsec:Category-Matching" \end_inset describes. When logging is performed, the level between matched rules and INFO will be checked to decide whether this single log will be output through the rule. When zlog_reload() is called, the configuration file will be re-read into memory, including rules. All category rules will be re-calculated. \end_layout \begin_layout Subsection Level Matching \end_layout \begin_layout Standard There are six default levels in zlog, "DEBUG", "INFO", "NOTICE", "WARN", "ERROR" and "FATAL". As in all other log libraries, aa.DEBUG means all logs of level greater than or equal to DEBUG will be output. Still, there are more expressions. Levels in the configuration file are not case sensitive; both capital or lowercase are accepted. \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout example expression \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout meaning \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout * \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout all [source level] \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa.debug \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout [source level]>=debug \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa.=debug \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout [source level]==debug \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa.!debug \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout [source level]!=debug \end_layout \end_inset \end_inset \end_layout \begin_layout Standard The level strings can be defined by the user. See \begin_inset CommandInset ref LatexCommand ref reference "sec:User-defined-Level" \end_inset . \end_layout \begin_layout Subsection Category Matching \begin_inset CommandInset label LatexCommand label name "subsec:Category-Matching" \end_inset \end_layout \begin_layout Standard Category Matching is simple. The name of the category is made up of letters, digits, and/or the underscore "_". \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout summarize \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout category string from configure file \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout category matches \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout category not matches \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout * matches all \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout *.* \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa, aa_bb, aa_cc, xx, yy ... \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout NONE \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout string end with underline matches super-category and sub-categories \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa_.* \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa, aa_bb, aa_cc, aa_bb_cc \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout xx, yy \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout string not ending with underline accurately matches category \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa.* \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa_bb, aa_cc, aa_bb_cc \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout ! matches category that has no rule matched \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout !.* \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout xx \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout aa(as it matches rules above) \end_layout \end_inset \end_inset \end_layout \begin_layout Subsection Output Action \end_layout \begin_layout Standard zlog supports various output methods. The syntax is \end_layout \begin_layout LyX-Code (output action), (output option); (format name, optional) \end_layout \begin_layout Standard \begin_inset Tabular \begin_inset Text \begin_layout Plain Layout output \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout output action \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout output option \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout to standard out \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout >stdout \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout no meaning \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout to standard error \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout >stderr \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout no meaning \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout to syslog \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout >syslog \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout syslog facility, can be: LOG_USER(default), LOG_LOCAL[0-7] \end_layout \begin_layout Plain Layout This is required. \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout pipeline output \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout | cat \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout no meaning \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout to file \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout "(file path)" \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout rotation. see \begin_inset CommandInset ref LatexCommand ref reference "sec:Rotation" \end_inset for detail \end_layout \begin_layout Plain Layout 10MB * 3 ~ "press.#r.log" \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout synchronous I/O file \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout -"(file path)" \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout user-defined output \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout $name \end_layout \end_inset \begin_inset Text \begin_layout Plain Layout "path" (dynamic or static) of record function \end_layout \end_inset \end_inset \end_layout \begin_layout Itemize stdout, stderr, syslog \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard As the above table describes, only the syslog action has a meaningful output option and it must be set. \end_layout \begin_layout Standard Warning: NEVER use >stdout or >stderr when your program is a daemon process. A daemon process always closes its first file descriptor, and when >stdout is set, zlog will output a log like this \end_layout \begin_layout LyX-Code write(STDOUT_FILENO, zlog_buf_str(a_thread->msg_buf), zlog_buf_len(a_thread->msg _buf)) \end_layout \begin_layout Standard What will happen then? The log will be written to the file whose fd is now 1. I have received mail from someone who said zlog as a daemon wrote logs to the configuration file. So remember, daemon processes should not set any rule output to stdout, or stderr. It will generate undefined behavior. If you still want output logs to console when stdout is closed, use "/dev/tty" instead. \end_layout \end_deeper \begin_layout Itemize pipeline output \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* | /usr/bin/cronolog /www/logs/example_%Y%m%d.log ; normal \end_layout \begin_layout Standard This is an example of how zlog pipelines its output to cronolog. The implementation is simple. popen("/usr/bin/cronolog /www/logs/example_%Y%m%d.log","w") is called at zlog_init(), and forward logs will be written to the open descriptor in the "normal" format. Writing through pipeline and cronnolog is faster than dynamic file of zlog, as there is no need to open and close file descripter each time when logs are written to a pipe. \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code *.* "press%d(%Y%m%d).log" \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 1 10 100000 \end_layout \begin_layout LyX-Code real 0m4.240s \end_layout \begin_layout LyX-Code user 0m2.500s \end_layout \begin_layout LyX-Code sys 0m5.460s \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code *.* | /usr/bin/cronolog press%Y%m%d.log \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 1 10 100000 \end_layout \begin_layout LyX-Code real 0m1.911s \end_layout \begin_layout LyX-Code user 0m1.980s \end_layout \begin_layout LyX-Code sys 0m1.470s \end_layout \begin_layout Standard There are some limitations when using pipeline output: \end_layout \begin_layout Itemize POSIX.1-2001 says that write(2)s of less than PIPE_BUF bytes must be atomic, On Linux, PIPE_BUF is 4096 bytes. \end_layout \begin_layout Itemize When a single log is longer than PIPE_BUF, and multiple processes write logs through one pipe (parent calls zlog_init(), and forks many child processes ), log interlacing will occur. \end_layout \begin_layout Itemize Unrelated multiple processes can start multiple cronolog processes and write to the same log file. Even if a single log is not longer than PIPE_BUF, multiple cronologs will cause log interlace. As cronologs read log continuously, it doesn't know where is the split between log entries. \end_layout \begin_layout Standard In summary, pipeline to a single log file: \end_layout \begin_layout Itemize Single process writing, no limitation for length of one log. Multi-threads in one process, atomic writing is already assured by zlog. \end_layout \begin_layout Itemize Related multiple processes, the length of one log should not longer than PIPE_BUF. \end_layout \begin_layout Itemize Unrelated multiple processes, no matter how long a single log is, will cause interlace and is not safe. \end_layout \end_deeper \begin_layout Itemize file \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Itemize file path \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard can be absolute file path or relative file path. It is quoted by double quotation marks. \emph on Conversion pattern \emph default can be used in file path. If the file path is "%E(HOME)/log/out.log" and the program environment $HOME is /home/harry, then the log file will be /home/harry/log/output.log. See \begin_inset CommandInset ref LatexCommand ref reference "sec:Conversion-pattern" \end_inset for more details. \end_layout \begin_layout Standard file of zlog is powerful, for example \end_layout \begin_layout Enumerate output to named pipe(FIFO), which must be created by mkfifo(1) before use \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* "/tmp/pipefile" \end_layout \end_deeper \begin_layout Enumerate output to null, do nothing at all \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* "/dev/null" \end_layout \end_deeper \begin_layout Enumerate output to console, in any case \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* "/dev/tty" \end_layout \end_deeper \begin_layout Enumerate output a log to each tid, in the directory where the process running \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* "%T.log" \end_layout \end_deeper \begin_layout Enumerate output to file with pid name, every day, in $HOME/log directory, rotate log at 1GB, keep 5 log files \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code *.* "%E(HOME)/log/aa.%p.%d(%F).log",1GB * 5 \end_layout \end_deeper \begin_layout Enumerate each category of aa_ super category, output log with category name \end_layout \begin_layout LyX-Code aa_.* "/var/log/%c.log" \end_layout \end_deeper \begin_layout Itemize rotate action \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard controls log file size and count. zlog rotates the log file when the file exceeds this value. For example, let the action be \end_layout \begin_layout LyX-Code "%E(HOME)/log/out.log",1M*3 \end_layout \begin_layout Standard and after out.log is filled to 1M, the rotation is \end_layout \begin_layout LyX-Code out.log -> out.log.1 \end_layout \begin_layout LyX-Code out.log(new create) \end_layout \begin_layout Standard If the new log is full again, the rotation is \end_layout \begin_layout LyX-Code out.log.1 -> out.log.2 \end_layout \begin_layout LyX-Code out.log -> out.log.1 \end_layout \begin_layout LyX-Code out.log(new create) \end_layout \begin_layout Standard The next rotation will delete the oldest log, as *3 means just allows 3 file exist \end_layout \begin_layout LyX-Code unlink(out.log.2) \end_layout \begin_layout LyX-Code out.log.1 -> out.log.2 \end_layout \begin_layout LyX-Code out.log -> out.log.1 \end_layout \begin_layout LyX-Code out.log(new create) \end_layout \begin_layout Standard So the oldest log has the biggest serial number. If *3 is not specified, it means rotation will continue and no old log will be deleted. \end_layout \end_deeper \begin_layout Itemize synchronous I/O file \begin_inset CommandInset label LatexCommand label name "ite:synchronous-I/O-file" \end_inset \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard Putting a minus sign '-' sets the synchronous I/O option. log file is opened with O_SYNC and every single log action will wait until the Operating System writes data to disk. It is painfully slow: \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 100 1000 \end_layout \begin_layout LyX-Code real 0m0.732s \end_layout \begin_layout LyX-Code user 0m1.030s \end_layout \begin_layout LyX-Code sys 0m1.080s \end_layout \begin_layout LyX-Code $ time ./test_press_zlog 100 1000 # synchronous I/O open \end_layout \begin_layout LyX-Code real 0m20.646s \end_layout \begin_layout LyX-Code user 0m2.570s \end_layout \begin_layout LyX-Code sys 0m6.950s \end_layout \end_deeper \end_deeper \begin_layout Itemize format name \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard It is optional. If not set, use zlog default format in global setting, which is: \end_layout \begin_layout LyX-Code [global] \end_layout \begin_layout LyX-Code default format = "%d %V [%p:%F:%L] %m%n" \end_layout \end_deeper \begin_layout Itemize see \begin_inset CommandInset ref LatexCommand ref reference "sec:User-defined-Output" \end_inset for more details for $. \end_layout \begin_layout Section Rotation \begin_inset CommandInset label LatexCommand label name "sec:Rotation" \end_inset \end_layout \begin_layout Standard Why rotation? I have see more than once in a production environment, that the hard disk is full of logs and causes the system to stop working, or a single log file is too big to open or grep. Several ways to rotate and archive log files are possible: \end_layout \begin_layout Enumerate Split log by date or time. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard For example, generate one log file per day. \end_layout \begin_layout LyX-Code aa.2012-08-02.log \end_layout \begin_layout LyX-Code aa.2012-08-03.log \end_layout \begin_layout LyX-Code aa.2012-08-04.log \end_layout \begin_layout Standard In this case, the system administrator knows how much log will be produced one day. The sys admin is able to search log files based on the day. The best way to make this split is to let the zlog library do it. Another choice is using cronosplit to analyse the content of log file and split it. A bad way is using crontab+logrotate to daily move log files, which is not accurate, some logs will be put into the file for the previous day. \end_layout \begin_layout Standard Using zlog, there is no need for external rotate action to complete the job. Setting time in the log file name works: \end_layout \begin_layout LyX-Code *.* "aa.%d(%F).log" \end_layout \begin_layout Standard or using cronolog for faster performace: \end_layout \begin_layout LyX-Code *.* | cronolog aa.%F.log \end_layout \end_deeper \begin_layout Enumerate Split log by size. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard Always suitable for development use. In this case, the program generates a lot of logs in a short period. But the text editor might not be able to open big files quickly. Although the split can be done using split tools afterwards, this requires extra steps. So a good way is to let the logging library do the rotation. There are two ways of rotation, as nlog describes, Sequence and Rolling. In case of Sequence: \end_layout \begin_layout LyX-Code aa.log (new) \end_layout \begin_layout LyX-Code aa.log.2 (less new) \end_layout \begin_layout LyX-Code aa.log.1 \end_layout \begin_layout LyX-Code aa.log.0 (old) \end_layout \begin_layout Standard And in case of Rolling: \end_layout \begin_layout LyX-Code aa.log (new) \end_layout \begin_layout LyX-Code aa.log.0 (less new) \end_layout \begin_layout LyX-Code aa.log.1 \end_layout \begin_layout LyX-Code aa.log.2 (old) \end_layout \begin_layout Standard It's hard to say which one is most suitable. \end_layout \begin_layout Standard If only some of the newest logs are useful to developers, logging library should do the cleanup work and delete the old log files. Some external tools can't find out which files are older. \end_layout \begin_layout Standard The simplest rotation configuration for zlog is: \end_layout \begin_layout LyX-Code *.* "aa.log", 10MB \end_layout \begin_layout Standard It is Rolling. When aa.log is larger than 10MB, zlog will rename file like this: \end_layout \begin_layout LyX-Code aa.log.2 -> aa.log.3 \end_layout \begin_layout LyX-Code aa.log.1 -> aa.log.2 \end_layout \begin_layout LyX-Code aa.log.0 -> aa.log.1 \end_layout \begin_layout LyX-Code aa.log -> aa.log.0 \end_layout \begin_layout Standard The configuration can be more complex: \end_layout \begin_layout LyX-Code *.* "aa.log", 10MB * 0 ~ "aa.log.#r" \end_layout \begin_layout Standard The 1st argument after the file name says when rotation will be triggered, in size. \end_layout \begin_layout Standard The 2nd argument after the file name says how many archive files will be kept, (0 means keep all). \end_layout \begin_layout Standard The 3rd argument after the file name shows the archive file name. #r is a sequence number for archive files. r is short for Rolling, and #s is short for sequence. Archive file name must contain one of #r or #s. \end_layout \end_deeper \begin_layout Enumerate Split log by size, and add time tag to archive file. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code aa.log \end_layout \begin_layout LyX-Code aa.log-20070305.00.log \end_layout \begin_layout LyX-Code aa.log-20070501.00.log \end_layout \begin_layout LyX-Code aa.log-20070501.01.log \end_layout \begin_layout LyX-Code aa.log-20071008.00.log \end_layout \begin_layout Standard In this case, the log file is not usually viewed frequently, and is likely checked once a day. Of course, when one day's log is more than 100MB, you should consider storing in two files and add postfix numbers. For example if the date is used as part of the pattern (like 20070501): \end_layout \begin_layout Standard The configuration of zlog is: \end_layout \begin_layout LyX-Code *.* "aa.log", 100MB ~ "aa-%d(%Y%m%d).#2s.log" \end_layout \begin_layout LyX-Code Do rotation every 100MB. The archive file name also supports conversion strings. #2s means the sequence number is at least 2 bytes wide. Sequence from 00. That's the most complex way to archive in zlog. \end_layout \end_deeper \begin_layout Enumerate Compress, move and delete old archive. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard Compress should not be done by the logging library, because compress need time and CPU. The mission of the logging library is to cooperate with compress programs. \end_layout \begin_layout Standard For the 3 ways to split logs, way 1 and way 3 are easy to manage. It is easy to find old log file by name or by modify time. And then compress, move and delete old log files by crontab and shell. \end_layout \begin_layout Standard For second way, compress is useless, delete is needed and zlog already supports it. \end_layout \begin_layout Standard If you really want to rotate and compress log file at the same time, I suggest logrotate. It is an independent program and will not confuse the situation. \end_layout \end_deeper \begin_layout Enumerate zlog support for external tools like logrotate. \end_layout \begin_layout Standard The rotation support of zlog is very powerful, still there are several cases zlog can not handle. Like rotation by time, before or after rotation call some user-defined shells. That will make zlog too complex. \end_layout \begin_layout Standard Under these circumstances, consider using external tools like logrotate. On linux, the problem is that when a tool renames the log file, the working process which uses an inode to reference the file will not automatically reopen the new file. The standard way is send a signal to the program and let it reopen the file. For syslogd the command is: \end_layout \begin_layout LyX-Code kill -SIGHUP `cat /var/run/syslogd.pid` \end_layout \begin_layout Standard For zlog as a library, it is not good to receive signals. zlog provide zlog_reload(), which reloads the configuration file and reopens all log files. So if you write a program and want to reopen a log file manually, you can write some code to do the job like this: after receiving a signal or command from client, call zlog_reload(). \end_layout \begin_layout Section Configure File Tools \end_layout \begin_layout LyX-Code $ zlog-chk-conf -h \end_layout \begin_layout LyX-Code Useage: zlog-chk-conf [conf files]... \end_layout \begin_layout LyX-Code -q, suppress non-error message \end_layout \begin_layout LyX-Code -h, show help message \end_layout \begin_layout Standard zlog-chk-conf tries to read configuration files, check their syntax, and output to screen whether it is correct or not. I suggest using this tool each time you create or change a configuration file. It will output like this \end_layout \begin_layout LyX-Code $ ./zlog-chk-conf zlog.conf \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:rule.c:391) sscanf [aaa] fail, category or level is null \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:conf.c:155) zlog_rule_new fail [aaa] \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:conf.c:258) parse configure file[zlog.conf] line[126] fail \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:conf.c:306) zlog_conf_read_config fail \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:conf.c:366) zlog_conf_build fail \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:zlog.c:66) conf_file[zlog.conf], init conf fail \end_layout \begin_layout LyX-Code 03-08 15:35:44 ERROR (10595:zlog.c:131) zlog_init_inner[zlog.conf] fail \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code ---[zlog.conf] syntax error, see error message above \end_layout \begin_layout Standard This example tells you that [aaa] is not a correct rule and that line 126 in the configuration file is wrong. Later failure reports result from that fundamental failure. \end_layout \begin_layout LyX-Code \end_layout \begin_layout Chapter zlog API \end_layout \begin_layout Standard All zlog APIs are thread safe. To use them, you just need to \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout Section initialize and finish \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int zlog_init(const char * \bar under confpath \bar default ); \end_layout \begin_layout LyX-Code int zlog_reload(const char * \bar under confpath \bar default ); \end_layout \begin_layout LyX-Code void zlog_fini(void); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard zlog_init() reads configuration from the file \bar under confpath \bar default . If \bar under confpath \bar default is NULL, it looks for the environment variable ZLOG_CONF_PATH to find the configuration file. If $ZLOG_CONF_PATH is NULL also, all logs will be output to stdout with an internal format. Only the first call to zlog_init() per process is effective, subsequent calls will fail and do nothing. \end_layout \begin_layout Standard zlog_reload() is designed to reload the configuration file. From the \bar under confpath \bar default it re-calculates the category-rule relationships, rebuilds thread buffers, and resets user-defined output function rules. It can be called at runtime when the configuration file is changed or you wish to use another configuration file. It can be called any number of times. If \bar under confpath \bar default is NULL, it reloads the last configuration file that zlog_init() or zlog_reload () specified. If zlog_reload() failed, the current configuration in memory will remain unchanged. So zlog_reload() is atomic. \end_layout \begin_layout Standard zlog_fini() releases all zlog API \emph on \emph default memory and closes opened files. It can be called any number of times. \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard On success , zlog_init() and zlog_reload() return zero. On error, zlog_init() and zlog_reload() return -1, and a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section category operation \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code typedef struct zlog_category_s zlog_category_t; \end_layout \begin_layout LyX-Code zlog_category_t *zlog_get_category(const char * \bar under cname \bar default ); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard zlog_get_category() gets a category from zlog's category_table for a future log action. If the category cname does not exist it will be created. Then zlog goes through all rules as determined by the configuration. It returns a pointer to matched rules corresponding to \bar under cname \bar default . \end_layout \begin_layout Standard This is how category string in rules matches \bar under cname \bar default : \end_layout \begin_layout Enumerate * matches all \bar under cname \bar default . \end_layout \begin_layout Enumerate category string which ends with underscore "_" matches super-category and sub-categories. For example, "aa_" matches \bar under cname \bar default like "aa", "aa_", "aa_bb", "aa_bb_cc". \end_layout \begin_layout Enumerate category string which does not end with underscore "_"matches \bar under cname \bar default accurately. For example, "aa_bb" matches only a \bar under cname \bar default of "aa_bb". \end_layout \begin_layout Enumerate ! matches \bar under cname \bar default that has no rule matched. \end_layout \begin_layout Standard The rules for each category will be automatically re-calculated when zlog_reload () is called. No need to worry about category's memory release, \emph on \emph default zlog_fini() will clean up at the end. \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard On success, return the address of zlog_category_t. On error, return NULL, and a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section log functions and macros \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code void zlog(zlog_category_t * \bar under category \bar default , \end_layout \begin_layout LyX-Code const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const char * \bar under format \bar default , ...); \end_layout \begin_layout LyX-Code void vzlog(zlog_category_t * \bar under category \bar default , \end_layout \begin_layout LyX-Code const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const char * \bar under format \bar default , va_list \bar under args \bar default ); \end_layout \begin_layout LyX-Code void hzlog(zlog_category_t * \bar under category \bar default , \end_layout \begin_layout LyX-Code const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const void * \bar under buf \bar default , size_t \bar under buflen \bar default ); \end_layout \begin_layout LyX-Code \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard These 3 functions are the real log functions producing user messages, which correspond to %m is configuration file entries. \bar under category \bar default comes from zlog_get_category() described above. \end_layout \begin_layout Standard zlog() and vzlog() \emph on \emph default produce output according to a \bar under format \bar default like printf(3) and vprintf(3). \end_layout \begin_layout Standard vzlog() \emph on \emph default is equivalent to zlog(), except that it is called with a va_list instead of a variable number of arguments. vzlog() invokes the va_copy macro, the value of \bar under args \bar default remain unchanged after the call. See stdarg(3). \end_layout \begin_layout Standard hzlog() \emph on \emph default is a little different, it produce output like this, the hexadecimal representati on of \bar under buf \emph on \bar default \emph default and output len is \bar under buf_len \end_layout \begin_layout LyX-Code hex_buf_len=[5365] \end_layout \begin_layout LyX-Code 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDE F \end_layout \begin_layout LyX-Code 0000000001 23 21 20 2f 62 69 6e 2f 62 61 73 68 0a 0a 23 20 #! /bin/bash..# \end_layout \begin_layout LyX-Code 0000000002 74 65 73 74 5f 68 65 78 20 2d 20 74 65 6d 70 6f test_hex - tempo \end_layout \begin_layout LyX-Code 0000000003 72 61 72 79 20 77 72 61 70 70 65 72 20 73 63 72 rary wrapper scr \end_layout \begin_layout Standard The parameter \bar under file \bar default and \bar under line \bar default are usually filled by the __FILE__ and __LINE__ macros. These indicate where the log event happened. The parameter \bar under func \bar default is filled with __func__ or __FUNCTION__, if the compiler supports it, otherwise it will be filled with "". \end_layout \begin_layout Standard \bar under level \emph on \bar default \emph default is an int in the current level list, which defaults to: \end_layout \begin_layout LyX-Code typedef enum { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code ZLOG_LEVEL_DEBUG = 20, \end_layout \begin_layout LyX-Code ZLOG_LEVEL_INFO = 40, \end_layout \begin_layout LyX-Code ZLOG_LEVEL_NOTICE = 60, \end_layout \begin_layout LyX-Code ZLOG_LEVEL_WARN = 80, \end_layout \begin_layout LyX-Code ZLOG_LEVEL_ERROR = 100, \end_layout \begin_layout LyX-Code ZLOG_LEVEL_FATAL = 120 \end_layout \end_deeper \begin_layout LyX-Code } zlog_level; \end_layout \begin_layout Standard Each fuction has its macros for easy use. For example, \end_layout \begin_layout LyX-Code #define zlog_fatal(cat, format, args...) \backslash \end_layout \begin_layout LyX-Code zlog(cat, __FILE__, sizeof(__FILE__)-1, \backslash \end_layout \begin_layout LyX-Code __func__, sizeof(__func__)-1, __LINE__, \backslash \end_layout \begin_layout LyX-Code ZLOG_LEVEL_FATAL, format, ##args) \end_layout \begin_layout Standard The full list of macros is: \end_layout \begin_layout LyX-Code /* zlog macros */ \end_layout \begin_layout LyX-Code /* zlog macros */ \end_layout \begin_layout LyX-Code zlog_fatal(cat, format, ...) \end_layout \begin_layout LyX-Code zlog_error(cat, format, ...) \end_layout \begin_layout LyX-Code zlog_warn(cat, format, ...) \end_layout \begin_layout LyX-Code zlog_notice(cat, format, ...) \end_layout \begin_layout LyX-Code zlog_info(cat, format, ...) \end_layout \begin_layout LyX-Code zlog_debug(cat, format, ...) \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code /* vzlog macros */ \end_layout \begin_layout LyX-Code vzlog_fatal(cat, format, args) \end_layout \begin_layout LyX-Code vzlog_error(cat, format, args) \end_layout \begin_layout LyX-Code vzlog_warn(cat, format, args) \end_layout \begin_layout LyX-Code vzlog_notice(cat, format, args) \end_layout \begin_layout LyX-Code vzlog_info(cat, format, args) \end_layout \begin_layout LyX-Code vzlog_debug(cat, format, args) \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code /* hzlog macros */ \end_layout \begin_layout LyX-Code hzlog_fatal(cat, buf, buf_len) \end_layout \begin_layout LyX-Code hzlog_error(cat, buf, buf_len) \end_layout \begin_layout LyX-Code hzlog_warn(cat, buf, buf_len) \end_layout \begin_layout LyX-Code hzlog_notice(cat, buf, buf_len) \end_layout \begin_layout LyX-Code hzlog_info(cat, buf, buf_len) \end_layout \begin_layout LyX-Code hzlog_debug(cat, buf, buf_len) \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard These functions return nothing. But if anything wrong happens, a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section MDC operation \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int zlog_put_mdc(const char * \bar under key \bar default , const char * \bar under value \bar default ); \end_layout \begin_layout LyX-Code char *zlog_get_mdc(const char * \bar under key \bar default ); \end_layout \begin_layout LyX-Code void zlog_remove_mdc(const char * \bar under key \bar default ); \end_layout \begin_layout LyX-Code void zlog_clean_mdc(void); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard MDC (Mapped Diagnostic Context) is a thread key-value map, and has nothing to do with category. \end_layout \begin_layout Standard \bar under key \bar default and \bar under value \bar default are all strings, which should be no longer than MAXLEN_PATH(1024). If the input is longer than MAXLEN_PATH(1024), the input will be truncated. \end_layout \begin_layout Standard One thing you should remember is that the map bonds to a thread, thus if you set a key-value pair in one thread, it will not affect other threads. \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard zlog_put_mdc() returns 0 for success, -1 for fail. zlog_get_mdc() returns a pointer to \bar under value \bar default for success, NULL for fail or key not exist. If anything wrong happens, a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section dzlog API \begin_inset CommandInset label LatexCommand label name "sec:dzlog-API" \end_inset \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int dzlog_init(const char * \bar under confpath \bar default , const char * \bar under cname \bar default ); \end_layout \begin_layout LyX-Code int dzlog_set_category(const char * \bar under cname \bar default ); \end_layout \begin_layout LyX-Code void dzlog(const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const char * \bar under format \bar default , ...); \end_layout \begin_layout LyX-Code void vdzlog(const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const char * \bar under format \bar default , va_list \bar under args \bar default ); \end_layout \begin_layout LyX-Code void hdzlog(const char * \bar under file \bar default , size_t \bar under filelen \bar default , \end_layout \begin_layout LyX-Code const char * \bar under func \bar default , size_t \bar under funclen \bar default , \end_layout \begin_layout LyX-Code long \bar under line \bar default , int \bar under level \bar default , \end_layout \begin_layout LyX-Code const void * \bar under buf \bar default , size_t \bar under buflen \bar default ); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard dzlog consists of simple functions that omit \emph on zlog_category_t \emph default . It uses a default category internally and puts the category under lock protection. It is thread safe also. Omitting the category means that users need not create, save, or transfer \emph on zlog_category_t \emph default variables. Still, you can get and use other category values at the same time through the normal API for flexibility. \end_layout \begin_layout Standard dzlog_init() is just as zlog_init(), but needs a \bar under cname \bar default for the internal default category. zlog_reload() and zlog_fini() can be used as before, to refresh conf_file, or release all. \end_layout \begin_layout Standard dzlog_set_category() \emph on \emph default is designed for changing the default category. The last default category is replaced by the new one. Don't worry about releasing memory since all category allocations will be cleaned up at zlog_fini(). \end_layout \begin_layout Standard Macros are defined in zlog.h. They are the general way in simple logging. \end_layout \begin_layout LyX-Code dzlog_fatal(format, ...) \end_layout \begin_layout LyX-Code dzlog_error(format, ...) \end_layout \begin_layout LyX-Code dzlog_warn(format, ...) \end_layout \begin_layout LyX-Code dzlog_notice(format, ...) \end_layout \begin_layout LyX-Code dzlog_info(format, ...) \end_layout \begin_layout LyX-Code dezlog_debug(format, ...) \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code vdzlog_fatal(format, args) \end_layout \begin_layout LyX-Code vdzlog_error(format, args) \end_layout \begin_layout LyX-Code vdzlog_warn(format, args) \end_layout \begin_layout LyX-Code vdzlog_notice(format, args) \end_layout \begin_layout LyX-Code vdzlog_info(format, args) \end_layout \begin_layout LyX-Code vdzlog_debug(format, args) \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code hdzlog_fatal(buf, buf_len) \end_layout \begin_layout LyX-Code hdzlog_error(buf, buf_len) \end_layout \begin_layout LyX-Code hdzlog_warn(buf, buf_len) \end_layout \begin_layout LyX-Code hdzlog_noticebuf, buf_len) \end_layout \begin_layout LyX-Code hdzlog_info(buf, buf_len) \end_layout \begin_layout LyX-Code hdzlog_debug(buf, buf_len) \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard On success, dzlog_init() and dzlog_set_category() return zero. On error, dzlog_init() and dzlog_set_category() return -1, and a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section User-defined Output \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code typedef struct zlog_msg_s { \end_layout \begin_layout LyX-Code char *buf; \end_layout \begin_layout LyX-Code size_t len; \end_layout \begin_layout LyX-Code char *path; \end_layout \begin_layout LyX-Code } zlog_msg_t; \end_layout \begin_layout LyX-Code typedef int (*zlog_record_fn)(zlog_msg_t * \bar under msg \bar default ); \end_layout \begin_layout LyX-Code int zlog_set_record(const char * \bar under rname \bar default , zlog_record_fn \bar under record \bar default ); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard zlog allows a user to define an output function. The output function bonds to a special kind of rule in configuration file. A typical rule is: \end_layout \begin_layout LyX-Code *.* $name, "record path %c %d"; simple \end_layout \begin_layout Standard zlog_set_record() does the bonding operation. Rules with the $ \bar under rname \bar default will be output through user-defined function \bar under record \bar default . The callback function has the type of zlog_record_fn. \end_layout \begin_layout Standard The members of struct zlog_msg_t are decribed below: \end_layout \begin_layout Standard \bar under path \bar default comes from the second parameter of rule after $name, which is generated dynamically like the file path. \end_layout \begin_layout Standard \bar under buf \bar default and \bar under len \bar default are zlog formatted log message and its length. \end_layout \begin_layout Standard All settings of zlog_set_record() are kept available after zlog_reload(). \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 RETURN VALUE \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard On success, zlog_set_record() returns zero. On error, it returns -1, and a detailed error log will be recorded to the log file indicated by ZLOG_PROFILE_ERROR. \end_layout \end_deeper \begin_layout Section debug and profile \end_layout \begin_layout Labeling \labelwidthstring 00.00.0000 SYNOPSIS \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code void zlog_profile(void); \end_layout \end_deeper \begin_layout Labeling \labelwidthstring 00.00.0000 DESCRIPTION \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Standard environment variable ZLOG_PROFILE_ERROR indicates zlog's error log path. \end_layout \begin_layout Standard environment variable ZLOG_PROFILE_DEBUG indicates zlog's debug log path. \end_layout \begin_layout Standard zlog_profile() prints all information in memory to zlog's error log file at runtime. You can compare it to the configuration file to find possible errors. \end_layout \end_deeper \begin_layout Chapter Advanced Usage \end_layout \begin_layout Section MDC \begin_inset CommandInset label LatexCommand label name "sec:MDC" \end_inset \end_layout \begin_layout Standard What is MDC? In log4j it is short for Mapped Diagnostic Context. That sounds like a complicated terminology. MDC is just a key-value map. Once you set it by function, the zlog library will print it to file every time a log event happens, or become part of log file path. Let's see an example in $(top_builddir)/test/test_mdc.c. \end_layout \begin_layout LyX-Code $ cat test_mdc.c \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code zlog_category_t *zc; \end_layout \begin_layout LyX-Code rc = zlog_init("test_mdc.conf"); \end_layout \begin_layout LyX-Code if (rc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zc = zlog_get_category("my_cat"); \end_layout \begin_layout LyX-Code if (!zc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("get cat fail \backslash n"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return -2; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zlog_info(zc, "1.hello, zlog"); \end_layout \begin_layout LyX-Code zlog_put_mdc("myname", "Zhang"); \end_layout \begin_layout LyX-Code zlog_info(zc, "2.hello, zlog"); \end_layout \begin_layout LyX-Code zlog_put_mdc("myname", "Li"); \end_layout \begin_layout LyX-Code zlog_info(zc, "3.hello, zlog"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout Standard The configure file is \end_layout \begin_layout LyX-Code $ cat test_mdc.conf \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code mdc_format= "%d.%ms %-6V (%c:%F:%L) [%M(myname)] - %m%n" \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code *.* >stdout; mdc_format \end_layout \begin_layout Standard And the output is \end_layout \begin_layout LyX-Code $ ./test_mdc \end_layout \begin_layout LyX-Code 2012-03-12 09:26:37.740 INFO (my_cat:test_mdc.c:47) [] - 1.hello, zlog \end_layout \begin_layout LyX-Code 2012-03-12 09:26:37.740 INFO (my_cat:test_mdc.c:51) [Zhang] - 2.hello, zlog \end_layout \begin_layout LyX-Code 2012-03-12 09:26:37.740 INFO (my_cat:test_mdc.c:55) [Li] - 3.hello, zlog \end_layout \begin_layout Standard You can see zlog_put_mdc() function sets the map with key "myname" and value "Zhang", and in configuration file \emph on %M(myname) \emph default indicates where the value shows in each log. The second time, value of key "myname" is overwritten to "Li", and the log changes also. \end_layout \begin_layout Standard When should MDC be used? That mainly depends on when a user need to separate same log action with different scenarios. For example, in .c \end_layout \begin_layout LyX-Code zlog_put_mdc("customer_name", get_customer_name_from_db() ); \end_layout \begin_layout LyX-Code zlog_info("get in"); \end_layout \begin_layout LyX-Code zlog_info("pick product"); \end_layout \begin_layout LyX-Code zlog_info("pay"); \end_layout \begin_layout LyX-Code zlog_info("get out"); \end_layout \begin_layout Standard in .conf \end_layout \begin_layout LyX-Code &format "%M(customer_name) %m%n" \end_layout \begin_layout Standard When the program processes two customers at the same time, the output could be: \end_layout \begin_layout LyX-Code Zhang get in \end_layout \begin_layout LyX-Code Li get in \end_layout \begin_layout LyX-Code Zhang pick product \end_layout \begin_layout LyX-Code Zhang pay \end_layout \begin_layout LyX-Code Li pick product \end_layout \begin_layout LyX-Code Li pay \end_layout \begin_layout LyX-Code Zhang get out \end_layout \begin_layout LyX-Code Li get out \end_layout \begin_layout Standard Now you can distinguish one customer from another, by using grep afterwards \end_layout \begin_layout LyX-Code $ grep Zhang aa.log > Zhang.log \end_layout \begin_layout LyX-Code $ grep Li aa.log >Li.log \end_layout \begin_layout Standard Or, another way is to seperate them to different log file when log action is taken. In .conf \end_layout \begin_layout LyX-Code *.* "mdc_%M(customer_name).log"; \end_layout \begin_layout Standard It will produce 3 logs \end_layout \begin_layout LyX-Code mdc_.log mdc_Zhang.log mdc_Li.log \end_layout \begin_layout Standard That's a quick way, if you know what you are doing. \end_layout \begin_layout Standard In MDC, the map belongs to a thread and each thread has it's own map. In one thread zlog_mdc_put() will not affect other thread's map. Still, if you want to distinguish one thread from another, using the %t conversion character is enough. \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code \end_layout \begin_layout Section Profile zlog Itself \begin_inset CommandInset label LatexCommand label name "sec:Profile-zlog-Itself" \end_inset \end_layout \begin_layout Standard Until this point we have assumed that the zlog library never fails. It helps the application to write log entries and to debug the application. But if zlog itself has some problem, how can we find out? Other programs debug through the log library so how can a log library debug itself? The answer is the same, zlog library has its own log. This profile log is usually closed, and can be opened by setting environment variables. \end_layout \begin_layout LyX-Code $ export ZLOG_PROFILE_DEBUG=/tmp/zlog.debug.log \end_layout \begin_layout LyX-Code $ export ZLOG_PROFILE_ERROR=/tmp/zlog.error.log \end_layout \begin_layout Standard profile log has just 2 levels, debug and error. After setting them, run test_hello program in \begin_inset CommandInset ref LatexCommand ref reference "sec:Hello-World-Example" \end_inset , and the debug log will be \end_layout \begin_layout LyX-Code $ more zlog.debug.log \end_layout \begin_layout LyX-Code 03-13 09:46:56 DEBUG (7503:zlog.c:115) ------zlog_init start, compile time[Mar 13 2012 11:28:56]------ \end_layout \begin_layout LyX-Code 03-13 09:46:56 DEBUG (7503:spec.c:825) spec:[0x7fdf96b7c010][%d(%F %T)][%F %T 29][] \end_layout \begin_layout LyX-Code 03-13 09:46:56 DEBUG (7503:spec.c:825) spec:[0x7fdf96b52010][ ][ 0][] \end_layout \begin_layout LyX-Code ...... \end_layout \begin_layout LyX-Code 03-13 09:52:40 DEBUG (8139:zlog.c:291) ------zlog_fini end------ \end_layout \begin_layout Standard zlog.error.log is not created, as no error occurs. \end_layout \begin_layout Standard As you can see, debug log shows how zlog is inited and finished, but no debug log is written when zlog_info() is executed. That's for efficency. \end_layout \begin_layout Standard If there is anything wrong with zlog library, all will show in zlog.error.log. For example, using a wrong printf syntax in zlog() \end_layout \begin_layout LyX-Code zlog_info(zc, "%l", 1); \end_layout \begin_layout Standard Then run the program, the zlog.error.log should be \end_layout \begin_layout LyX-Code $ cat zlog.error.log \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:buf.c:189) vsnprintf fail, errno[0] \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:buf.c:191) nwrite[-1], size_left[1024], format[%l] \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:spec.c:329) zlog_buf_vprintf maybe fail or overflow \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:spec.c:467) a_spec->gen_buf fail \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:format.c:160) zlog_spec_gen_msg fail \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:rule.c:265) zlog_format_gen_msg fail \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:category.c:164) hzb_log_rule_output fail \end_layout \begin_layout LyX-Code 03-13 10:04:58 ERROR (10102:zlog.c:632) zlog_output fail, srcfile[test_hello.c], srcline[41] \end_layout \begin_layout Standard Now, you could find the reason why the expected log doesn't generate, and fix the wrong printf syntax. \end_layout \begin_layout Standard Runtime profiling causes a loss of efficency. Normally, I keep ZLOG_PROFILE_ERROR on and ZLOG_PROFILE_DEBUG off in my environment. \end_layout \begin_layout Standard There is another way to profile the zlog library. zlog_init() reads the configuration file into memory. Throughout all log actions, the configure structure remains unchanged. There is possibility that this memory is damaged by other functions in an application, or the memory doesn't equal what the configuration file describes. So there is a function to show this memory at runtime and print it to ZLOG_PROF ILE_ERROR. \end_layout \begin_layout Standard see $(top_builddir)/test/test_profile.c \end_layout \begin_layout LyX-Code $ cat test_profile.c \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code rc = dzlog_init("test_profile.conf", "my_cat"); \end_layout \begin_layout LyX-Code if (rc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code dzlog_info("hello, zlog"); \end_layout \begin_layout LyX-Code zlog_profile(); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout Standard zlog_profile() is the function. The configuration file is simple \end_layout \begin_layout LyX-Code $ cat test_profile.conf \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code simple = "%m%n" \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.* >stdout; simple \end_layout \begin_layout Standard Then zlog.error.log is \end_layout \begin_layout LyX-Code $ cat /tmp/zlog.error.log \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:zlog.c:783) ------zlog_profile start------ \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:zlog.c:784) init_flag:[1] \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:75) -conf[0x2333010]- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:76) --global-- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:77) ---file[test_profile.conf],mtime[2012-06-01 11:20:44]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:78) ---strict init[1]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:79) ---buffer min[1024]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:80) ---buffer max[2097152]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:82) ---default_format--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:format.c:48) ---format[0x235ef60][default = %d(%F %T) %V [%p:%F:%L] %m%n(0x233b810)]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:85) ---file perms[0600]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:conf.c:87) ---rotate lock file[/tmp/zlog.lock]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:rotater.c:48) --rotater[0x233b7d0][0x233b7d0,/tmp/zlog. lock,4]-- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level_list.c:37) --level_list[0x2335490]-- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x23355c0][0,*,*,1,6]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x23375e0][20,DEBUG,debug,5,7]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x2339600][40,INFO,info,4,6]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x233b830][60,NOTICE,notice,6,5]- -- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x233d850][80,WARN,warn,4,4]--- \end_layout \begin_layout LyX-Code 06-01 11:21:26 WARN (7063:level.c:37) ---level[0x233fc80][100,ERROR,error,5,3]-- - \end_layout \begin_layout Section User-defined Level \begin_inset CommandInset label LatexCommand label name "sec:User-defined-Level" \end_inset \end_layout \begin_layout Standard Here are all the steps to define your own levels. \end_layout \begin_layout Enumerate Define levels in the configuration file. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ cat $(top_builddir)/test/test_level.conf \end_layout \begin_layout LyX-Code [global] \end_layout \begin_layout LyX-Code default format = "%V %v %m%n" \end_layout \begin_layout LyX-Code [levels] \end_layout \begin_layout LyX-Code TRACE = 30, LOG_DEBUG \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.TRACE >stdout; \end_layout \begin_layout Standard The internal default levels are (no need to write them in the conf file): \end_layout \begin_layout LyX-Code DEBUG = 20, LOG_DEBUG \end_layout \begin_layout LyX-Code INFO = 40, LOG_INFO \end_layout \begin_layout LyX-Code NOTICE = 60, LOG_NOTICE \end_layout \begin_layout LyX-Code WARN = 80, LOG_WARNING \end_layout \begin_layout LyX-Code ERROR = 100, LOG_ERR \end_layout \begin_layout LyX-Code FATAL = 120, LOG_ALERT \end_layout \begin_layout LyX-Code UNKNOWN = 254, LOG_ERR \end_layout \begin_layout Standard In zlog, an integer(30) and a level string(TRACE) represent a level. Note that this integer must be in [1,253], any other number is illegal. Higher numbers are more important. TRACE is more important than DEBUG(30>20), and less important than INFO(30<40). After the definition, TRACE can be used in rule of configure file. This sentence \end_layout \begin_layout LyX-Code my_cat.TRACE >stdout; \end_layout \begin_layout Standard means that level >= TRACE, which is TRACE, INFO, NOTICE, WARN, ERROR, FATAL will be written to standard output. \end_layout \begin_layout Standard The conversion charactor %V of format string generates the uppercase value of the level string and %v generates the lowercase value of the level string. \end_layout \begin_layout Standard In the level definition LOG_DEBUG means when using >syslog in a rule, all TRACE log will output as syslog' s LOG_DEBUG level. \end_layout \end_deeper \begin_layout Enumerate Using the new log level in source file, the direct way is like this \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code zlog(cat, __FILE__, sizeof(__FILE__)-1, \backslash \end_layout \begin_layout LyX-Code __func__, sizeof(__func__)-1,__LINE__, \backslash \end_layout \begin_layout LyX-Code 30, "test %d", 1); \end_layout \begin_layout Standard For easy use, create a .h file \end_layout \begin_layout LyX-Code $ cat $(top_builddir)/test/test_level.h \end_layout \begin_layout LyX-Code #ifndef __test_level_h \end_layout \begin_layout LyX-Code #define __test_level_h \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code enum { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code ZLOG_LEVEL_TRACE = 30, \end_layout \begin_layout LyX-Code /* must equals conf file setting */ \end_layout \end_deeper \begin_layout LyX-Code }; \end_layout \begin_layout LyX-Code #define zlog_trace(cat, format, ...) \backslash \end_layout \begin_layout LyX-Code zlog(cat, __FILE__, sizeof(__FILE__)-1, \backslash \end_layout \begin_layout LyX-Code __func__, sizeof(__func__)-1, __LINE__, \backslash \end_layout \begin_layout LyX-Code ZLOG_LEVEL_TRACE, format, ## __VA_ARGS__) \end_layout \begin_layout LyX-Code #endif \end_layout \end_deeper \begin_layout Enumerate Then zlog_trace can be used int .c file \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ cat $(top_builddir)/test/test_level.c \end_layout \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "test_level.h" \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code zlog_category_t *zc; \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code rc = zlog_init("test_level.conf"); \end_layout \begin_layout LyX-Code if (rc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zc = zlog_get_category("my_cat"); \end_layout \begin_layout LyX-Code if (!zc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("get cat fail \backslash n"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return -2; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zlog_trace(zc, "hello, zlog - trace"); \end_layout \begin_layout LyX-Code zlog_debug(zc, "hello, zlog - debug"); \end_layout \begin_layout LyX-Code zlog_info(zc, "hello, zlog - info"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \end_deeper \begin_layout Enumerate Now we can see the output \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ ./test_level \end_layout \begin_layout LyX-Code TRACE trace hello, zlog - trace \end_layout \begin_layout LyX-Code INFO info hello, zlog - info \end_layout \begin_layout Standard That's just what we expect. The configuration file only allows >=TRACE ouput to screen. And %V and %v work as well. \end_layout \end_deeper \begin_layout Section User-defined Output \begin_inset CommandInset label LatexCommand label name "sec:User-defined-Output" \end_inset \end_layout \begin_layout Standard The goal of user-defined output is that zlog gives up some rights. zlog is only responsible for generating path and message dynamically as per the user's configuration, but leaves the log output, rotate and cleanup actions for the user to specify. You can do what ever you want by setting a function to special rules. Here are the steps to define your own output function. \end_layout \begin_layout Enumerate Define output in rules of configure file. \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ cat test_record.conf \end_layout \begin_layout LyX-Code [formats] \end_layout \begin_layout LyX-Code simple = "%m%n" \end_layout \begin_layout LyX-Code [rules] \end_layout \begin_layout LyX-Code my_cat.* $myoutput, " mypath %c %d";simple \end_layout \end_deeper \begin_layout Enumerate Set an output function for myoutput, then use it \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code #include \end_layout \begin_layout LyX-Code #include "zlog.h" \end_layout \begin_layout LyX-Code int output(zlog_msg_t *msg) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("[mystd]:[%s][%s][%ld] \backslash n", msg->path, msg->buf, (long)msg->len); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code \end_layout \begin_layout LyX-Code int main(int argc, char** argv) \end_layout \begin_layout LyX-Code { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code int rc; \end_layout \begin_layout LyX-Code zlog_category_t *zc; \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code rc = zlog_init("test_record.conf"); \end_layout \begin_layout LyX-Code if (rc) { \end_layout \begin_layout LyX-Code printf("init failed \backslash n"); \end_layout \begin_layout LyX-Code return -1; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zlog_set_record("myoutput", output); \end_layout \begin_layout LyX-Code zc = zlog_get_category("my_cat"); \end_layout \begin_layout LyX-Code if (!zc) { \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code printf("get cat fail \backslash n"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return -2; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \begin_layout LyX-Code zlog_info(zc, "hello, zlog"); \end_layout \begin_layout LyX-Code zlog_fini(); \end_layout \begin_layout LyX-Code return 0; \end_layout \end_deeper \begin_layout LyX-Code } \end_layout \end_deeper \begin_layout Enumerate Now we can see how the user-defined output() works \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout LyX-Code $ ./test_record \end_layout \begin_layout LyX-Code [mystd]:[ mypath my_cat 2012-07-19 11:01:12][hello, zlog \end_layout \begin_layout LyX-Code ][12] \end_layout \begin_layout Standard As you can see, msglen is 12, and msg is formatted by zlog to contain a newline character. \end_layout \end_deeper \begin_layout Enumerate There are many other things you can do with user-defined output functions. As one user(flw@newsmth.net) provided: \begin_inset Separator latexpar \end_inset \end_layout \begin_deeper \begin_layout Enumerate Log name is foo.log \end_layout \begin_layout Enumerate If foo.log is larger than 100M, then generate a new logfile which contains all the contents of foo.log. And zlog truncates foo.log to 0 and re-appends to it when the next log happens. \end_layout \begin_layout Enumerate When the time is over 5 minutes after last logging, even if foo.log is not larger than 100M, zlog still jumps to a new file. \end_layout \begin_layout Enumerate The new file name should be defined by your own needs. For example add device number as prefix and time string as postfix. \end_layout \begin_layout Enumerate You might compress the new log file to save disk space and network bandwidth. \end_layout \begin_layout Standard I wish him good luck trying to write such a function for multi-process or multi-thread cases! \end_layout \end_deeper \begin_layout Chapter Epilog \end_layout \begin_layout Verse Here's to alcohol, the cause of – and solution to – all life’s problems. \end_layout \begin_layout Right Address Homer Simpson \end_layout \end_body \end_document