Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何添加日志,以便在需要时轻松打开,并在不增加生产开销的情况下关闭?_C++ - Fatal编程技术网

C++ 如何添加日志,以便在需要时轻松打开,并在不增加生产开销的情况下关闭?

C++ 如何添加日志,以便在需要时轻松打开,并在不增加生产开销的情况下关闭?,c++,C++,在我的C#项目中,我喜欢使用ConditionalAttribute,并发现它非常有用。我有很多用于日志记录的类,只要使用相应的条件属性set或unset重新编译,我就可以打开或关闭日志记录(没有开销) 如何对C++有同样的效果?我应该用类似的东西吗?可能现有的一些日志库具有相同的功能,可能是boost?谢谢 您可以使用预处理器: #ifdef ENABLE_LOGGING void log(const std::string& message) { /* do logging*/}

在我的C#项目中,我喜欢使用
ConditionalAttribute
,并发现它非常有用。我有很多用于日志记录的类,只要使用相应的条件属性set或unset重新编译,我就可以打开或关闭日志记录(没有开销)


如何对C++有同样的效果?我应该用类似的东西吗?可能现有的一些日志库具有相同的功能,可能是
boost
?谢谢

您可以使用预处理器:

#ifdef ENABLE_LOGGING
  void log(const std::string& message) { /* do logging*/}
#else
  void log(const std::string&){}
#endif

您也可以对模板执行类似的操作,但为什么会使事情过于复杂?

您可以使用预处理器:

#ifdef ENABLE_LOGGING
  void log(const std::string& message) { /* do logging*/}
#else
  void log(const std::string&){}
#endif

您也可以对模板执行类似的操作,但为什么要过度复杂呢?

我建议您看看如何提供
TRACE/ATLTRACE
和类似的宏(如果我是正确的,您使用的是Visual Studio)。一般来说,它们归结为在调试构建中有跟踪调用,在发布构建中没有操作。以下是一个例子:

struct CTrace
{
    static void CTrace::Trace(LPCTSTR lpszFormat, ...)
    {
        va_list args;
        va_start(args, lpszFormat);
        TCHAR szBuffer[1024];
        int nSize = sizeof(szBuffer)/sizeof(szBuffer[0]);
        int nBuf = _vsntprintf(szBuffer, nSize, lpszFormat, args);          
        OutputDebugString(szBuffer); // write to debug output
        va_end(args);
    }    
};

#ifdef _DEBUG   
#define TRACE               CTrace::Trace
#else  
#define TRACE               true ? (void)0 : CTrace::Trace
#endif // _DEBUG
然后在代码中有如下内容:

TRACE("value is %d", 34);
在调试生成中,这将被编译为:

CTrace::Trace("value is %d", 34);
在版本构建中,它转向:

true ? (void)0 : CTrace::Trace("value is %d", 34);

然后由编译器对其进行优化。您可以通过检查生成的代码来验证它。

我建议您看看如何提供
TRACE/ATLTRACE
和类似的宏(如果我是正确的,您使用的是Visual Studio)。一般来说,它们归结为在调试构建中有跟踪调用,在发布构建中没有操作。以下是一个例子:

struct CTrace
{
    static void CTrace::Trace(LPCTSTR lpszFormat, ...)
    {
        va_list args;
        va_start(args, lpszFormat);
        TCHAR szBuffer[1024];
        int nSize = sizeof(szBuffer)/sizeof(szBuffer[0]);
        int nBuf = _vsntprintf(szBuffer, nSize, lpszFormat, args);          
        OutputDebugString(szBuffer); // write to debug output
        va_end(args);
    }    
};

#ifdef _DEBUG   
#define TRACE               CTrace::Trace
#else  
#define TRACE               true ? (void)0 : CTrace::Trace
#endif // _DEBUG
然后在代码中有如下内容:

TRACE("value is %d", 34);
在调试生成中,这将被编译为:

CTrace::Trace("value is %d", 34);
在版本构建中,它转向:

true ? (void)0 : CTrace::Trace("value is %d", 34);


然后由编译器对其进行优化。您可以通过检查生成的代码来验证它。

预处理器指令(
#ifdef
#ifndef
)?重新编译并不意味着您可以轻松激活日志,轻松激活日志,意味着在系统启动和运行且您无法访问任何开发工具时激活日志,比如编译器…@user1708860我不需要简单的激活。当注销时,我不需要开销。就像我说的那样。使用日志2。编写低延迟代码。3.仅在调试和故障排除时才需要日志。预处理器指令(
#ifdef
#ifndef
)?重新编译并不意味着您可以轻松激活日志,轻松激活日志,意味着在系统启动和运行且您无法访问任何开发工具时激活日志,比如编译器…@user1708860我不需要简单的激活。当注销时,我不需要开销。就像我说的那样。使用日志2。编写低延迟代码。3.只需要日志进行调试和故障排除。您确定编译器将进行优化,并且不会添加其他不起任何作用的方法调用吗?禁用日志记录时不需要任何开销。@javapowered:这完全取决于您如何实现它。上面我所展示的内容确保了
log
函数的整个实现在调用站点上是可见的(如果您在头中这样做的话),然后编译器内联并优化是很简单的。如果您将其保存在.cpp文件中,它可能会被优化,也可能不会被优化,这取决于编译器标志。您还可以在需要记录时调用宏:
#define log(x)/*do actual logging*/
,然后在需要禁用日志时重新定义它,使其不做任何事情。那个么你们就可以保证它不会有任何效果。你们确定编译器会进行优化,不会添加额外的方法调用,而这些调用什么都不做吗?禁用日志记录时不需要任何开销。@javapowered:这完全取决于您如何实现它。上面我所展示的内容确保了
log
函数的整个实现在调用站点上是可见的(如果您在头中这样做的话),然后编译器内联并优化是很简单的。如果您将其保存在.cpp文件中,它可能会被优化,也可能不会被优化,这取决于编译器标志。您还可以在需要记录时调用宏:
#define log(x)/*do actual logging*/
,然后在需要禁用日志时重新定义它,使其不做任何事情。那么你可以保证它不会有任何效果。我真的应该使用这种c风格的宏吗?probaly boost日志库或其他日志库可以为我做到这一点?我想你应该这么做。我可能错了,但是其他日志库提供了在发布版本中删除日志的功能(因此更像是调试跟踪,然后是在发布版本中也应该启用的真实日志记录),它们也依赖于宏。e、 g.boost log(它不是boost的一部分)有boost_log_琐碎的宏。我最初的问题支持几个文件。我可以创建任意数量的
StreamWriter
,并写入任意数量的文件。您的版本只打印到一个目标。不,您的初始问题不支持多个文件,您的代码示例支持。您的问题只是要求打开/关闭日志记录,而不是支持多个文件,所以我已经回答了您的问题。实际上,您是向流而不是文件写入的,所以我不确定我的示例是否也应该考虑到这一点。不幸的是,我无法猜测您必须提供满足所有需求的精确实现的所有需求,因此我将其留给读者作为练习。请随意扩展
CTrace::Trace
实现以满足您的需要。我会使用NLog/Log4Net,我真的应该使用这种c风格的宏吗?probaly boost日志库或其他日志库可以为我做到这一点?我想你应该这么做。我可能错了,但是其他日志库提供了在发布版本中删除日志的功能(因此更像是调试跟踪,然后是在发布版本中也应该启用的真实日志记录),它们也依赖于宏。e、 g.boost log(它不是boost的一部分)有boost_log_琐碎的宏。我最初的问题支持几个文件。我可以创建尽可能多的
StreamWriter