我一直在为我们的产品编写日志记录代码,但遇到体系结构问题。我们有两个用C ++为Window编写的命令行可执行文件,分别称为Foo和Bar,它们依赖于一个我们称为Core的DLL。我想从Core内登录。
问题是,这些日志条目应该在哪里结束?如果我运行Foo,我想在Foo.log中看到它们,如果我运行Bar,它们应该在Bar.log中。如果我同时运行Foo和Bar,该怎么办? (我认为我已经整理了运行Foo或Bar的多个副本的情况,有效地锁定了日志文件。)
一个想法是,Core可以保留“当有人发出记录请求时我需要调用的所有记录器”的列表。这意味着要编写一个全新的API,并且DLL中的日志记录与exes或静态库中的日志记录不同。那不理想。如果它在lib中,我什至不知道代码在哪里结束!
我已经研究过log4cplus,并增强了日志记录功能,但是对于如何将其与这些组件结合使用也没有任何吸引力,因此有些想法被困住了。这当然可以解决吗?!
答案 0 :(得分:-1)
功能指针是IMO的关键。
我通常在.exe代码的最顶层实现记录器,而在启动时,我会一直向下传递函数指针。这是一个例子。
enum struct eLogLevel : uint8_t
{
Error,
Warning,
Info,
Debug
};
// C function pointer to write messages to arbitrary destination. Messages are better to be UTF8.
using pfnLogMessage = void( *)( eLogLevel lvl, const char* msg );
// DLL API, call this once, immediately after loading your DLL. Keep the level + function pointer in static variables.
// Unless messing with DLL segments, static variables are per-process, i.e. two processes will have different copy of these variables.
// Good idea to also call on shutdown, passing nullptr, before closing the underlying implementation stream.
void initializeLogging( eLogLevel maxLevelToLog, pfnLogMessage fnLogMessage );
// Invoke that function pointer to actually log stuff.
void logMessage( eLogLevel lvl, const CStringA& msg );
// Convenience wrappers to format and write various messages.
// Moar examples: https://github.com/Const-me/vis_avs_dx/blob/master/avs_dx/DxVisuals/Utils/logger.h
inline void logMessageV( eLogLevel lvl, const char* pszFormat, va_list args )
{
CStringA str;
str.FormatV( pszFormat, args );
logMessage( lvl, str );
}
#define LOG_MESSAGE_FORMAT( lvl ) va_list args; va_start( args, pszFormat ); logMessageV( lvl, pszFormat, args ); va_end( args );
inline void logError( const char* pszFormat, ... )
{
LOG_MESSAGE_FORMAT( eLogLevel::Error );
}