1, 在mingw中配置log4c
configure --disable-doc --enable-reread --without-expat --prefix=`pwd`/dest && make -j && make install
小插曲:杀毒软件等,360,qq等,可能会把configure时候产生的conftest.exe误报为病毒,导致configure失败。
2, 在examples文件夹中创建用于封装log4c的l4c源文件
/*
* 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();
}
3, 编译生成l4c动态链接库
gcc -o l4c.dll -fPIC -shared -static -O0 -g -w -I../dest/include l4c.c ../dest/lib/liblog4c.a
4, 使用Dependency Walker查看自定义函数的ordinal
也可以用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
5,制作def文件
LIBRARY "l4c"
DESCRIPTION "simple wrapper of l4c"
EXPORTS
l4c_category_get @1
l4c_category_log @2
l4c_fini @3
l4c_init @4
6,生成lib
lib /def:l4c.def /out:l4c.lib /machine:x86
在msvc的命令行里可以执行dumpbin和lib等vc++ sdk的工具
7,制作一个简单的头文件
#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
8, 测试代码
#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;
}
9, 测试用的配置文件log4crc
<?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>
10, 编译测试代码
cl dlltest.c
11, 运行测试代码
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
12, 截图
注意:
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;
}