【问题标题】:logger with file name, line and time stamp带有文件名、行和时间戳的记录器
【发布时间】:2013-02-28 11:46:07
【问题描述】:

我有一个自定义记录器类,它具有用于调试、信息等消息的不同方法。除了日志消息,我还想打印调用记录器方法的文件的名称和行,以及时间戳。

我现在的解决方案是这样的:

m_logger.debug("some debug message", __FILE__ , __LINE__, __TIME__);

问题:有没有办法避免调用__FILE____LINE____TIME__ 这两个宏并实现 somewho 自动调用?

谢谢。

【问题讨论】:

    标签: c++ logging


    【解决方案1】:

    大概是这样的:

    #define debug_with_ft(x) debug(x, __FILE__, __TIME__)
    
    ...
    m_logger.debug_with_ft("some debug message");
    

    当然,有多种不同的方法可以解决这个问题,例如在宏中隐藏整个m_logger

    #define debug_with_ft(x) m_logger.debug(x, __FILE__, __TIME__)
    

    【讨论】:

    • 正如 Laurent 所说,这不是 __TIME__ 的解决方案。虽然对于__FILE____LINE__ 这似乎是最好的解决方案。谢谢。
    • @ezdazuzena:这是一种自动调用__FILE____LINE____TIME__中的任何一个或全部的解决方案。 __TIME__ 的问题不是您真正想要的,但这将是一个完全独立的问题。一个你没有问的。
    • 它会起作用,但我认为使用硬编码的宏魔法迟早会遇到麻烦。当调用签名、方法名称或任何相关内容发生变化时,这将是一个相当大的 PIA。
    • 好吧,我不知道当你问 TIME 时,你的意思实际上与 TIME 完全不同,对吗?显然,您也可以添加时间戳,作为日志记录类的 debug() 成员函数的一部分,或者在宏中,这就是您想要的。您可能必须编写一个函数来调用某个函数来确定现在是几点并将时间格式化为您可以打印的内容。但这肯定是可行的。
    【解决方案2】:

    __TIME__ 是一个预处理器宏,它将在编译时生成当前时间。因此,它不应该在您的情况下使用,因为您可能希望在运行时(记录消息时)访问当前时间。

    __FILE__ 也是一个预处理器宏,必须在预编译时进行评估,不能以其他方式实现。

    您可能还对__LINE__ 宏感兴趣

    【讨论】:

    • 谢谢,我实际上忘记了`__LINE__ 宏。
    【解决方案3】:

    这是宏正确解决方案的一种情况。你 想要使用宏调用您的记录器(因为只有宏可以 自动插入__FILE____LINE__),并且您想要 以允许客户端代码传递一个或多个的方式这样做 消息元素,可能使用<<。通常的做法 这类似于:

    #define LOG() m_logger.getStream( __FILE__, __LINE__ )
    

    m_logger.getStream 插入标题(使用它的 参数和当前时间),并返回一个引用 到日志流,或者一个特殊的包装类,它也 实现<<——只返回对流的引用是 最简单的,但是使用包装器可以捕获 消息(因为包装器是临时的,它将是 在完整表达式的末尾销毁),释放锁 采用getStream(以便日志记录是线程安全的),或者 确保输出是原子的,如果 << 包装器是 类似:

    template <typename T>
    LogStream& LogStream::operator<<( T const& object )
    {
        if ( myStream != NULL ) {
            *myStream << object;
        }
    }
    

    ,您可以禁用日志记录,并且在以下情况下不会进行任何转换 它被禁用了。

    【讨论】:

      【解决方案4】:

      为什么你认为__FILE____TIME__ 不好?我不确定它们本身是否真的是宏。它们是所谓的宏名称。我也认为它们是由标准定义的,因此使用它们应该是安全且可以的。

      在旁注中,您似乎错过了编译时评估和运行时评估的概念。

      在运行时如何知道源文件的名称?这就是为什么你应该使用__FILE__,因为编译器会为你评估文件名。

      相反__TIME__ 也是编译器替换的宏名。您想记录编译或调用该行的时间吗?如果是后者,您应该使用适当的运行时函数。

      我认为没有任何可能绕过__FILE__

      但是,如果您只想缩短通话时间

      我使用以下 sn-p:

      #ifndef NDEBUG
      #define DEBUG_MSG(msg) do{ std::cerr << __FILE__ << "(@" << __LINE__ << "): " << msg << '\n'; } while( false )
      #else
      #define DEBUG_MSG(msg) do{ } while ( false )
      #endif
      

      我发现它非常便携且易于使用,但它并不打算用作类方法。 您可能可以将其定义为类似

      #define DEBUG_MSG(msg) debug( msg, __FILE__, __LINE__ )
      

      并像使用一样

      m_logger.DEBUG_MSG("message");
      

      因此宏将扩展为设计的函数调用。然而,这是相当冒险的。 如果您更改debug 签名,则需要更改宏,并且它很难移植。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-04
        • 2012-05-07
        • 1970-01-01
        • 2018-01-10
        • 2018-02-07
        • 1970-01-01
        相关资源
        最近更新 更多