25.3. 日志文件维护

把数据库服务器的日志输出保存在一个地方是个好主意, 而不是仅仅通过/dev/null丢弃它们。 在进行问题诊断的时候,日志输出是非常宝贵的。不过,日志输出可能很庞大(特别是在比较高的调试级别上), 因此你不会希望无休止地保存它们。你需要轮转日志文件, 这样在一段合理的时间后会开始新的日志文件并且移除旧的。

如果你简单地把postgresstderr定向到一个文件中,你会得到日志输出,但是截断该日志文件的唯一方法是停止并重起服务器。这样做对于开发环境中使用的PostgreSQL可能是可接受的,但是你肯定不想在生产环境上这么干。

一个更好的办法是把服务器的stderr输出发送到某种日志轮转程序里。我们有一个内建的日志轮转程序,你可以通过在 postgresql.conf里设置配置参数logging_collectortrue的办法启用它。该程序的控制参数在 第 20.8.1 节里描述。你也可以使用这种方法把日志数据捕捉成机器可读的CSV(逗号分隔值)格式。

另外,如果在你已经使用的其他服务器软件中有一个外部日志轮转程序,你可能更喜欢使用它。 比如,包含在Apache发布里的rotatelogs工具就可以用于PostgreSQL。要做到这一点,方法之一是把服务器的stderr用管道重定向到要用的程序。 如果你用pg_ctl启动服务器,那么stderr已经重定向到stdout, 因此你只需要一个管道命令,比如:

pg_ctl start | rotatelogs /var/log/pgsql_log 86400

您可以通过设置logrotate来收集由PostgreSQL内置日志收集器生成的日志文件来组合这些方法。在这种情况下,日志收集器定义日志文件的名称和位置,而logrotate 则定期归档这些文件。启动日志轮转时,logrotate必须确保应用程序将进一步的输出发送到新文件。这通常是通过postrotate脚本完成的,该脚本向应用程序发送SIGHUP信号,使其重新打开日志文件。在PostgreSQL中,您可以使用logrotate选项运行pg_ctl。服务器收到此命令后,服务器将切换到新的日志文件或重新打开现有文件,具体取决于日志记录配置(请参见第 20.8.1 节)。

注意

使用静态日志文件名时,如果达到最大打开文件数限制或发生文件表溢出,则服务器可能无法重新打开日志文件。 在这种情况下,日志消息将发送到旧的日志文件,直到成功进行日志轮转为止。 如果将logrotate配置为压缩日志文件并将其删除,则服务器可能会丢失此时间范围内记录的消息。 为避免此问题,可以将日志收集器配置为动态分配日志文件名,并使用prerotate脚本忽略打开的日志文件。

另外一种生产级的管理日志输出的方法就是把它们发送给syslog,让syslog处理文件轮转。 要利用这个工具,我们需要设置postgresql.conf里的log_destination配置参数设置为syslog(记录syslog日志)。然后在你想强迫syslog守护进程开始写入一个新日志文件的时候, 你就可以发送一个 SIGHUP信号给它。 如果你想自动进行日志轮转,可以配置logrotate程序处理 来自syslog的日志文件。

不过,在很多系统上,syslog不是非常可靠,特别是在面对大量日志消息的情况下; 它可能在你最需要那些消息的时候截断或者丢弃它们。另外,在Linuxsyslog会把每个消息刷写到磁盘上, 这将导致很差的性能(你可以在syslog配置文件里面的文件名开头使用一个-来禁用这种行为)。

请注意上面描述的所有解决方案关注的是在可配置的间隔上开始一个新的日志文件, 但它们并没有处理对旧的、不再需要的日志文件的删除。你可能还需要设置一个批处理任务来定期地删除旧日志文件。 另一种可能的方法是配置日志轮转程序,让它循环地覆盖旧的日志文件。

pgBadger是一个外部项目,它可以进行日志文件的深度分析。 check_postgres可在重要消息出现在日志文件中时向Nagios提供警告,也可以探测很多其他的特别情况。