configure --disable-doc --enable-reread --without-expat --prefix=`pwd`/dest && make -j && make install
小插曲:杀毒软件等,360,qq等,可能会把configure时候产生的conftest.exe误报为病毒,导致configure失败。
/* * This is one of log4c example programs. * * Notice how no relationships between the category and a certain * priority, appender, or formatter are coded here. These are all left * to the log4crc config file so they can be chaned without recompiling * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> #ifndef _WIN32 #include <sys/time.h> #else #include <time.h> #include <windows.h> #include <winsock.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include "log4c.h" // 引用package自带的头文件 #define L4C_API __declspec(dllexport) L4C_API int l4c_init(void){ return log4c_init(); } L4C_API void * l4c_category_get(const char* a_name){ return log4c_category_get(a_name); } L4C_API void l4c_category_log(const void * a_category , int a_priority , const char* a_format, ...){ if (log4c_category_is_priority_enabled((log4c_category_t*)a_category , a_priority)) { va_list va; va_start(va, a_format); log4c_category_vlog(a_category, a_priority, a_format, va); va_end(va); } } L4C_API int l4c_fini(void){ return log4c_fini(); }
gcc -o l4c.dll -fPIC -shared -static -O0 -g -w -I../dest/include l4c.c ../dest/lib/liblog4c.a
也可以用dumpbin查看自定义函数在dll中位置
dumpbin /exports l4c.dll
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file l4c.dll File Type: DLL Section contains the following exports for l4c.dll 00000000 characteristics 52245CBA time date stamp Mon Sep 02 17:39:06 2013 0.00 version 1 ordinal base 4 number of functions 4 number of names ordinal hint RVA name 1 0 0000158B l4c_category_get 2 1 0000159E l4c_category_log 3 2 000015DE l4c_fini 4 3 0000157E l4c_init Summary 1000 .CRT 2000 .bss 1000 .data 5000 .debug_abbrev 1000 .debug_aranges 1000 .debug_frame 18000 .debug_info 5000 .debug_line 11000 .debug_loc 1000 .debug_pubnames 1000 .debug_pubtypes 1000 .debug_ranges 1000 .debug_str 1000 .edata 3000 .eh_frame 1000 .idata A000 .rdata 1000 .reloc C000 .text 1000 .tls
LIBRARY "l4c" DESCRIPTION "simple wrapper of l4c" EXPORTS l4c_category_get @1 l4c_category_log @2 l4c_fini @3 l4c_init @4
lib /def:l4c.def /out:l4c.lib /machine:x86
#ifndef _L4C_WIN32_H_ #define _L4C_WIN32_H_ #ifdef WIN32 #ifdef L4C_EXPORTS # define L4C_API __declspec(dllexport) #else # define L4C_API __declspec(dllimport) #endif #else # define L4C_API #endif enum log4c_priority_level_t{ /** fatal */ LOG4C_PRIORITY_FATAL = 000, /** alert */ LOG4C_PRIORITY_ALERT = 100, /** crit */ LOG4C_PRIORITY_CRIT = 200, /** error */ LOG4C_PRIORITY_ERROR = 300, /** warn */ LOG4C_PRIORITY_WARN = 400, /** notice */ LOG4C_PRIORITY_NOTICE = 500, /** info */ LOG4C_PRIORITY_INFO = 600, /** debug */ LOG4C_PRIORITY_DEBUG = 700, /** trace */ LOG4C_PRIORITY_TRACE = 800, /** notset */ LOG4C_PRIORITY_NOTSET = 900, /** unknown */ LOG4C_PRIORITY_UNKNOWN = 1000 } ; #ifdef __cplusplus extern "C" { #endif L4C_API int l4c_init(void); L4C_API void * l4c_category_get(const char* a_name); L4C_API void l4c_category_log(const void * a_category , int a_priority , const char* a_format,...); L4C_API int l4c_fini(void); #ifdef __cplusplus }; #endif #endif
#include "l4c.h" #pragma comment(lib, "l4c.lib") int main(int argc, char** argv) { int i = 0; void* mycat = (void*)0; l4c_init(); mycat = l4c_category_get("six13log.log.app.application2"); for (i = 0; i < 100; i++) l4c_category_log(mycat, LOG4C_PRIORITY_DEBUG, "Debugging app 2"); l4c_fini(); return 0; }
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE log4c SYSTEM ""> <log4c version="1.2.3"> <config> <bufsize>0</bufsize> <debug level="2"/> <nocleanup>0</nocleanup> <reread>1</reread> </config> <category name="root" priority="notice"/> <category name="six13log.log" priority="error" appender="stdout" /> <rollingpolicy name="myrollingpolicy" type="sizewin" maxsize="1024" maxnum="10" /> <appender name="myrollingfileappender" type="rollingfile" logdir="." prefix="myprefix" layout="dated" rollingpolicy="myrollingpolicy" /> <appender name="stdout" type="stream" layout="basic"/> <appender name="stderr" type="stream" layout="dated"/> <appender name="syslog" type="syslog" layout="basic"/> <appender name="s13file" type="s13_file" layout="basic"/> <appender name="plain_stderr" type="s13_stderr" layout="none"/> <appender name="cat_stderr" type="s13_stderr" layout="catlayout"/> <appender name="xml_stderr" type="s13_stderr" layout="xmllayout"/> <appender name="user_stderr" type="s13_stderr" layout="userlayout"/> <layout name="basic" type="basic"/> <layout name="dated" type="dated"/> <layout name="catlayout" type="s13_cat"/> <layout name="xmllayout" type="s13_xml"/> <layout name="none" type="s13_none"/> <layout name="userlayout" type="s13_userloc"/> <category name="six13log.log.app.application2" priority="debug" appender="cat_stderr" /> <category name="six13log.log.app.application3" priority="debug" appender="user_stderr" /> <category name="six13log.log.app" priority="debug" appender="myrollingfileappender" /> </log4c>
cl dlltest.c
H:\log4c-1.2.3\examples\dlltest>dlltest.exe [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2 [stdout] DEBUG six13log.log.app.application2 - Debugging app 2
注意:
1) 多个appender 不能共享一个policy,否则,只有一个工作,一定要为每一个appender创建一个policy。
2)log4c的性能不高,如果应用在数据处理的逻辑里面非常不合适,一些GUI程序可能比较合适,主要的一个性能瓶颈在log4c_category_log, 大概一毫秒也就是6条左右的速度。 然而我用fprintf直接刷到文件的速度比这个要快至少500倍以上,16ms打印了9000条左右。
一小段测试用的bench对比,log4c_category_log vs. fprintf
/* * This is one of log4c example programs. * * Notice how no relationships between the category and a certain * priority, appender, or formatter are coded here. These are all left * to the log4crc config file so they can be chaned without recompiling * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #ifndef _WIN32 #include <sys/time.h> #else #include <time.h> #include <windows.h> #include <winsock.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #include "log4c.h" #ifdef _WIN32 #if !defined(__MINGW32__) && !defined(__MINGW64__) int gettimeofday(struct timeval* tp, void* tzp) { DWORD t; t = timeGetTime(); tp->tv_sec = t / 1000; tp->tv_usec = t % 1000; /* 0 indicates that the call succeeded. */ return 0; } #endif #if !defined(HAVE_SLEEP) || !HAVE_DECL_SLEEP #define sleep(x) Sleep(x*1000) #endif #endif /* _WIN32 */ #include "log4tvu.h" #include <map> #include <string> typedef unsigned int uint32; #include <list> #include <TvuMutex.hpp> #include <TvuSemaphore.hpp> #include <TvuThread.hpp> #include <FIFO.hpp> enum { MaxLogCount = 20, MaxLogLength= 1000, MaxLogCache = 20000, }; struct logstruct { int level; char cat[20]; char msg[200]; }; static FIFO<void * > * s_log = NULL; void * backlog(void *args) { static bool initialized = false; static std::map<std::string, log4c_category_t *> catcache; log4c_category_t* mycat = NULL; if (!initialized) { log4c_init(); initialized = true; } static char * logblock = NULL; static int logcount = 0; FILE * fout = fopen("1.log", "w"); while(true) { if (logcount >= MaxLogCache){ logcount = 0; free(logblock);logblock = NULL; } if (logblock == NULL){ s_log->Pick((void **)&logblock, INFINITE); logcount = 0; } logstruct s; memcpy(&s, logblock + logcount * sizeof(logstruct), sizeof(logstruct)); logcount ++; /* */ if (catcache.find(s.cat) == catcache.end()) { mycat = log4c_category_get(s.cat); catcache [s.cat] = mycat; }else{ mycat = catcache [s.cat]; } //log4c_category_log(mycat, s.level, s.msg); fprintf(fout, "%d, %s\n", GetTickCount(), s.msg); } } int tvulog(int level, const char * cat, const char * format, ...) { if (s_log == NULL){ s_log = new FIFO<void *>(MaxLogCount); } static bool backlogrunning = false; if (!backlogrunning){ CTvuThread t; t.Create(backlog, NULL); backlogrunning = true; } int cursize = s_log->GetSize(); char logstr [MaxLogLength] = ""; sprintf(logstr, "the CUrrent q size is %d", cursize); // 1Mega per block. logstruct s; s.level = level; strcpy(s.cat, cat); strcpy(s.msg, logstr); static char * logblock = NULL; static int logcount = 0; if (logcount >= MaxLogCache){ s_log->Push(logblock, INFINITE); logcount = 0; logblock = NULL; } if (logblock == NULL){ logblock = (char*)malloc(sizeof(logstruct) * MaxLogCache); } memcpy(logblock + sizeof(logstruct) * logcount, &s, sizeof(logstruct)); logcount ++; return 0; }