简体   繁体   English

使用共享DLL进行日志记录的体系结构

[英]Architecture for logging with shared DLLs

I've been writing logging code for our product, and have an architectural problem. 我一直在为我们的产品编写日志记录代码,并且遇到体系结构问题。 We have two command-line executables, written in C++ for Window, call them Foo and Bar, that depend on a DLL which we'll name Core. 我们有两个用C ++为Window编写的命令行可执行文件,分别称为Foo和Bar,它们依赖于一个我们称为Core的DLL。 I want to log from within Core. 我想从Core内登录。

The question is, where should those log entries end up? 问题是,这些日志条目应该在哪里结束? If I run Foo, I want to see them in Foo.log, and if I run Bar, they should be in Bar.log. 如果我运行Foo,我想在Foo.log中看到它们,如果我运行Bar,它们应该在Bar.log中。 What if I run both Foo and Bar at the same time, what then? 如果我同时运行Foo和Bar,该怎么办? (I think I already sorted the case when multiple copies of Foo or Bar are run, effectively locking the log file). (我认为我已经整理了运行Foo或Bar的多个副本的情况,有效地锁定了日志文件)。

One thought is that Core can keep a list of "all the loggers I need to invoke when someone makes a logging request". 一种想法是Core可以保留“有人提出记录请求时我需要调用的所有记录器”的列表。 This implies there is a whole new API to write and that logging in DLLs is written different to logging in exes or static libraries. 这意味着要编写一个全新的API,并且DLL中的日志记录与exes或静态库中的日志记录不同。 That's not ideal. 那不理想。 I may not even know where the code ends up if it's in a lib! 如果它在lib中,我什至不知道代码在哪里结束!

I've looked at log4cplus, and boost logging but can't get any traction on how this would work with those components either, so am a bit stuck for ideas. 我已经看过log4cplus,可以增强日志记录功能,但是也无法了解如何将它们与这些组件一起使用,因此有些想法被卡住了。 This is surely a solved problem though?! 这肯定是一个已解决的问题吗?

Function pointers is the key, IMO. 功能指针是IMO的关键。

I usually implement loggers on the very top level, in the .exe code, and on startup I pass the function pointer all the way down. 我通常在.exe代码的最顶层实现记录器,并且在启动时始终将函数指针向下传递。 Here's an example. 这是一个例子。

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 );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM