11

我正在编写一个旨在供其他库或可执行文件使用的 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。

4

6 回答 6

14

您可以提供一个回调机制,以允许库的用户为您的库提供一个适配器来记录他们的日志。

即,在您的库中提供一个抽象的日志接口类,例如:

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 类。他们的 Logger impl 将按照他们认为合适的方式实现日志记录。

这允许使用不同日志库的应用程序使用您的库。

请注意,上面的代码是基本的且未经测试的。在实践中,您可能希望更改日志方法以包含日志级别参数等。

于 2009-07-16T11:35:18.857 回答
2

在你的库中声明日志功能的原型:

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() );
}
于 2009-07-16T10:22:43.043 回答
1

使用log4cxxlog4cplus

于 2009-07-16T09:10:33.110 回答
0

如果您不想使用现有的日志库,可以尝试使用宏。我建议提供您自己的库,并使其与带有 printf 格式机制的宏一起使用。

我过去做过类似的事情。该宏称为日志对象,它封装了可以通过插件扩展的真实日志记录。

但我认为 Log4xxx 已经完成了类似的事情,所以也许看看它是件好事。

这是一个建议(抱歉没有时间测试,我希望它有效)

标题:

#ifdef _MYAPI_IMPL
#define MY_API __declspec(dllexport)
#别的
#define MY_API __declspec(dllimport)
#万一

MY_API 类日志
{
上市:
    枚举级别 {错误、警告、信息、调试};
    Log(Level level, const char* file, int line );
    void operator()(const char* 格式, ... );
私人的:
       const char* m_file;
       级别 m_level;
       诠释 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)

My_API 记录器类
{
上市:
    虚拟无效日志(常量字符*消息)=0;
};

MY_API LoggerManager 类
{
私人的:
    静态 LoggerManager* s_inst;
    记录器管理器() {}
        虚拟 ~LoggerManager() {}
上市:
    静态 LoggerManager* Instance();
    静态无效清洁();
    addLogger(Logger* newLogger, Log::Level minlevel = Log::Info);
        log(const char* file, int line, Log::Level level, const char* message);
};

价格:

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, 格式);
    字符消息[LENGTH+1]={0};

    _vsnprintf(消息,长度,格式,va);

    va_end(va);

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


};

其他库和 exe 应该能够像这样调用。他们只需要包含 .h 并与库链接。

LOG_INF("你好 %s!", "world");

更新:我添加了日志机制所需的解释。一种方法是使用单例并提供一个接口,以便为实际日志记录子类化。

使用宏的好处是它使您能够获取日志的位置,这在某些情况下可能是非常有趣的信息。当您不想实现所有日志记录机制时,也可以将宏转换为常规 printf。

于 2009-07-16T10:14:48.630 回答
0

您可以使用 google-glog。我觉得很好用。

https://github.com/google/glog

它支持每个文件的调试值,可以记录到系统日志,给你发电子邮件,以及许多其他不错的功能。

于 2009-07-16T10:20:56.573 回答
-1

syslog - 然后你可以让任何 syslog 工具使用它。

或允许用户指定回调。

于 2009-07-16T09:53:19.263 回答