18.8. 错误报告和日志

18.8.1. 在哪里做日志

log_destination (string)

PostgreSQL支持多种方法来记录服务器消息,包括stderrcsvlogsyslog。在 Windows 上还支持eventlog。设置这个参数为一个由想要的日志目的地的列表,之间用逗号分隔。默认值是只记录到stderr。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

如果csvlog被包括在log_destination中,日志项会以"逗号分隔值"CSV)格式被输出,这样可以很方便地把日志载入到程序中。详见Section 18.8.4。要产生 CSV 格式的日志输出,必须启用logging_collector

Note: 在大多数 Unix 系统上,你将需要修改系统的syslog守护进程的配置来使用log_destinationsyslog选项。PostgreSQL可以在syslog设备LOCAL0LOCAL7中记录(见syslog_facility),但是大部分平台上的默认syslog配置会丢弃所有这种消息。你将需要增加这样的内容:

local0.*    /var/log/postgresql

syslog守护进程的配置文件来让它工作。

在 Windows 上,当你使用log_destinationeventlog选项时,你应该在操作系统中注册一个事件源极其库,这样 Windows 事件查看器能够清楚地显示事件日志消息。详见Section 17.11

logging_collector (boolean)

这个参数启用日志收集器,它是一个捕捉被发送到stderr的日志消息的后台进程,并且它会将这些消息重定向到日志文件中。这种方法比记录到syslog通常更有用,因为某些类型的消息不会在syslog输出中出现(一个常见的例子是动态链接器错误消息;另一个例子是由archive_command等脚本产生的错误消息)。这个参数只能在服务器启动时设置。

Note: 也可以不使用日志收集器而把日志记录到stderr,日志消息将只会去到服务器的stderr被定向到的位置。不过,那种方法只适合于低日志量,因为它没有提供方法来轮转日志文件。还有,在某些不使用日志收集器的平台上可能会导致丢失或者混淆日志输出,因为多个进程并发写入同一个日志文件时会覆盖彼此的输出。

Note: 日志收集器被设计成从来不会丢失消息。这意味着在极高的负载下,如果服务器进程试图在收集器已经落后时发送更多的日志消息,那么它会被阻塞。相反,syslog倾向于在无法写入消息时丢掉消息,这意味着在这样的情况下它可能会无法记录某些消息,但是它不会阻塞系统的其他部分。

log_directory (string)

logging_collector被启用时,这个参数决定日志文件将被在哪个目录下创建。它可以被指定为一个绝对路径,也可以被指定为一个相对于集簇数据目录的相对路径。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_filename (string)

logging_collector被启用时,这个参数设置被创建的日志文件的文件名。该值被视为一种strftime模式,因此%转义可以被用来指定根据时间变化的文件名(注意如果有任何时区独立的%转义,计算将在由log_timezone指定的时区中完成)。被支持的%转义和开放组织的strftime说明中列举的类似。注意系统的strftime不会被直接使用,因此平台相关(非标准)的扩展无法工作。

如果你不使用转义来指定一个文件名,你应该计划使用一个日志轮转工具来避免最终填满整个磁盘。在 8.4 发行之前,如果不存在%转义,PostgreSQL将追加新日志文件创建时间的纪元,但是现在已经不再这样做了。

如果在log_destination中启用了 CSV 格式输出,.csv将会被追加到时间戳日志文件名中来创建 CSV 格式输出(如果log_filename.log结尾,该后缀会被替换)。在上述例子的情况中,CSV 文件名将是server_log.1093827753.csv

这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_file_mode (integer)

在 Unix 系统上,当logging_collector被启用时,这个参数设置日志文件的权限(在微软 Windows 上这个参数将被忽略)。这个参数值应当是一个数字形式的模式,它可以被chmodumask系统调用接受(要使用通常的十进制格式,该数字必须以一个0(零)开始)。

默认的权限是0600,表示只有服务器拥有者才能读取或写入日志文件。其他常用的设置是0640,它允许拥有者的组成员读取文件。不过要注意你需要修改log_directory为将文件存储在集簇数据目录之外的某个位置,才能利用这个设置。在任何情况下,让日志文件变成任何人都可读是不明智的,因为日志文件中可能包含敏感数据。

这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_rotation_age (integer)

logging_collector被启用时,这个参数决定一个个体日志文件的最长生命期。当这些分钟过去后,一个新的日志文件将被创建。将这个参数设置为零将禁用基于时间的新日志文件创建。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_rotation_size (integer)

logging_collector被启用时,这个参数决定一个个体日志文件的最大尺寸。当这么多千字节被发送到一个日志文件后,将创建一个新的日志文件。将这个参数设置为零将禁用基于尺寸的新日志文件创建。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_truncate_on_rotation (boolean)

logging_collector被启用时,这个参数将导致PostgreSQL截断(覆盖而不是追加)任何已有的同名日志文件。不过,截断只在一个新文件由于基于时间的轮转被打开时发生,在服务器启动或基于尺寸的轮转时不会发生。如果被关闭,在所有情况下以前存在的文件将被追加。例如,使用这个设置和一个类似postgresql-%H.loglog_filename将导致产生 24 个每小时的日志文件,并且循环地覆盖它们。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

例子:要保留 7 天的日志,每天的一个日志文件被命令为server_log.Monserver_log.Tue等等,并且自动用本周的日志覆盖上一周的日志。可以这样做:将log_filename设置为server_log.%a、将log_truncate_on_rotation设置为on并且将log_rotation_age设置为1440

例子:要保留 24 小时的日志,每个小时一个日志文件,但是在日志文件尺寸超过 1GB 时轮转。可以这样做:将log_filename设置为server_log.%H%M、 将log_truncate_on_rotation设置为on、 将log_rotation_age设置为60并且 将log_rotation_size设置为1000000。 Including %M in 在log_filename中包括%M允许发生任何尺寸驱动的轮转来选择一个不同于每个小时的初始文件名的新文件名。

syslog_facility (enum)

当启用了向syslog记录时,这个参数决定要使用的syslog"设备"。你可以在LOCAL0LOCAL1LOCAL2LOCAL3LOCAL4LOCAL5LOCAL6LOCAL7中选择,默认值是LOCAL0。还请参阅系统的syslog守护进程的文档。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

syslog_ident (string)

当启用了向syslog记录时,这个参数决定用来标识syslog中的PostgreSQL消息的程序名。默认值是postgres。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

event_source (string)

当启用了向事件日志记录时,这个参数决定用来标识日志中PostgreSQL消息的程序名。默认值是PostgreSQL。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

18.8.2. 什么时候记录日志

client_min_messages (enum)

控制被发送给客户端的消息级别。有效值是DEBUG5DEBUG4DEBUG3DEBUG2DEBUG1LOGNOTICEWARNINGERRORFATALPANIC。每个级别都包括其后的所有级别。级别越靠后,被发送的消息越少。默认值是NOTICE。注意LOG在这里有与log_min_messages中不同的排名。

log_min_messages (enum)

控制哪些消息级别被写入到服务器日志。有效值是DEBUG5DEBUG4DEBUG3DEBUG2DEBUG1INFONOTICEWARNINGERRORLOGFATALPANIC。每个级别都包括以后的所有级别。级别越靠后,被发送的消息越少。默认值是WARNING。注意LOG在这里有与log_min_messages中不同的排名。只有超级用户可以改变这个设置。

log_min_error_statement (enum)

控制哪些导致一个错误情况的 SQL 语句被记录在服务器日志中。任何指定严重级别或更高级别的消息的当前 SQL 语句将被包括在日志项中。有效值是DEBUG5DEBUG4DEBUG3DEBUG2DEBUG1INFONOTICEWARNINGERRORLOGFATALPANIC。默认值是ERROR,它表示导致错误、日志消息、致命错误或恐慌错误的语句将被记录在日志中。要有效地关闭记录失败语句,将这个参数设置为PANIC。只有超级用户可以改变这个设置。

log_min_duration_statement (integer)

如果语句运行至少指定的毫秒数,将导致记录每一个这种完成的语句的持续时间。将这个参数设置为零将打印所有语句的执行时间。设置为 -1 (默认值)将停止记录语句持续时间。例如,如果你设置它为250ms,那么所有运行 250ms 或更久的 SQL 语句将被记录。启用这个参数可以有助于追踪应用中未优化的查询。只有超级用户可以改变这个设置。

对于使用扩展查询协议的客户端,解析、绑定和执行步骤的持续时间将被独立记录。

Note: 当把这个选项和log_statement一起使用时,已经被log_statement记录的语句文本不会在持续时间日志消息中重复。如果你没有使用syslog,我们推荐你使用log_line_prefix记录 PID 或会话 ID,这样你可以使用进程 ID 或会话 ID 把语句消息链接到后来的持续时间消息。

Table 18-1解释了PostgreSQL所使用的消息严重级别。如果日志输出被发送到syslog或 Windows 的eventlog,严重级别会按照表中所示进行转换。

Table 18-1. 消息严重级别

严重性用法syslogeventlog
DEBUG1..DEBUG5为开发者提供连续的更详细的信息。DEBUGINFORMATION
INFO提供用户隐式要求的信息,例如来自VACUUM VERBOSE的输出。INFOINFORMATION
NOTICE提供可能对用户有用的信息,例如长标识符截断提示。NOTICEINFORMATION
WARNING提供可能出现的问题的警告,例如在一个事务块外COMMITNOTICEWARNING
ERROR报告一个导致当前命令中断的错误。WARNINGERROR
LOG报告管理员可能感兴趣的信息,例如检查点活动。INFOINFORMATION
FATAL报告一个导致当前会话中断的错误。ERRERROR
PANIC报告一个导致所有数据库会话中断的错误。CRITERROR

18.8.3. 记录什么到日志

application_name (string)

application_name可以是任意的小于NAMEDATALEN字字符 (标准编译是64字符)的字符串。它通常由一个连接服务器后的的应用程序设置。 名字会记录在pg_stat_activity和CSV日志条目中。 也可以通过log_line_prefix参数,包含在规律的日志条目中。 只有可打印的ASCII字符可以被用于application_name。 其他字符会被问号(?)替换。 application_name可以是任意小于NAMEDATALEN个字符(标准编译中是 64 个字符)的字符串。这通常由一个应用通过到服务器的连接设置。该名称将被显示在pg_stat_activity视图中并被包括在 CSV 日志项中。它也会被通过log_line_prefix包括在普通日志项中。只有可打印 ASCII 字符能被使用在application_name之中。其他字符将被替换为问号(?)。

debug_print_parse (boolean)
debug_print_rewritten (boolean)
debug_print_plan (boolean)

这个参数启用发出各种调试输出。当设置时,会打印生成的解析树, 查询重写输出,或执行的每个查询的执行计划。这些信息是在LOG 信息级别发出,因此默认的,它们会出现在服务器日志中,但不会发送给客户端。 可以通过 client_min_messages和/或log_min_messages 来设置。这些参数缺省是off。 这些参数将会让多种调试输出被发出。当被设置时,它们为每一个被执行的查询打印结果分析树、查询重写器输出或执行计划。这些消息在LOG消息级别上被发出,因此默认情况下它们将出现在服务器日志中但不会被发送到客户端。你可以通过调整client_min_messages和/或log_min_messages来改变这种情况。这些参数默认是关闭的。

debug_pretty_print (boolean)

当被设置时,debug_pretty_print会缩进由debug_print_parsedebug_print_rewrittendebug_print_plan产生的输出。这将导致比关闭参数时使用的"紧凑"模式可读性更强但是更长的输出。它默认是打开的。

log_checkpoints (boolean)

导致检查点和重启点被记录在服务器日志中。一些统计信息也被包括在日志消息中,包括写入缓冲区的数据和写它们所花的时间。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。默认值是关闭。

log_connections (boolean)

导致每一次尝试对服务器的连接被记录,客户端认证的成功完成也会被记录。这个参数在会话开始后不能被改变。默认值是关闭。

Note: 某些客户端程序(例如psql)在要求密码时会尝试连接两次,因此重复的"收到连接"消息并不一定表示一个错误。

log_disconnections (boolean)

这个参数和log_connections相似地在服务器日志中输出一行,不过是在会话终止时记录并且包括会话的持续时间。默认是关闭。这个参数在会话开始后不能被更改。

log_duration (boolean)

导致每一个完成的语句的持续时间被记录。默认值是off。只有超级用户可以改变这个设置。

对于使用扩展查询协议的客户端,解析、绑定和执行步骤的持续时间将被独立记录。

Note: 设置这个选项和设置log_min_duration_statement为零之间的区别是,超过log_min_duration_statement强制查询的文本被记录,但这个选项不会。因此,如果log_durationon并且log_min_duration_statement为正值,所有持续时间都将被记录,但是只有超过阈值的语句才会被记录查询文本。这种行为有助于在高负载安装中收集统计信息。

log_error_verbosity (enum)

控制为每一个被记录的消息要写入到服务器日志的细节量。有效值是TERSEDEFAULTVERBOSE,每一个都为显示的消息增加更多域。TERSE排除记录DETAILHINTQUERYCONTEXT错误信息。VERBOSE输出包括SQLSTATE错误码(见Appendix A)以及产生错误的源代码文件名、函数名和行号。只有超级用户能够更改这个设置。

log_hostname (boolean)

默认情况下,连接日志消息只显示连接主机的 IP 地址。打开这个参数将导致也记录主机名。注意根据你的主机名解析设置,这可能会导致很微小的性能损失。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

log_line_prefix (string)

这是一个printf风格的字符串,它在每个日志行的开头输出。%字符开始"转义序列",它将被按照下文描述的替换成状态信息。未识别的转义被忽略。其他字符被直接复制到日志行。某些转义只被会话进程识别并且被主服务器进程等后台进程忽略。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。默认值是一个空字符串。

转义效果只限会话
%a应用名
%u用户名
%d数据库名
%r远程主机名或 IP 地址,以及远程端口
%h远程主机名或 IP 地址
%p进程 ID
%t无毫秒的时间戳
%m带毫秒的时间戳
%i命令标签:会话当前命令的类型
%eSQLSTATE 错误代码
%c会话 ID:见下文
%l对每个会话或进程的日志行号,从 1 开始
%s进程开始的时间戳
%v虚拟事务 ID (backendID/localXID)
%x事务 ID (如果未分配则为 0)
%q不产生输出,但是告诉非会话进程在字符串的这一点停止;会话进程忽略
%%纯文字 %

%c转义打印一个准唯一的会话标识符,它由两个 4 字节的十六进制数(不带先导零)组成,以点号分隔。这些数字是进程启动时间和进程 ID,因此%c也可以被用作保存打印这些项的方式的空间。例如,要从pg_stat_activity生成会话标识符,使用这个查询:

SELECT to_hex(EXTRACT(EPOCH FROM backend_start)::integer) || '.' ||
       to_hex(pid)
FROM pg_stat_activity;

Tip: 如果你为log_line_prefix设置了非空值,你通常应该让它的最后一个字符为空格,这样用以提供和日志行的剩余部分的视觉区别。也可以使用标点符号。

Tip: Syslog产生自己的时间戳和进程 ID 信息,因此如果你记录到syslog你可能不希望包括哪些转义。

log_lock_waits (boolean)

控制当一个会话为获得一个锁等到超过deadlock_timeout时,是否要产生一个日志消息。这有助于决定是否所等待造成了性能低下。默认值是off

log_statement (enum)

控制哪些 SQL 语句被记录。有效值是 none (off)、ddlmodall(所有语句)。ddl记录所有数据定义语句,例如CREATEALTERDROP语句。mod记录所有ddl语句,外加数据修改语句例如INSERT, UPDATEDELETETRUNCATE, 和COPY FROM。 如果PREPAREEXECUTEEXPLAIN ANALYZE包含合适类型的命令,它们也会被记录。对于使用扩展查询协议的客户端,当收到一个执行消息时会产生日志并且会包括绑定参数的值(任何内嵌的单引号会被双写)。

默认值是none。只有超级用户可以改变这个设置。

Note: 即使设置了log_statement=all,包含 简单语法错误的语句也不会被记录。因为仅在完成基本的语法分析并 确定了语句类型之后才记录日志。在使用扩展查询协议的情况下,在 执行阶段之前(语法分析或规划阶段)同样不会记录。将 log_min_error_statement设为ERROR 或更低才能记录这些语句。 即使使用log_statement = all设置,包含简单语法错误的语句也不会被记录。这是因为只有在完成基本语法解析并确定了语句类型之后才会发出日志消息。在扩展查询协议的情况下,在执行阶段之前(即在解析分析或规划期间)出错的语句也不会被记录。将log_min_error_statement设置为ERROR(或更低)来记录这种语句。

log_temp_files (integer)

控制记录临时文件名和尺寸。临时文件可以被创建用来排序、哈希和存储临时查询结果。当每一个临时文件被删除时都会制作一个日志项。一个零值记录所有临时文件信息,而正值只记录尺寸大于或等于指定千字节数的文件。默认设置为 -1,它禁用这种记录。只有超级用户可以更改这个设置。

log_timezone (string)

设置在服务器日志中写入的时间戳的时区。和TimeZone不同,这个值是集簇范围的,因此所有会话将报告一致的时间戳。内建默认值是GMT,但是通常会被在postgresql.conf中覆盖。initdb将安装一个对应于其系统环境的设置。详见Section 8.5.3。这个参数只能在postgresql.conf文件中或在服务器命令行上设置。

18.8.4. 使用 CSV 格式的日志输出

包括在log_destination中的csvlog,提供了一个 便捷的方式向数据库中导入日志文件。这个选项以CSV格式发出日志行, 带有这些列: 以毫秒为单位的时间戳,用户名,数据库名,进程ID,客户端主机:端口号, 会话ID,每个会话的行号,命令标签,会话开始时间,虚拟事务ID,日常事务ID, 错误严重性,SQLSTATE代码,错误信息,错误信息的详细信息,建议, 导致错误的内部查询(如果存在),其中的错误位置的字符统计, 错误范围,导致错误的用户查询(如果存在,并且启用log_min_error_statement), 其中的错误位置的字符统计,PostgreSQL源代码中报错的位置(如果 log_error_verbosity设置为verbose)和应用程序名。 下面是一个用于存储CSV格式日志暑促的简单表定义: 在log_destination列表中包括csvlog提供了一种便捷方式将日志文件导入到一个数据库表。这个选项发出逗号分隔值(CSV)格式的日志行,包括这些列: 带毫秒的时间戳、 用户名、 数据库名、 进程 ID、 客户端主机:端口号、 会话 ID、 每个会话的行号、 命令标签、 会话开始时间、 虚拟事务 ID、 普通事务 ID、 错误严重性、 SQLSTATE 代码、 错误消息、 错误消息详情、 提示、 导致错误的内部查询(如果有)、 错误位置所在的字符计数、 错误上下文、 导致错误的用户查询(如果有且被log_min_error_statement启用)、 错误位置所在的字符计数、 在 PostgreSQL 源代码中错误的位置(如果log_error_verbosity被设置为verbose)以及应用名。 下面是一个定义用来存储 CSV 格式日志输出的样表:

CREATE TABLE postgres_log
(
  log_time timestamp(3) with time zone,
  user_name text,
  database_name text,
  process_id integer,
  connection_from text,
  session_id text,
  session_line_num bigint,
  command_tag text,
  session_start_time timestamp with time zone,
  virtual_transaction_id text,
  transaction_id bigint,
  error_severity text,
  sql_state_code text,
  message text,
  detail text,
  hint text,
  internal_query text,
  internal_query_pos integer,
  context text,
  query text,
  query_pos integer,
  location text,
  application_name text,
  PRIMARY KEY (session_id, session_line_num)
);

使用COPY FROM命令将一个日志文件导入到这个表中:

COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;

你可以做一些事情来简化导入 CSV 日志文件:

  1. 设置log_filenamelog_rotation_age为你的日志文件提供一种一致的、可预测的命名空间。这让你预测文件名会是怎样以及知道什么时候一个个体日志文件完成并且因此准备好被导入。

  2. log_rotation_size设置为 0 来禁用基于尺寸的日志轮转,因为它使得日志文件名难以预测。

  3. log_truncate_on_rotation设置为on,这样在同一个文件中旧日志数据不会与新数据混杂。

  4. 上述表定义包括一个主键声明。这有助于避免意外地两次导入相同的信息。COPY命令一次提交所有它导入的数据,因此任何错误将导致整个导入失败。如果你导入一个部分完成的日志文件并且稍后当它完全完成后再次导入,主键违背将导致导入失败。请等到日志完成且被关闭之后再导入。这个过程也可以避免意外地导入部分完成的行,这种行也将导致COPY失败。