Добавление общей поддержки ведения журнала в общей библиотеке C ++ - PullRequest
8 голосов
/ 16 июля 2009

Я пишу разделяемую библиотеку c ++, которая предназначена для использования другой библиотекой или исполняемым файлом. Каков наилучший способ добавить общий журнал в моей библиотеке? В идеале я хотел бы адаптировать мою библиотеку к функциям регистрации, выбранным пользователем библиотеки. Предположим, у меня есть класс в моей библиотеке

class A {
  public: 
  void method(string param1, int param2);
}   

void A::method(string param1, int param2){
  /* i want to log values of param1 and param2, 
     but actual logging method must be defined outside of my library. 
     Maybe some kind of macro should help here. */ 
   /*e.g.*/  GENERICLOG_DEBUG("param1=" + param1+ " param2="+param1);
   /*if so, what that macro body should look like ? */
}

Я не хочу привязывать свою библиотеку к какому-либо определенному log4XXX API.

Ответы [ 6 ]

10 голосов
/ 16 июля 2009

Вы можете предоставить механизм обратного вызова, чтобы пользователь библиотеки мог предоставить вашей библиотеке адаптер для их регистрации.

Т.е., в вашей библиотеке предоставьте абстрактный интерфейс интерфейса ведения журнала, например ::100100

class Logger
{
public:
    virtual ~Logger () {}
    virtual void log (const std::string& message) = 0;
};

и класс для регистрации Logger:

class Log
{
private:
    static Logger* logger_;
public:
    static void registerLogger (Logger& logger)
    { logger_ = &logger; }

    static void log (const std::string& message)
    { if (logger_ != 0) logger_->log (message); }
};

Затем ваша библиотека регистрирует что-то вроде:

Log::log ("My log message");

Приложение, использующее вашу библиотеку, должно предоставить реализацию Logger (т.е. конкретный подкласс) и зарегистрировать ее в вашем классе Log. Их логгеры будут осуществлять регистрацию по своему усмотрению.

Это позволяет вашей библиотеке использоваться приложениями, которые используют разные библиотеки журналов.

Обратите внимание, что приведенный выше код является базовым и непроверенным. На практике вы можете изменить методы ведения журнала, включив в них параметр уровня ведения журнала и т. Д.

2 голосов
/ 16 июля 2009

Использование log4cxx или log4cplus .

1 голос
/ 16 июля 2009

Объявите прототип функции ведения журнала в вашей библиотеке:

extern void __cdecl UserLog(char* stText);

Не используйте его в своей библиотеке. Пользователь вашей библиотеки должен реализовать эту функцию, а ваша библиотека будет использовать реализацию пользователя.

Реализация пользователя может выглядеть следующим образом (это всего лишь пример):

void __cdecl UserLog(char* stText)
{
  std::cout << stText << std::endl;
}

Это действительно, если ваша библиотека статическая.

В своем коде вы сможете использовать следующим образом:

class A {
  public: 
  void method(string param1, int param2);
}   

void A::method(string param1, int param2){
   string formatted = str( boost::format( "param1=%s param2=%d" ) % param1 % param2 );
   UserLog( formatted.c_str() );
}
1 голос
/ 16 июля 2009

Вы можете использовать google-glog. Я нахожу это полезным для использования.

https://github.com/google/glog

Он поддерживает отладочные значения для каждого файла, может входить в системный журнал, отправлять вам электронные письма и загружать другие полезные функции.

0 голосов
/ 16 июля 2009

Если вы не хотите использовать существующую библиотеку журналов, вы можете попробовать использовать макросы. Я бы порекомендовал предоставить свою собственную библиотеку и сделать ее доступной с макросами с механизмом форматирования типа printf.

Я делал что-то подобное в прошлом. Макрос вызвал объект журнала, который инкапсулирует реальное ведение журнала, которое можно было расширить с помощью плагина.

Но я думаю, что что-то подобное уже сделано Log4xxx, так что, возможно, стоит посмотреть на это.

Вот предложение (извините, нет времени для тестирования, я надеюсь, что оно работает)

Заголовок:

#ifdef _MYAPI_IMPL
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif

class MY_API Log
{
public:
    enum Level {Error, Warning, Info, Debug};
    Log(Level level, const char* file, int line );
    void operator()(const char* Format, ... );
private:
       const char* m_file;
       Level m_level;
       int m_line;
};

#define __LOG(lvl) (Log(lvl, __FILE__, __LINE__ ))

#define LOG_ERR  __LOG(Log::Error)
#define LOG_WRN  __LOG(Log::Warning)
#define LOG_INF  __LOG(Log::Info)
#define LOG_DBG  __LOG(Log::Debug)

class My_API Logger
{
public:
    virtual void log(const char* message)=0;
};

class MY_API LoggerManager
{
private:
    static LoggerManager* s_inst;
    LoggerManager() {}
        virtual ~LoggerManager() {}
public:
    static LoggerManager* Instance();
    static void Clean();
    addLogger(Logger* newLogger, Log::Level minlevel = Log::Info);
        log(const char* file, int line, Log::Level level, const char* message);
};

Cpp:


Log::Log(Level level, const char* file, int line)
 : m_file(file), m_level(level), m_line(line)
{
}

void Log::operator()(const char* format, ... )
{
    va_list va;
    va_start(va, format);
    char message[LENGTH+1]={0};

    _vsnprintf(message, LENGTH, format, va);

    va_end(va);

    LoggerManager::Instance()->log(m_file, m_line, m_level, message);


};

Другие libs и exe должны быть в состоянии звонить так. Они просто должны включить .h и ссылку на библиотеку.

LOG_INF("Hello %s!", "world");

Обновление: я добавил объяснение, необходимое для механизма регистрации. Одним из способов является использование синглтона и предоставление интерфейса, который будет разделен на подклассы для фактической регистрации.

Преимущество использования макросов заключается в том, что они дают вам возможность найти местоположение журнала, что может быть очень интересной информацией в некоторых случаях. Также возможно превратить макросы в обычный printf, если вы не хотите реализовывать весь механизм ведения журнала.

0 голосов
/ 16 июля 2009

syslog - тогда вы можете использовать любое средство системного журнала.

или разрешить пользователю указать обратный вызов.

...