log4cxx配置使用(二)

一、配置文件的例子

log4j.rootLogger=DEBUG,lib
log4j.appender.lib=org.apache.log4j.ConsoleAppender
log4j.appender.lib.Threshold=DEBUG
log4j.appender.lib.File=./log/output.log
log4j.appender.lib.Append=true
log4j.appender.lib.layout=org.apache.log4j.PatternLayout
log4j.appender.lib.layout.ConversionPattern=[%-5p] %d %l : %m%n

下面就是一个简单的用配置文件配置log4cxx的代码

#include <log4cxx/logger.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/exception.h>
#include <iostream>
int main()
{
        log4cxx::PropertyConfigurator::configureAndWatch("log4cxx.properties");
        log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("lib"));
        LOG4CXX_DEBUG(logger, "this is log4cxx test");
        return 0;
}

用配置文件的例子,网上可以找到很多,我这里要写的是用代码直接配置log4cxx。

二、头文件

#ifndef _aLogger_H__
#define _aLogger_H__

#include <log4cxx/logger.h>
#include <log4cxx/logstring.h>
#include <log4cxx/log4cxx.h>

#define _MSGBUF_MAX 4096

class aLogger
{
public:
	aLogger(const log4cxx::LogString &name="undefined");

	~aLogger();

	/**
 	 * @brief 添加控制台日志
 	 */
	void addConsoleLog(const log4cxx::LayoutPtr &layout);

	/**
 	 * @brief 移除控制台日志
 	 */
	void removeConsoleLog();

	/**
 	 * @brief 添加回滚文件日志
 	 */
	void addDailyLocalFileLog(const log4cxx::LayoutPtr &layout);

	/**
 	 * @brief 设置日志等级
 	 *
 	 * @param "TRACE" < "DEBUG" < "INFO" < "WARN" < "ERROR" < "FATAL"
 	 */
	bool setLevel(const log4cxx::LogString &level);

	/** 
	 * @brief trace 级别日志
	 * 
	 * @param format 参数
	 * @param ... 参数列表
	 */
	void trace(const char *format, ... );

	void debug(const char *format, ... );

	void info(const char *format, ... );

	void warn(const char *format, ... );

	void error(const char *format, ... );

	void fatal(const char *format, ... );

	/**
 	 * @brief 强制写日志,无视当前的日志级别
 	 */
	void forcelog(const log4cxx::LogString &level, const char *format, ... );

	/**
 	 * @brief 条件写错误日志,无视当前的日志级别
 	 */
	void assertlog(bool condition, const log4cxx::LogString &level, const char *format, ... );
private:
	log4cxx::LoggerPtr logger;
};

#endif

三、实现文件

#include <log4cxx/helpers/pool.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/dailyrollingfileappender.h>
#include <log4cxx/consoleappender.h>
#include <log4cxx/patternlayout.h>
#include <log4cxx/logmanager.h>
#include <cstdarg>
#include <cstdio>
#include "aLogger.h"

using namespace std;
using namespace log4cxx;

extern map<string, string> argMap;

aLogger::aLogger(const LogString &name)
{
	PatternLayoutPtr layout = new PatternLayout();
	LogString conversionPattern = LogString("%d{yyMMdd-HH:mm:ss} ") + name + LogString(" %5p: %m%n");
	layout->setConversionPattern(conversionPattern);

        logger = Logger::getRootLogger();
	logger->setLevel(Level::getTrace());
	addConsoleLog(layout);
	addDailyLocalFileLog(layout);
}

aLogger::~aLogger()
{
	LogManager::shutdown();
}

void aLogger::addConsoleLog(const LayoutPtr &layout)
{
	if (NULL == layout) return;

	helpers::Pool p;

	ConsoleAppenderPtr consoleAppender = new ConsoleAppender(LayoutPtr(layout));
	consoleAppender->setTarget(ConsoleAppender::getSystemOut());
	consoleAppender->activateOptions(p);
	consoleAppender->setEncoding("UTF-8");
	consoleAppender->setName("consoleAppender");

	BasicConfigurator::configure(AppenderPtr(consoleAppender));
}

void aLogger::removeConsoleLog()
{
	if (NULL == logger) return;
	ConsoleAppenderPtr consoleAppender = logger->getAppender("consoleAppender");
	if (NULL == consoleAppender) return;
	if (logger->isAttached(consoleAppender))
		logger->removeAppender(consoleAppender);
}

void aLogger::addDailyLocalFileLog(const LayoutPtr &layout)
{
	if (NULL == layout) return;

        helpers::Pool p;

	LogString LogPath;
	map<string, string>::const_iterator it = argMap.find("logPath");
	if (it == argMap.end())
		LogPath = "/tmp/out.log";
	else
		LogPath = it->second;

	DailyRollingFileAppenderPtr rollingfileAppender = new DailyRollingFileAppender();
	rollingfileAppender->setFile(LogPath);
        rollingfileAppender->setAppend(true);
        rollingfileAppender->setDatePattern("‘.‘yyyyMMdd-HH");
        rollingfileAppender->setLayout(LayoutPtr(layout));
        rollingfileAppender->activateOptions(p);
	rollingfileAppender->setEncoding("UTF-8");
	rollingfileAppender->setName("rollingfileAppender");

	BasicConfigurator::configure(AppenderPtr(rollingfileAppender));
}

bool aLogger::setLevel(const std::string &level)
{
	if (NULL == logger) return false;

	//如果字符串不符合要求,则返回DEBUG级别的指针
	LevelPtr pLevel = Level::toLevel(level);
        logger->setLevel(pLevel);
	return true;
}

void aLogger::trace(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_TRACE(logger, message);
}

void aLogger::debug(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_DEBUG(logger, message);
}

void aLogger::info(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_INFO(logger, message);
}

void aLogger::warn(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_WARN(logger, message);
}

void aLogger::error(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_ERROR(logger, message);
}

void aLogger::fatal(const char *format, ... )
{
	if (NULL == logger) return;

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	LOG4CXX_FATAL(logger, message);
}

void aLogger::forcelog(const log4cxx::LogString &level, const char *format, ... )
{
	if (NULL == logger) return;

	LevelPtr pLevel = Level::toLevel(level);

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	helpers::MessageBuffer oss_;
	logger->forcedLog(pLevel, oss_.str(oss_ << message), LOG4CXX_LOCATION);
}

void aLogger::assertlog(bool condition, const log4cxx::LogString &level, const char *format, ... )
{
	if (NULL == logger || !condition) return;

	LevelPtr pLevel = Level::toLevel(level);

	char message[_MSGBUF_MAX];
	va_list ArgList;
	va_start(ArgList, format);
	vsnprintf(message, sizeof(message), format, ArgList);
	va_end(ArgList);
	helpers::MessageBuffer oss_;
	logger->forcedLog(pLevel, oss_.str(oss_ << message), LOG4CXX_LOCATION);
}

四、测试程序

#include <unistd.h>
#include <map>
#include <cstdlib>
#include <memory>
#include "aLogger.h"

using namespace std;

map<string, string> argMap;

int main(int argc, char *argv[])
{
	int result = 0;
	opterr = 0;
	while ((result = getopt(argc, argv, "dl:")) != -1)
	{
		switch(result)
		{
			case ‘d‘:
			{
				argMap["daemon"] = "1";
				break;
			}
			case ‘l‘:
			{
				argMap["logPath"] = optarg;
				break;
			}
		}
	}
	auto_ptr<aLogger> logger(new aLogger("logicserver"));
	logger->setLevel("TRACE");
	if (atoi(argMap["daemon"].c_str()) == 1)
	{
		logger->removeConsoleLog();
		daemon(1, 1);
	}
	while (true)
        {
                logger->debug("定时测试, 字符串%s, 数字%d", "test", 123456789);
		logger->assertlog(1 == 1, "ERROR", "条件测试, 条件满足则输出 字符串%s", "test");
                sleep(1);
        }
	return 0;
}

说明:

a) daemon函数让程序后台运行

int daemon(int nochdir, int noclose);

参数:

当 nochdir为零时,当前目录变为根目录,否则不变;

当 noclose为零时,标准输入、标准输出和错误输出重导向为/dev/null,也就是不输出任何信 息,否则照样输出。

返回值:

deamon()调用了fork(),如果fork成功,那么父进程就调用_exit(2)退出,所以看到的错误信息 全部是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。

五、搭建编译环境

a)首先执行autoscan

[[email protected] test1]# autoscan 
[[email protected] test1]# ls
aLogger.cpp  aLogger.h  autoscan.log  configure.scan  main.cpp
[[email protected] test1]# mv configure.scan configure.in

b) 编辑configure.in文件

[[email protected] test1]# vim configure.in
AC_PREREQ([2.63])
AC_INIT([MyfirstPro], [1.0], [[email protected]])
AC_CONFIG_SRCDIR([aLogger.h])
AC_CONFIG_HEADERS([config.h])
#添加automake
AM_INIT_AUTOMAKE(MyfirstPro,1.0)

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
#添加libtool工具
AC_PROG_LIBTOOL
.
.
.

#修改这一行,输出Makefile
AC_OUTPUT(Makefile)

c) 运行autoheader,生成config.h.in文件

[[email protected] test1]# autoheader 
[[email protected] test1]# ls
aLogger.cpp  aLogger.h  autom4te.cache  autoscan.log  config.h.in  configure.in  main.cpp

d) 运行aclocal,生成aclocal.m4文件

[[email protected] test1]# aclocal
[[email protected] test1]# ls
aclocal.m4  aLogger.cpp  aLogger.h  autom4te.cache  autoscan.log  config.h.in  configure.in  main.cpp

e) 运行autoconf,生成configure脚本

[[email protected] test1]# autoconf 
[[email protected] test1]# ls
aclocal.m4  aLogger.cpp  aLogger.h  autom4te.cache  autoscan.log  config.h.in  configure  configure.in  main.cpp

f) 编写Makefile.am脚本

[[email protected] test1]# vim Makefile.am 
AUTOMAKE_OPTIONS = foreign
INCLUDES = -I/usr/include/log4cxx/
bin_PROGRAMS = firstPro
firstPro_SOURCES =                 aLogger.cpp                 main.cpp
firstPro_LDADD = /usr/local/log4cxx/lib/liblog4cxx.la
firstPro_LDFLAGS = -D_GNU_SOURCE
[[email protected] test1]# ls
aclocal.m4   aLogger.h       autoscan.log  configure     main.cpp
aLogger.cpp  autom4te.cache  config.h.in   configure.in  Makefile.am

g) 运行automake,生成Makefile.in

[[email protected] test1]# libtoolize
[[email protected] test1]# automake -a
[[email protected] test1]# ls
aclocal.m4   aLogger.h       autoscan.log  config.h.in  configure     depcomp     ltmain.sh  Makefile.am  missing
aLogger.cpp  autom4te.cache  config.guess  config.sub   configure.in  install-sh  main.cpp   Makefile.in

h) 执行./configure脚本,生成Makefile文件

[[email protected] test1]# ./configure 
#开始编译我们的程序
[[email protected] test1]# make 
(CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/sh /root/test1/missing --run autoheader)
rm -f stamp-h1
touch config.h.in
cd . && /bin/sh ./config.status config.h
config.status: creating config.h
make  all-am
make[1]: Entering directory `/root/test1‘
g++ -DHAVE_CONFIG_H -I. -I/usr/include/log4cxx/    -g -O2 -MT aLogger.o -MD -MP -MF .deps/aLogger.Tpo -c -o aLogger.o aLogger.cpp
mv -f .deps/aLogger.Tpo .deps/aLogger.Po
g++ -DHAVE_CONFIG_H -I. -I/usr/include/log4cxx/    -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.cpp
mv -f .deps/main.Tpo .deps/main.Po
/bin/sh ./libtool --tag=CXX   --mode=link g++  -g -O2 -D_GNU_SOURCE  -o firstPro aLogger.o main.o /usr/local/log4cxx/lib/liblog4cxx.la 
libtool: link: g++ -g -O2 -D_GNU_SOURCE -o firstPro aLogger.o main.o  /usr/local/log4cxx/lib/liblog4cxx.so -L/usr/local/apr/lib -L/usr/local/apr-util/lib /usr/local/apr-util/lib/libaprutil-1.so /usr/local/apr-util/lib/libexpat.so /usr/local/apr/lib/libapr-1.so -lrt -lcrypt -lpthread -pthread -Wl,-rpath -Wl,/usr/local/apr-util/lib -Wl,-rpath -Wl,/usr/local/apr/lib -Wl,-rpath -Wl,/usr/local/apr-util/lib -Wl,-rpath -Wl,/usr/local/apr/lib
make[1]: Leaving directory `/root/test1‘

#运行测试
[[email protected] test1]# ./firstPro 
20150719-09:23:32 logicserver DEBUG: 定时测试, 字符串test, 数字123456789
20150719-09:23:32 logicserver ERROR: 条件测试, 条件满足则输出 字符串test

六、动态编译和静态编译

动态编译的可执行文件需要附带一个的动态链接库,在执行时,需要调用其对应动态链接库中的命令。所以其优点一方面是缩小了执行文件本身的体积,另一方面是加快了编译速度,节省了系统资源。缺点一是哪怕是很简单的程序,只用到了链接库中的一两条命令,也需要附带一个相对庞大的链接库;二是如果其他计算机上没有安装对应的运行库,则用动态编译的可执行文件就不能运行。

静态编译就是编译器在编译可执行文件的时候,将可执行文件需要调用的对应动态链接库(.so)中的部分提取出来,链接到可执行文件中去,使可执行文件在运行的时候不依赖于动态链接库。所以其优缺点与动态编译的可执行文件正好互补。

a)动态编译

[[email protected] test1]# ldd firstPro 
	linux-vdso.so.1 =>  (0x00007fff0c7ff000)
	liblog4cxx.so.10 => /usr/local/log4cxx/lib/liblog4cxx.so.10 (0x00007f17d01a8000)
	libaprutil-1.so.0 => /usr/local/apr-util/lib/libaprutil-1.so.0 (0x00007f17cff82000)
	libexpat.so.0 => /usr/local/apr-util/lib/libexpat.so.0 (0x00007f17cfd5b000)
	libapr-1.so.0 => /usr/local/apr/lib/libapr-1.so.0 (0x00007f17cfb28000)
	librt.so.1 => /lib64/librt.so.1 (0x0000003c54200000)
	libcrypt.so.1 => /lib64/libcrypt.so.1 (0x0000003c5d600000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003c53600000)
	libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003c60a00000)
	libm.so.6 => /lib64/libm.so.6 (0x0000003c53e00000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003c5ee00000)
	libc.so.6 => /lib64/libc.so.6 (0x0000003c53200000)
	/lib64/ld-linux-x86-64.so.2 (0x0000003c52a00000)
	libfreebl3.so => /lib64/libfreebl3.so (0x0000003c5de00000)
	libdl.so.2 => /lib64/libdl.so.2 (0x0000003c52e00000)
[[email protected] test1]# du -sh firstPro 
316K	firstPro    #这个可执行文件的大小

从上面make编译时的输出,和这里的ldd的输出,我们可以确定,这个程序是动态链接,也就是这个程序运行的服务器上,必须安装了log4cxx的库才行。

[[email protected] ~]$ ./firstPro
./firstPro: error while loading shared libraries: liblog4cxx.so.10: cannot open shared object file: No such file or directory

b)修改la文件

[[email protected] test1]# vim /usr/local/log4cxx/lib/liblog4cxx.la 
[[email protected] test1]# vim /usr/local/apr/lib/libapr-1.la
[[email protected] test1]# vim /usr/local/apr-util/lib/libaprutil-1.la
[[email protected] test1]# vim /usr/local/apr-util/lib/libexpat.la 
#将这4个文件的dlname和library_names这2行注释掉

c)静态编译

[[email protected] test1]# make clean
[[email protected] test1]# make

#将文件大小和链接库和上面的对比下
[[email protected] test1]# du -sh firstPro 
12M	firstPro
[[email protected] test1]# ldd firstPro 
	linux-vdso.so.1 =>  (0x00007fffbb1ff000)
	librt.so.1 => /lib64/librt.so.1 (0x0000003c54200000)
	libcrypt.so.1 => /lib64/libcrypt.so.1 (0x0000003c5d600000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003c53600000)
	libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003c60a00000)
	libm.so.6 => /lib64/libm.so.6 (0x0000003c53e00000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003c5ee00000)
	libc.so.6 => /lib64/libc.so.6 (0x0000003c53200000)
	/lib64/ld-linux-x86-64.so.2 (0x0000003c52a00000)
	libfreebl3.so => /lib64/libfreebl3.so (0x0000003c5de00000)
	libdl.so.2 => /lib64/libdl.so.2 (0x0000003c52e00000)

这样就不需要链接log4cxx的库,可以在没有安装它的环境下运行。

#让程序在后台运行,并指定输出日志
[[email protected] ~]$ ./firstPro -d -l /log/out.log

这就是log4cxx简单的文本输出和控制台输出的类。

时间: 2024-10-18 09:31:51

log4cxx配置使用(二)的相关文章

zabbix基础配置(二)

zabbix基础配置(二) ============================================================================= 概述: ============================================================================= zabbix agent安装配置:  安装配置过程 1.安装 # yum install zabbix-agent-3.0.2-1.el7.x86_64

Linux之Web服务(2)Httpd服务配置之二

Linux之Web服务(2)Httpd服务配置之二 前言 在上一篇通过一些简单的案例或说明来介绍了部分关于Httpd2.4中httpd.conf配置文件中的配置选项及对应的功能.主要是对访问控制和在处理对指定目录或文件进行访问控制的一些安全问题性的处理.但是一直没有提到访问控制的具体讲解,本篇列出访问控制的具体使用选项和功能,以及其它高级配置. 1.Httpd2.4 文档访问授权具体参数 前提:文档访问授权选项配置只适合在以下标签中生效: <Directory >  <FIles>

linux杂谈(十九):DNS服务器的配置(二)

1.本机和外网的解析 ? ?之前讨论了DNS的正向解析和反向解析,但有的时候我们想让DNS服务器对于服务器本机的解析和对于外网的解析是不同的.那就需要在主配置文件中对本机和外网进行不同的配置: ? ? ? ? ? ?这个是主配置文件中对于本服务器的访问,并且副配置文件为example.com.zone:(注意要注释的内容). ? ? ? ?这个是对于非本机的配置,并且副配置文件为example.com.inter. ? ?为了统一期间,把之前的副配置文件的策略注释掉. ? ? ? ? ?然后我们

linux杂谈(十五):ftp的企业应用级的配置(二)

上篇最后我们讲到了匿名用户家目录的修改,今天来看看匿名用户还可以做什么操作. 1.匿名用户创建和删除目录 其实所有的功能都是上篇所列举的那些参数所控制的,通常大家在记不清的时候都可以查看man手册(man vsftpd.conf),里面列举了所有可以修改的参数.关于匿名用户创建和删除目录的参数如下所示: 把这两个参数设置为YES,匿名用户就可已创建目录了,记得每次修改完配置文件都要重新启动/etc/init.d/vsftpd服务. 发现还是无法创建,怎么回事?其实我们考虑问题一定要全面.虽然配置

DNS 配置篇二

一.子域配置 1.基本概念 子域的作用是在本地DNS下再划分一个小的(子)DNS.作用的方便集中管理, 不过问题是要配置转发.父DNS可以知道解析子DNS,子DNS 则只可以解析自己 本地记录,不能解析父DNS. 正向子域授权: 只需要在父域的区域解析库中添加"胶水记录", glue record 子域名称   IN  NS  子域的名称服务器 ops  IN   NS   ns.ops ops  IN   NS   ns2.ops ns.ops  IN  A       172.16

GoldenGate配置(二)之双向复制配置

 GoldenGate配置(二)之双向复制配置 环境: Item Source System Target System Platform Red Hat Enterprise Linux Server release 5.4 Red Hat Enterprise Linux Server release 5.4 Hostname gc1 gc2 Database Oracle 10.2.0.1 Oracle 11.2.0.1 Character Set ZHS16GBK ZHS16GBK OR

linux杂谈(十九):DNSserver的配置(二)

1.本机和外网的解析 ? ?之前讨论了DNS的正向解析和反向解析,但有的时候我们想让DNSserver对于server本机的解析和对于外网的解析是不同的.那就须要在主配置文件里对本机和外网进行不同的配置: ? ? ? ? ? ?这个是主配置文件里对于本server的訪问,而且副配置文件为example.com.zone:(注意要凝视的内容). ? ? ? ?这个是对于非本机的配置,而且副配置文件为example.com.inter. ? ?为了统一期间,把之前的副配置文件的策略凝视掉. ? ?

iOS xmpp协议实现聊天之openfire的服务端配置(二)

本篇主要说一下如何利用命令行来正确配置MySql. 首先打开终端: 1.为mysql起一个别名 alias mysql=/usr/local/mysql/bin/mysql 2.创建mysql的管理员  admin(后期登陆用到) alias mysqladmin=/usr/local/mysql/bin/mysqladmin 3.设置root账号密码 mysqladmin -u root password 初始密码 4.连接数据库 mysql -u root -p  (提示输入刚才的密码) 5

十、RD 虚拟主机配置(二)

十.RD 虚拟主机配置(二) 3. 创建ISCSI 共享卷 1. 登录ISCSI 服务器,打开服务器管理器文件和存储服务ISCSI,选择"新建iscsi虚拟磁盘",如图 2. 选择iscsi 虚拟磁盘位置,选择"下一步",如图 3. 设置iscsi 虚拟磁盘名称,描述信息,选择"下一步",如图 4. 设置iscsi 虚拟磁盘大小,如图 5. 在分配iscsi 目标对话框,选择"新建iscsi目标",如图 6. 在指定目标名称对