堵塞有什么意义?

时间:2008-09-09 17:08:48

标签: c++ logging log4cpp

我一直在想,堵塞的重点是什么?就像我所知,clog和cerr一样,但是有了缓冲,所以效率更高。通常stderr与stdout相同,因此clog与cout相同。这对我来说似乎很蹩脚,所以我认为我必须误解它。如果我将消息发送到同一个地方,我会收到错误信息(可能是/ var / log / messages中的内容),那么我可能不会写太多(因此使用非 - 缓冲的cerr)。根据我的经验,我希望我的日志消息是最新的(不缓冲)所以我可以帮助找到崩溃(所以我不想使用缓冲的阻塞)。显然我应该一直使用cerr。

我希望能够在我的程序中重定向阻塞。重定向cerr会很有用,这样当我调用库例程时,我可以控制cerr和clog的去向。有些编译器可以支持吗?我刚检查了DJGPP,stdout被定义为FILE结构的地址,因此执行“stdout = freopen(...)”之类的操作是违法的。

  • 是否可以重定向clog,cerr,cout,stdin,stdout和/或stderr?
  • clog和cerr缓冲之间的唯一区别是什么?
  • 我应该如何实施(或找到)更强大的日志工具(请链接)?

6 个答案:

答案 0 :(得分:35)

  

是否可以重定向clog,cerr,cout,stdin,stdout和/或stderr?

是。您需要rdbuf功能。

ofstream ofs("logfile");
cout.rdbuf(ofs.rdbuf());
cout << "Goes to file." << endl;
  

clog和cerr缓冲之间的唯一区别是什么?

据我所知,是的。

答案 1 :(得分:14)

如果你在posix shell环境中(我真的在考虑bash),你可以重定向任何一个 文件描述符到任何其他文件描述符,所以要重定向,你可以只是:

$ myprogram 2>&5 

将stderr重定向到fd = 5表示的文件。

编辑:第二个想法,我更喜欢@Konrad Rudolph关于重定向的答案。 rdbuf()是一种更加连贯和便携的方式。

至于日志记录,那么......我从Boost库开始,了解所有不在std库中的C ++。看哪:Boost Logging v2

编辑:Boost日志记录不是 Boost Libraries的一部分;它已经过审核,但未被接受。

编辑:2年后,早在2010年5月,Boost确实接受了一个名为Boost.Log的日志记录库。

当然,还有其他选择:

  • Log4Cpp(适用于C ++的log4j样式API)
  • Log4Cxx(Apache赞助的log4j样式API)
  • Pantheios(已解散?上次我尝试过我无法在最近的编译器上构建它)
  • Google's GLog(帽子@SuperElectric)

还有Windows事件记录器。

还有一些可能有用的文章:

答案 2 :(得分:2)

关于重定向器类的一点要点。它需要被正确销毁,并且只能销毁一次。析构函数将确保如果在函数中声明的函数实际返回并且该对象本身从未被复制,则将发生这种情况。

为确保无法复制,请提供私有复制和赋值运算符:

class redirecter
{
public:
    redirecter(std::ostream & src, std::ostream & dst)
        : src_(src), sbuf(src.rdbuf(dst.rdbuf())) {}
    ~redirecter() { src.rdbuf(sbuf); }
private:
    std::ostream & src_;
    std::streambuf * const sbuf_;
    // Prevent copying.                        
    redirecter( const redirecter& );
    redirecter& operator=( const redirecter& );
};

我通过将std :: clog重定向到main()中的日志文件来使用此技术。为确保main()实际返回,我将main()的内胆放置在try / catch块中。然后,在程序的其他地方(可能调用exit()),我抛出了异常。这会将控制权返回给main(),然后可以执行return语句。

答案 3 :(得分:1)

重定向

关于如何重定向std::clogstd::wclog),Konrad Rudolph的回答很好。

其他答案告诉您各种可能性,例如使用命令行重定向,例如2>output.log。在Unix中,您还可以创建一个文件,并使用诸如3>output.log之类的东西向命令添加另一个输出。然后,在程序中,您必须使用数字fd 3来打印日志。您可以继续正常打印到stdoutstderr。 Visual Studio IDE的CDebug命令具有类似的功能,该命令会将其输出发送到IDE输出窗口。

  

stderrstdout一样吗?

这通常是正确的,但是在Unix下,您可以将stderr设置为/dev/console,这意味着它会转到另一个tty(又称终端)。这些天很少使用。我在IRIX上有这种方式。我将打开一个单独的X窗​​口并查看其中的错误。

syslog

没有提到的一件事,在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/下,syslog服务器会自动处理该更改并将所有与邮件相关的日志保存到这些文件夹中。

注意:我还必须创建/va/log/mail文件夹和该文件夹中的文件,以确保一切正常(因为否则邮件守护程序可能没有足够的权限。)

快照记录器(一个小插头)

我使用过log4cplus,从版本1.2.x开始,它非常好。我对此有三个缺点:

  1. 如果我想调用fork(),它要求我完全清除所有内容;不知何故,它在fork()调用中无法正常运行...(至少在我使用的版本中)
  2. 在我希望管理员无需修改原始文件即可进行更改的环境中,配置文件(.properties)难以管理
  3. 它使用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的文件很有用,您的所有服务都会在其中发送日志。这样可以了解某些错误,当并行运行许多服务时,使用单独的日志文件不那么容易。

这是快照记录器配置文件中的一个简单示例:

[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可以按严重性(如syslog),正则表达式和 component 过滤输出。我们有一个normal和一个secure组件,默认为normal。我希望将发送到secure组件的日志写入安全文件。这意味着在一个子目录中,该目录比大多数管理员可以查看的常规日志受到更多保护。当我运行HTTP服务时,有时会发送信息,例如信用卡的最后3位数字。我更喜欢将它们保存在安全日志中。也可能是与密码有关的错误。实际上,我认为是日志中的任何安全隐患。同样,组件是可扩展的,因此您可以拥有自己的组件。

答案 4 :(得分:0)

基本记录器

#define myerr(e) {CriticalSectionLocker crit; std::cerr << e << std::endl;}

用作myerr("ERR: " << message);myerr("WARN: " << message << code << etc);

非常有效。

然后做:

./programname.exe 2> ./stderr.log
perl parsestderr.pl stderr.log

或只是手动解析stderr.log

我承认这不适用于性能关键代码。但无论如何谁写了。

答案 5 :(得分:0)

由于这里有一些有关重定向的答案,因此我将添加this nice gem我最近偶然发现有关重定向的信息:

#include <fstream>
#include <iostream>

class redirecter
{
public:
    redirecter(std::ostream & dst, std::ostream & src)
        : src(src), sbuf(src.rdbuf(dst.rdbuf())) {}
    ~redirecter() { src.rdbuf(sbuf); }
private:
    std::ostream & src;
    std::streambuf * const sbuf;
};

void hello_world()
{
    std::cout << "Hello, world!\n";
}

int main()
{
    std::ofstream log("hello-world.log");
    redirecter redirect(log, std::cout);
    hello_world();
    return 0;
}

基本上,它是一个重定向类,允许您重定向任何两个流,并在完成后将其还原。