我想在我的代码中记录不同的文件。
我如何使用xml配置在Log4cxx中执行此操作,或者在代码中以编程方式执行此操作...
更新
Logger.addAppender()方法:
log4cxx::helpers::Pool p;
std::string paramAppender = "appxNormalAppender";
std::string paramFileName = "\\Logs\\MyLog.txt";
LOG4CXX_DECODE_CHAR(logAppender, paramAppender );
LOG4CXX_DECODE_CHAR(logFileName, paramFileName );
FileAppenderPtr fileAppender =
logger->getLoggerRepository()->getRootLogger()->getAppender(logAppender);
if(fileAppender!= NULL)
{
fileAppender->setFile(logFileName);
fileAppender->activateOptions(p);
}
这不起作用,因为
假设我将FileName设置为Logger-k for k component,它会记录到 记录器-k,然后我将文件名设置为Logger-k + 1为compoent k + 1,然后是组件k, 和k + 1记录相同的loggerk + 1文件。似乎最后一个文件名覆盖或影响所有其他文件......
并且
所有组成部分1,... compoeent k,componentk + 1,.... 组件n在同一个应用程序中......
答案 0 :(得分:2)
正常创建每个记录器,然后为每个记录器通过Logger.addAppender()方法将FileAppender设置为所需的文件。
答案 1 :(得分:1)
您需要为记录器创建单独的appender。在我的示例中,我创建了 afile1 和 afile2 appenders。我还创建了两个记录器: my.logger1 和 my.logger2 。当您使用 my.logger1 时,它会记录到 mylog1 文件,当您使用 my.logger2 时,它会记录到 mylog2 文件。
这是我的 log.properties 文件:
log4cplus.appender.afile1.layout=log4cplus::PatternLayout
log4cplus.appender.afile1.layout.ConversionPattern=%d [ %c{1} ] [ %-5p ] %m%n
log4cplus.appender.afile1=log4cplus::RollingFileAppender
log4cplus.appender.afile1.File=mylog1.log
log4cplus.appender.afile1.MaxFileSize=5MB
log4cplus.appender.afile1.MaxBackupIndex=2
log4cplus.appender.afile2.layout=log4cplus::PatternLayout
log4cplus.appender.afile2.layout.ConversionPattern=%d [ %c{1} ] [ %-5p ] %m%n
log4cplus.appender.afile2=log4cplus::RollingFileAppender
log4cplus.appender.afile2.File=mylog2.log
log4cplus.appender.afile2.MaxFileSize=5MB
log4cplus.appender.afile2.MaxBackupIndex=2
log4cplus.logger.my.logger1=INHERIT, afile1
log4cplus.additivity.my.logger1=false
log4cplus.logger.my.logger2=INHERIT, afile2
log4cplus.additivity.my.logger2=false
这是一个示例程序:
example.cpp:
#include <iostream>
#include <log4cplus/logger.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/configurator.h>
#include <log4cplus/fileappender.h>
#define MYLOG1_INFO(logEvent) LOG4CPLUS_INFO (log4cplus::Logger::getInstance("my.logger1"), logEvent)
#define MYLOG2_INFO(logEvent) LOG4CPLUS_INFO (log4cplus::Logger::getInstance("my.logger2"), logEvent)
int main(int argc, char**argv)
{
try
{
log4cplus::PropertyConfigurator::doConfigure("log.properties");
}
catch( ... )
{
std::cerr<<"Exception occured while opening log.properties\n";
return -1;
}
MYLOG1_INFO("hello world!");
MYLOG2_INFO("hello world!");
return 0;
}
这是Makefile(我想我的log4cplus是在父目录中构建的):
CXXFLAGS+=-I$(abspath ../log4cplus-1.0.4/include)
all: example.o
$(CXX) $^ $(abspath ../log4cplus-1.0.4/src/.libs/liblog4cplus.a) -lpthread -o test
试试这个例子,您应该了解appender如何工作
Log4cplus主要类似于log4j。所以你可以阅读log4j的基本原理。 要获得课程名称,您必须访问log4cplus.sourceforge.net
关于日志格式。 log4cplus的文档仅在doxygen中可用。所以在这里你可以阅读formating in pattern layout
如果你想记录进程ID,那么你应该在你的布局转换模式中使用%i
例如:
...
log4cplus.appender.afile2.layout.ConversionPattern=[%i] %m%n
...
它将记录进程ID和消息
答案 2 :(得分:1)
对于动态组件,请尝试:
#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <log4cxx/Logger.h>
#include <log4cxx/LogManager.h>
#include <log4cxx/xml/domconfigurator.h>
#include <log4cxx/FileAppender.h>
#include <log4cxx/SimpleLayout.h>
#include <log4cxx/helpers/transcoder.h>
void func(int k) {
std::string strName = "Log." + boost::lexical_cast<std::string>(k);
log4cxx::LoggerPtr log = log4cxx::Logger::getLogger(strName);
LOG4CXX_DECODE_CHAR(fileName, strName + ".log");
log4cxx::FileAppenderPtr appender(new log4cxx::FileAppender(new log4cxx::SimpleLayout, fileName, false));
log->addAppender(appender);
LOG4CXX_INFO(log, strName);
log->removeAppender(appender);
}
int main(int argc, char * argv[]) {
log4cxx::xml::DOMConfigurator::configure("trace.xml");
if(log4cxx::Logger::getLogger("Log")->getAllAppenders().empty()) {
std::cout << "failed to config log4cxx" << std::endl;
return 1;
}
log4cxx::LoggerPtr log = log4cxx::Logger::getLogger("Log");
boost::thread_group threadGroup;
for(int k = 0; k != 3; ++k) {
threadGroup.create_thread(boost::bind(func, k));
}
threadGroup.join_all();
return 0;
}
使用简单的trace.xml
<?xml version="1.0" encoding="UTF-8" ?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.SimpleLayout"/>
</appender>
<root>
<level value="all"/>
</root>
<category name="Log">
<level value="INFO"/>
<appender-ref ref="ConsoleAppender"/>
</category>
</log4j:configuration>
答案 3 :(得分:0)
这是在对当前解决方案感到沮丧之后使用log4cxx中的类MDC
在线程上下文中进行动态日志记录的另一种解决方案。它基本上允许将instanceid
前缀添加到File
的{{1}}属性中。它要求在加载配置文件之前正确编译和定义自定义FileAppender
。与通常的旧log4cxx 0.10.0版本一起使用。可以与以下代码段一起使用:
FileAppender
可以与此属性配置文件一起使用:
#include <XFileAppender.h>
void PushInstance(const std::string &instanceid)
{
MDC::put("__ITRInstanceId", value);
}
void PopInstance()
{
MDC::remove("__ITRInstanceId");
}
int main()
{
{
auto logger = Logger::getLogger("Test1");
PushInstance("user1");
logger->log(log4cxx::Level::getInfo(), "Info");
PopInstance();
}
{
auto logger = Logger::getLogger("Test2");
PushInstance("user1");
logger->log(log4cxx::Level::getWarn(), "Warning");
PopInstance();
}
// Imagine "Test1" and "Test2" used from different
// threads acting as "user1"
// Following line will ensure writers will be closed when "user1"
// e.g. is logging out
XFileAppender::CloseIstanceWriters("instance1");
return 0;
}
XFileAppender标头:
# Default log filename. Can be overridden by system properties
LogFilename=File.log
# Appenders
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yyyy HH:mm:ss}] %-6p: %m%n
log4j.appender.USER=org.apache.log4j.XFileAppender
log4j.appender.USER.File=${LogFilename}
log4j.appender.USER.layout=org.apache.log4j.PatternLayout
log4j.appender.USER.layout.ConversionPattern=[%d{dd/MM/yyyy HH:mm:ss}] %-6p: %m%n
# Root
log4j.rootLogger=WARN, stdout
# Classes
log4j.logger.Test1=INFO, USER
log4j.additivity.Test1 = false
log4j.logger.Test2=INFO, USER
log4j.additivity.Test2 = false
XFileAppender源:
// Copyright (c) 2019 Francesco Pretto
// This file is subject to the Apache License Version 2.0
#pragma once
#include "libdefs.h"
#include <memory>
#include <unordered_map>
#include <mutex>
#include <log4cxx/fileappender.h>
namespace log4cxx
{
class ITR_LOGGING_SHARED_API XFileAppender : public FileAppender
{
private:
struct InstanceWriter
{
typedef std::shared_ptr<InstanceWriter> Ptr;
InstanceWriter(helpers::Pool& p);
helpers::Mutex Mutex;
helpers::WriterPtr Writer;
};
typedef std::unordered_map<LogString, XFileAppender *> AppenderIdentities;
public:
DECLARE_LOG4CXX_OBJECT(XFileAppender)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(XFileAppender)
LOG4CXX_CAST_ENTRY_CHAIN(FileAppender)
END_LOG4CXX_CAST_MAP()
XFileAppender();
public:
void close() override;
void append(const spi::LoggingEventPtr &event, helpers::Pool &p) override;
void activateOptions(helpers::Pool &p) override;
public:
/**
Clear all registered writers
NOTE: It doesn't close them. This is useful example when reloading configuration
*/
static void ClearWriters();
/**
Close all writers linked to instance
*/
static void CloseIstanceWriters(const LogString &instanceid);
private:
InstanceWriter::Ptr getInstanceWriter(helpers::Pool &p);
void CloseWriter(const LogString &istanceid);
void closeWriter(InstanceWriter &writer);
void closeWriter(helpers::Writer &writer);
void closeWriters();
helpers::WriterPtr createWriter(const LogString &instanceid, helpers::Pool& p);
helpers::WriterPtr createWriter(const File &file, helpers::Pool& p);
static void removeAppenderIstances(const LogString &appname, std::vector<LogString> &instanceIds);
private:
XFileAppender(const XFileAppender&);
XFileAppender& operator=(const XFileAppender&);
private:
static helpers::Mutex s_mutex;
static std::unordered_map<LogString, AppenderIdentities> s_appenderIdentities; // NOTE: Guarded by s_mutex
private:
bool m_failedWriter; // NOTE: Guarded by mutex
helpers::WriterPtr m_writer; // NOTE: Guarded by mutex
std::unordered_map<LogString, InstanceWriter::Ptr> m_instanceWriters; // NOTE: Guarded by mutex
}; // class XFileAppender
LOG4CXX_PTR_DEF(XFileAppender);
} // namespace log4cxx