MySQL 错误日志

一、错误日志概述

错误日志包含 mysqld 启动、关闭记录及诊断消息(如 errors、warnings、notes),需重点关注 error 级别。错误消息可能存储在 Performance_schema.error_log 表中。若以 mysqld_safe 启动,消息可能写入错误日志。

二、错误日志组件

MySQL 8.0 错误日志基于组件,分为过滤器和接收器。

1. 过滤器(filter)

过滤器用于修改日志事件,影响可写入的信息。

(1)log_filter_internal

  • 内置组件,无需加载,不可多次使用。
  • 结合 log_error_verbosity 和 log_error_suppression_list 系统变量,实现基于日志事件优先级和错误代码的过滤。

(2)log_filter_dragnet

  • 用于自定义过滤规则,不可多次使用。
  • URN:
file://component_log_filter_dragnet
  • 结合 dragnet.log_error_filter_rules 系统变量,实现基于用户自定义规则的过滤。

2. 接收器(sink)

接收器将日志事件处理为特定格式并写入输出目标(如文件、系统日志)。

(1)log_sink_internal

  • 内置组件,无需加载,不可多次使用。
  • 支持 performance.error_log 系统表。
  • 输出格式(传统错误日志输出):
2020-08-06T14:25:02.835618Z 0 [Note] [MY-012487] [InnoDB] DDL log recovery : begin
2020-08-06T14:25:02.936146Z 0 [Warning] [MY-010068] [Server] CA certificate /var/mysql/sslinfo/cacert.pem is self signed.
2020-08-06T14:25:02.963127Z 0 [Note] [MY-010253] [Server] IPv6 is available.
2020-08-06T14:25:03.109022Z 5 [Note] [MY-010051] [Server] Event Scheduler: scheduler thread started with id 5
  • 字段:time thread [label] [err_code] [subsystem] msg

(2)log_sink_json

  • 以 JSON 格式输出,可多次使用。
  • URN:
file://component_log_sink_json
  • 支持 performance.error_log 系统表。
  • 输出格式(JSON 对象):
{
  "prio": 3,
  "err_code": 10051,
  "source_line": 561,
  "source_file": "event_scheduler.cc",
  "function": "run",
  "msg": "Event Scheduler: scheduler thread started with id 5",
  "time": "2020-08-06T14:25:03.109022Z",
  "ts": 1596724012005,
  "thread": 5,
  "err_symbol": "ER_SCHEDULER_STARTED",
  "SQL_state": "HY000",
  "subsystem": "Server",
  "buffered": 1596723903109022,
  "label": "Note"
}
  • 特殊字段:ts(时间戳)、buffered(时间戳)。
  • 时间戳转换示例:
mysql> SET time_zone = '+00:00';
mysql> SELECT FROM_UNIXTIME(1596724012005/1000.0);
+-------------------------------------+
| FROM_UNIXTIME(1596724012005/1000.0) |
+-------------------------------------+
| 2020-08-06 14:26:52.0050            |
+-------------------------------------+
mysql> SELECT FROM_UNIXTIME(1596723903109022/1000000.0);
+-------------------------------------------+
| FROM_UNIXTIME(1596723903109022/1000000.0) |
+-------------------------------------------+
| 2020-08-06 14:25:03.1090                  |
+-------------------------------------------+

(3)log_sink_syseventlog

  • 写入系统日志(syslog),不可多次使用。
  • URN:
file://component_log_sink_syseventlog

(4)log_sink_test

  • 用于测试用例,不用于生产。
  • URN:
file://component_log_sink_test

(5)Early-Startup

服务器处理启动选项前生成的错误日志消息。

三、配置方法

1. 功能说明

  • 日志事件可经过滤器过滤,影响写入信息。
  • 日志事件由接收器输出,可启用多个接收器写入多个目标。
  • 内置过滤器和接收器结合实现默认错误日志格式。
  • 可加载接收器支持 JSON 格式或系统日志记录。
  • 系统变量控制启用的日志组件及运行方式。

2. 系统变量

(1)log_error_services

  • 控制错误日志使用的组件。
  • 变量值:0(禁用);列表(多元素用分号或逗号分隔)。
  • 默认值示例:
mysql> SELECT @@GLOBAL.log_error_services;  -- 默认值
+----------------------------------------+
| @@GLOBAL.log_error_services            |
+----------------------------------------+
| log_filter_internal; log_sink_internal |
+----------------------------------------+
  • 注意:组件顺序重要,过滤器需在接收器前;可配置多个接收器。
  • 示例:
    • 一个接收器接收所有事件,一个接收过滤后事件:log_sink_1; log_filter_internal; log_sink_2
    • 两个接收器均接收过滤后事件:log_filter_internal; log_sink_1; log_sink_2

(2)log_error_verbosity

  • 控制日志详细程度。
  • 变量值:1(仅 errors);2(默认,errors 和 warnings);3(errors、warnings、information/note)。

(3)log_error_suppression_list

  • 控制不记录的事件(日志事件黑名单),仅抑制 WARNING/INFORMATION 事件,不抑制 ERROR/SYSTEM 消息。
  • 变量值:空字符串;错误代码列表(符号或数字形式,数字可不带 MY- 前缀,用逗号分隔)。
  • 示例:ER_SERVER_SHUTDOWN_COMPLETE, MY-000031, 000031, MY-31, 31
  • 错误代码范围:全局(1-999,服务器和客户端用);服务器(>10000,仅服务器用)。

(4)log_error

  • 控制默认错误日志输出目标。
  • 变量值:
    • 空值:默认控制台(stderr)。
    • 未命名文件:数据目录下 host_name.err 文件。
    • 指定文件名:默认数据目录下生成 .err 后缀文件,通常放 /var/log/ 下。
  • 对接收器的影响:
    • 若为 stderr:log_sink_internal、log_sink_json、log_sink_test 写控制台;log_sink_syseventlog 写系统日志(与该值无关)。
    • 若不为 stderr:log_sink_internal、log_sink_test 写 file_name;log_sink_json 写 file_name 加 .NN.json 后缀(如 file_name.00.json);log_sink_syseventlog 写系统日志(与该值无关)。

(5)log_timestamps

  • 控制日志(常规、错误、慢查询日志)时间戳的时区。
  • 时间戳格式:ISO 8601/RFC 3339 格式 YYYY-MM-DDThh:mm:ss.uuuuuu 加结尾符号(如 2021-02-01T00:39:31.438390Z2021-02-01T14:48:52.935812+08:00)。
  • 变量值:UTC(默认,时间戳以 Z 结尾);SYSTEM(时间戳以 ±hh:mm 结尾)。

3. 添加或删除日志组件

(1)添加组件

  • 手动加载:使用 INSTALL COMPONENT,组件会注册到 mysql.component 表,供后续启动自动加载。

    mysql> select * from mysql.component;
    +--------------+--------------------+---------------------------------------+
    | component_id | component_group_id | component_urn                         |
    +--------------+--------------------+---------------------------------------+
    |            1 |                  1 | file://component_log_sink_syseventlog |
    +--------------+--------------------+---------------------------------------+
    
  • 将组件添加到 log_error_services 系统变量(修改配置文件,持久化设置)。

(2)删除组件

  • 使用 UNINSTALL COMPONENT。

(3)示例

  • 用系统日志接收器替换默认接收器:

    mysql> install component 'file://component_log_sink_syseventlog';
    mysql> set global log_error_services='log_filter_internal; log_sink_syseventlog';
    

    Note:URN 语法为 INSTALL COMPONENT 'file://component_组件名称';

    • 相关系统变量(8.0.13 前为 log_syslog_*):
      • syseventlog.facility:指定 syslog 消息功能(默认 daemon)。
      • syseventlog.include_pid:是否包含服务器进程 ID。
      • syseventlog.tag:添加 mysqld 作为 syslog 标识符。
  • 配置多个接收器:

    mysql> set global log_error_services='log_filter_internal; log_sink_internal; log_sink_syseventlog';
    

    系统日志查看示例:

    $ more /var/log/messages
    Mar 16 15:57:41 yingzai systemd[1]: Stopping MySQL Server...
    Mar 16 15:57:41 yingzai mysqld[123315]: Received SHUTDOWN from user <via user signal>. Shutting down mysqld (Version: 8.0.23).
    Mar 16 15:57:43 yingzai mysqld[123315]: /opt/mysql/bin/mysqld: Forcing close of thread 8  user: 'root'.
    Mar 16 15:57:43 yingzai mysqld[123315]: /opt/mysql/bin/mysqld: Forcing close of thread 9  user: 'root'.
    Mar 16 15:57:43 yingzai mysqld[123315]: /opt/mysql/bin/mysqld: Forcing close of thread 10  user: 'root'.
    Mar 16 15:57:44 yingzai mysqld[123315]: /opt/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.23)  MySQL Community Server - GPL.
    Mar 16 15:57:44 yingzai systemd[1]: mysqld.service: Succeeded.
    Mar 16 15:57:44 yingzai systemd[1]: Stopped MySQL Server.
    Mar 16 15:57:44 yingzai systemd[1]: Started MySQL Server.
    Mar 16 15:57:46 yingzai systemd[1]: mysqld.service: Main process exited, code=exited, status=1/FAILURE
    Mar 16 15:57:46 yingzai systemd[1]: mysqld.service: Failed with result 'exit-code'.
    
  • 恢复默认组件并卸载多余组件:

    mysql> set global log_error_services = default;
    mysql> uninstall component 'file://component_log_sink_syseventlog';
    
  • 使用 JSON 格式接收器:

    mysql> install component 'file://component_log_sink_json';
    mysql> set persist log_error_services='log_filter_internal; log_sink_internal; log_sink_json';
    

    日志文件查看:

    $ ll
    total 16
    -rw-r----- 1 mysql mysql 4268 Mar 16 16:20 err.log
    -rw-r----- 1 mysql mysql 6338 Mar 16 16:20 err.log.00.json
    

四、错误事件字段

1. 核心字段

  • time:事件时间戳(精度微秒)。
  • msg:内容。
  • prio:事件优先级(0:System event;1:Error event;2:Warning event;3:Note/information event,可表示为数字或字符串)。
  • err_code:错误代码(如 1022)。
  • err_symbol:错误符号(如 ER_DUP_KEY)。
  • SQL_state:SQLSTATE 值(如 ‘23000’)。
  • subsystem:发生事件的子系统(InnoDB、Repl、Server 等)。

2. 可选字段

  • 错误其他信息:OS_errno(操作系统错误号)、OS_errmsg(操作系统错误信息)、label(与 prio 对应的字符串标签)。
  • 客户端标识:user(客户端用户)、host(客户端主机名)、thread(线程 ID)、query_id(查询 ID)。
  • 调试信息:source_file(源文件,无前导路径)、source_line(源文件行号)、function(函数)、component(组件或插件)。

3. 自定义字段

略。

五、错误日志的过滤方式

1. 基于优先级的过滤

由 log_filter_internal 实现,通过以下系统变量:

  • log_error_verbosity:控制日志详细度。
  • log_error_suppression_list:设置日志事件黑名单。

2. 基于规则的过滤

由 log_filter_dragnet 实现,支持用户自定义规则。

(1)组件操作

  • 开启:

    mysql> install component 'file://component_log_filter_dragnet';
    mysql> set global log_error_services='log_filter_dragnet; log_sink_internal';
    
  • 卸载:

    SET GLOBAL log_error_services = default;
    UNINSTALL COMPONENT 'file://component_log_filter_dragnet';
    

(2)系统变量

  • dragnet.log_error_filter_rules:指定过滤规则,每条规则为以英文句号结尾的 IF 语句(不区分大小写)。
    示例:

    SET GLOBAL dragnet.log_error_filter_rules = '
      IF prio>=INFORMATION THEN drop.
      IF EXISTS source_line THEN unset source_line.
    ';
    

    Note:为方便阅读,可每行一条规则。

(3)过滤规则语法

rule:
    IF condition THEN action
    [ELSEIF condition THEN action] ...
    [ELSE action]
    .

condition: {
    field comparator value
  | [NOT] EXISTS field
  | condition {AND | OR}  condition
}

action: {
    drop
  | throttle {count | count / window_size}
  | set field [:= | =] value
  | unset [field]
}

field: {
    core_field
  | optional_field
  | user_defined_field
}

core_field: {
    time
  | msg
  | prio
  | err_code
  | err_symbol
  | SQL_state
  | subsystem
}

optional_field: {
    OS_errno
  | OS_errmsg
  | label
  | user
  | host
  | thread
  | query_id
  | source_file
  | source_line
  | function
  | component
}

user_defined_field:
    sequence of characters in [a-zA-Z0-9_] class

comparator: {== | != | <| >= | =| <= | =< | < | >}

value: {
    string_literal
  | integer_literal
  | float_literal
  | error_symbol
  | priority
}

count: integer_literal
window_size: integer_literal

string_literal:
    sequence of characters quoted as '...' or "..."

integer_literal:
    sequence of characters in [0-9] class

float_literal:
    integer_literal[.integer_literal]

error_symbol:
    valid MySQL error symbol such as ER_ACCESS_DENIED_ERROR or ER_STARTUP

priority: {
    ERROR
  | WARNING
  | INFORMATION
}

(4)规则说明

  • 支持 AND、OR 运算符,字符串可用反斜杠转义。
  • 事件优先级比较:可用数字或字符串(如 IF prio == INFORMATION THEN ...IF prio == 3 THEN ...)。
  • 错误代码比较:可用数字或符号形式(如 IF err_code == ER_STARTUP THEN ...IF err_code == 1408 THEN ...)。
    查看错误代码对应关系:参考 MySQL 手册,或使用 perror 命令。

(5)过滤规则动作

  • drop:删除当前日志事件(不记入日志)。
  • throttle:限流,格式为 count 或 count/window_size(count 为时间窗口允许的事件数,window_size 为时间窗口(秒),默认 60 秒)。
    示例:
    • 插件关闭消息每 60 秒最多 5 次:IF err_code == ER_PLUGIN_SHUTTING_DOWN_PLUGIN THEN throttle 5.
    • 错误和警告每小时最多 1000 次,信息消息每小时最多 100 次:IF prio < INFORMATION THEN throttle 1000/3600 ELSE throttle 100/3600.
  • set:为字段赋值,后续规则可基于新值判断。
  • unset:丢弃字段,后续规则中该字段 EXISTS 测试为假。
    示例:IF myfield == 2 THEN unset myfield.IF myfield == 2 THEN unset.

六、错误日志文件刷新和重命名

1. 错误日志刷新

  • 执行 flush error logsflush logs 命令。
  • 执行 mysqladmin flush-logs 命令。

2. 错误日志重命名(轮换)

重命名后需刷新以生成新日志文件,步骤:

mv host_name.err host_name.err-old
mysqladmin flush-logs
mv host_name.err-old backup-directory