Архитектура для ведения журнала с помощью общих DLL - PullRequest
0 голосов
/ 14 мая 2019

Я писал код для нашего продукта, и у меня возникла архитектурная проблема.У нас есть два исполняемых файла командной строки, написанные на C ++ для Window, называющие их Foo и Bar, которые зависят от DLL, которую мы назовем Core.Я хочу войти изнутри Core.

Вопрос в том, где эти записи должны заканчиваться?Если я запускаю Foo, я хочу видеть их в Foo.log, а если я запускаю Bar, они должны быть в Bar.log.Что если я запустил Foo и Bar одновременно, что тогда?(Я думаю, что я уже отсортировал случай, когда запущено несколько копий Foo или Bar, эффективно блокируя файл журнала).

Одна мысль состоит в том, что Core может хранить список «всех регистраторов, которые мне нужно вызывать, когдакто-то делает запрос на регистрацию ".Это подразумевает, что существует совершенно новый API для записи, и что регистрация в DLL записывается иначе, чем в exe или статических библиотеках.Это не идеально.Возможно, я даже не знаю, где заканчивается код, если он находится в lib!

Я смотрел на log4cplus и ускорял ведение журнала, но не могу понять, как это будет работать с этими компонентами, поэтомуЯ немного застрял на идеях.Это, безусловно, решенная проблема, хотя?!

1 Ответ

0 голосов
/ 14 мая 2019

Функциональные указатели - это ключ, 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 );
}
...