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