重定向
关于如何重定向std::clog (std::wclog),Konrad Rudolph 的回答很好。
其他答案告诉您各种可能性,例如使用命令行重定向,例如2>output.log。使用 Unix,您还可以创建一个文件并将另一个输出添加到您的命令中,例如 3>output.log。然后,在您的程序中,您必须使用 fd 数字 3 来打印日志。您可以继续正常打印到stdout和stderr。 Visual Studio IDE 的 CDebug 命令具有类似的功能,该命令将其输出发送到 IDE 输出窗口。
stderr和stdout一样吗?
这通常是正确的,但在 Unix 下,您可以将 stderr 设置为 /dev/console,这意味着它会转到另一个 tty(也称为终端)。这些天很少使用它。我在 IRIX 上就是这样。我会打开一个单独的 X-Window 并查看其中的错误。
还有很多人向/dev/null 发送错误消息。在你写的命令行上:
command ...args... 2>/dev/null
系统日志
还有一点没有提到,在 Unix 下,你也有syslog()。
Linux 下的最新版本(可能还有 Mac OS/X)的功能比以前要多得多。特别是,它可以使用标识和其他一些参数将日志重定向到特定文件(即mail.log)。 syslog 机制可以在计算机之间使用,因此计算机 A 的日志可以发送到计算机 B。当然您可以通过各种方式过滤日志,尤其是按严重性。
syslog() 使用起来也很简单:
syslog(LOG_ERR, "message #%d", count++);
它提供 8 个级别(或严重性)、一个格式为 printf(),以及该格式的参数列表。
如果您第一次调用openlog() 函数,您可能会以编程方式进行一些调整。您必须在第一次调用 syslog() 之前调用它。
正如 unixman83 所提到的,您可能希望使用宏来代替。这样,您可以在消息中包含一些参数,而无需一遍又一遍地重复它们。也许是这样的(见Variadic Macro):
// (not tested... requires msg to be a string literal)
#define LOG(lvl, msg, ...) \
syslog(lvl, msg " (in " __FILE__ ":%d)", __VA_ARGS__, __LINE__)
您可能还会发现__func__ 很有用。
重定向、过滤等是通过创建配置文件来完成的。这是我的 snapwebsites 项目中的an example:
mail.err /var/log/mail/mail.err
mail.* /var/log/mail/mail.log
& stop
我在/etc/rsyslog.d/下安装文件并运行:
invoke-rc.d rsyslog restart
因此syslog 服务器会处理该更改并将所有与邮件相关的日志保存到这些文件夹中。
注意:我还必须创建/var/log/mail 文件夹和文件夹内的文件,以确保一切正常(否则邮件守护进程可能没有足够的权限。) p>
snaplogger(一个小插件)
我使用过log4cplus,从 1.2.x 版本开始,它非常好。不过,我有三个缺点:
- 如果我想调用
fork();,它需要我完全清除所有内容
- 配置文件 (
.properties) 在我的环境中不容易管理,我喜欢管理员在不修改原始文件的情况下进行更改
- 它使用 C++03,我们现在是 2019 年...我希望至少有 C++11
正因为如此,特别是因为第 (1) 点,我编写了自己的版本,名为 snaplogger。不过,这并不完全是一个独立的项目。我使用 snapcpp 环境中的许多其他项目(获取 snapcpp 并运行 bin/build-snap 脚本或仅运行 get the binaries from launchpad 会容易得多。)
使用 snaplogger 或 log4cplus 等记录器的优势在于,您通常可以定义任意数量的目标和许多其他参数(例如 syslog() 提供的严重级别)。 log4cplus 能够将其输出发送到许多不同的地方:文件、系统日志、MS-Windows 日志系统、控制台、服务器等。查看这两个项目中的附加程序以了解可能性列表。这里有趣的因素是任何日志都可以发送到所有目的地。这对于有一个名为 all.log 的文件很有用,所有服务都在其中发送它们的日志。这有助于理解某些在并行运行多个服务时使用单独的日志文件不容易发生的错误。
这是 snaplogger 配置文件中的一个简单示例:
[all]
type=file
lock=true
filename=/var/log/snapwebsites/all.log
[file]
lock=false
filename=/var/log/snapwebsites/firewall.log
请注意,对于all.log 文件,我需要一个锁,这样多个写入者就不会在彼此之间破坏日志。 [file] 部分没有必要,因为我只有一个进程(没有线程)。
两者都为您提供了一种添加自己的附加程序的方法。因此,例如,如果您有一个带有输出窗口的 Qt 应用程序,您可以编写一个附加程序来将 SNAP_LOG_ERROR() 调用的输出发送到该窗口。
snaplogger 还为您提供了一种方法来扩展消息中的变量支持(也称为格式)。例如,我可以使用${date} 变量插入日期。然后我可以用一个参数来调整它。为了只输出年份,我使用${date:year}。这种可变参数支持也是可扩展的。
snaplogger 可以按严重性(如系统日志)、正则表达式和组件过滤输出。我们有一个normal 和一个secure 组件,默认是normal。我希望将发送到secure 组件的日志写入安全文件。这意味着在一个子目录中,它比大多数管理员可以查看的普通日志受到更多保护。当我运行我的 HTTP 服务时,有时我会发送诸如信用卡的最后 3 位数字之类的信息。我更喜欢将它们保存在安全日志中。也可能是与密码相关的错误。任何我认为在日志中存在安全风险的东西,真的。同样,组件是可扩展的,因此您可以拥有自己的组件。