【问题标题】:C++: logger design, line/function information as function argumentC++:记录器设计,行/函数信息作为函数参数
【发布时间】:2013-05-13 10:11:20
【问题描述】:

我的应用程序有一个简单的记录器。这是一个(简化的)界面:

class ILogger
{
public:

    virtual void LogUnsafe(const LogPriority& priority, const boost::format& message) = 0;

    virtual void Log(const LogPriority& priority, const boost::format& message)
    {
        if (priority <= logPriority_)
        {
            std::unique_lock<std::mutex> lock(loggerMutex_);
            LogUnsafe(priority, message);
        }
    }

    void Log(const LogPriority& priority, const std::string& message)
    {
        Log(priority, boost::format(message));
    }

    template<typename T, typename... Args>
    void Log(const LogPriority& priority, boost::format &format, const T &v, Args... args)
    {
        Log(priority, boost::format(format) % v, args ...);
    }

    template<typename... Args>
    void Log(const LogPriority& priority, const char *format, Args... args)
    {
        boost::format fmt(format);
        Log(priority, fmt, args ...);
    }
};

现在我需要(为了便于错误检测)在每条日志消息中包含行和功能信息(使用__LINE____FUNCTION__)。合理地它应该作为函数参数传递。而且,像往常一样,我不想在每次编写日志消息时都输入所有这些宏。所以我在这里遇到了麻烦。我怎样才能优雅地将它们传递给日志记录函数,而无需在每条日志消息中明确写入?

提前致谢。

【问题讨论】:

  • 由于 LINE 是一个宏,我认为唯一的方法是制作一个包含 LINE 宏的不同宏。
  • @olevegard,不知道这有什么帮助。您能否提供一个简短的例子来说明这个想法?
  • 您不应该使用“I”来标识您的界面。这是用户不需要知道的实现细节。

标签: c++ logging c++11


【解决方案1】:

我发现“最好”的方法是使用通过宏创建的日志对象,正如 Neil 上面解释的那样。它的“好”之处在于它封装了站点上所有可用的信息,因此可以将其传递给不同的记录器。例如,您可以拥有一个“记录器”链,通过网络将其发送到磁盘和系统监视器(如 Windows 事件日志)。然后,您还可以使用生产者-消费者日志线程来提高性能。

class LogEntry{

    LogEntry(const boost::format& traceMsg, const unsigned int lineNumber, const std::string& file){
        //set members
    }

    std::string print(){
        // Do print logic... 
    }

    // Getters... Allow the logger instance build its own log from the info.
}

然后使用宏:

#define LOG( format ) sendToLogQueue( LogEntry( format, __LINE__, std::string(__FILE__) ) );

【讨论】:

    【解决方案2】:

    传统方法是将您的日志调用包装在一个宏中,并且只在代码中使用该宏。

    例如

    #ifdef NDEBUG
    #define LOG(priority, message) \
       Log(priority,message)
    ...
    #else
    #define LOG(priority, message) \
       Log(priority, message, __FILE__, __LINE__)
    ...
    #endif
    
    void function()
    {
       LOG(PRI1, "Message");
    }
    

    然后总是使用 LOG 宏。

    【讨论】:

    • 注意:即使在发布模式下,也没有理由不包含__FILE____LINE__。它们可用!
    • 它们是可用的,但会占用额外的代码/数据空间。由于缺少 RAM,我们的嵌入式系统需要删除它们以进行发布/发布构建。每一点都有帮助:-)
    • 啊!这是一个非常特殊的需求,在服务器上工作时,我们保留它们(实际上将__func__ 添加到组合中)。
    • @Neil,听起来很合理。我们也在为嵌入式系统编写这段代码:)
    猜你喜欢
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多