8.4.5.6 读取审计日志文件
审核日志插件支持使用 SQL 接口来读取 JSON 格式的审核日志文件。(对其他格式的日志文件不适用。)
当审核日志插件初始化并配置为 JSON 日志时,它将使用当前审核日志文件所在目录作为查找可读审核日志文件的位置。插件从audit_log_file
系统变量中获取文件路径、基本名称和后缀,然后寻找名为以下模式的文件,其中[...]
表示可选文件名部分:
basename[.timestamp].suffix[.gz][[.pwd_id].enc]
如果文件名以.enc
结尾,文件加密,读取未加密内容需要从密钥ring获取解密密码。审核日志插件确定解密密码的密钥ring ID 如下:
-
如果
.enc
前面有pwd_id
,密钥ring ID 是audit_log-
。pwd_id
-
如果
.enc
前面没有pwd_id
,文件是老名称,来自审核日志加密密码历史实现之前。密钥ring ID 是audit_log
。
关于加密审核日志文件的更多信息,请参见加密审核日志文件。
插件忽略了手动重命名的文件和无法从密钥ring中获取密码加密的文件。插件打开每个候选文件,验证该文件实际包含JSON
审核事件,然后使用每个文件中的时间戳对文件进行排序。结果是一个可以使用日志读取函数访问的文件序列:
-
audit_log_read()
从审核日志中读取事件或关闭读取进程。 -
audit_log_read_bookmark()
返回最近写入的审核日志事件的书签。这个书签可以传递给audit_log_read()
以指示开始读取位置。
audit_log_read()
可选地接受一个JSON
字符串参数,成功调用任意函数返回的结果是一个JSON
字符串。
使用读取审核日志函数时,请遵循以下原则:
-
调用
audit_log_read()
从给定位置或当前位置开始读取事件,或者关闭读取:-
初始化审核日志读取序列,传递一个指示开始位置的参数。其中一种方法是传递
audit_log_read_bookmark()
返回的书签:SELECT audit_log_read(audit_log_read_bookmark());
-
从当前位置继续读取序列,调用
audit_log_read()
不指定位置:SELECT audit_log_read();
-
可以明确地关闭读取序列,传递
JSON
null
参数:SELECT audit_log_read('null');
不需要明确地关闭读取。读取将在会话结束或调用
audit_log_read()
时隐式地关闭,以开始新的读取序列。
-
-
成功调用
audit_log_read()
读取事件返回JSON
字符串,包含审核事件数组:-
如果返回数组的最后一个值不是
JSON
null
值,那么读取的事件后面还有更多事件,可以再次调用audit_log_read()
来读取更多事件。 -
如果返回数组的最终值是一个
JSON
null
值,那么当前读取序列中已经没有更多事件可读了。
每个非
null
数组元素都是一个以JSON
哈希表示的事件,例如:[ { "timestamp": "2020-05-18 13:39:33", "id": 0, "class": "connection", "event": "connect", ... }, { "timestamp": "2020-05-18 13:39:33", "id": 1, "class": "general", "event": "status", ... }, { "timestamp": "2020-05-18 13:39:33", "id": 2, "class": "connection", "event": "disconnect", ... }, null ]
关于 JSON 格式审核日志文件内容的更多信息,请见JSON审核日志文件格式。
-
-
audit_log_read()
函数读取事件,但未指定位置,在以下情况下都会产生错误:-
还没有通过将位置传递给
audit_log_read()
初始化读取序列。 -
当前读取序列中已经没有更多事件可读了,即
audit_log_read()
之前返回的数组以JSON
null
值结尾。 -
最近读取序列已经被通过将
JSON
null
值传递给audit_log_read()
关闭了。
在这些条件下,需要首先通过调用
audit_log_read()
函数来初始化读取序列,并传入一个指定位置的参数。 -
要将位置传递给audit_log_read()
,请包括一个指明开始读取的参数。例如,传入一个书签,这是一个JSON
对象,其中包含唯一标识某个事件的timestamp
和id
元素。下面是一个通过调用audit_log_read_bookmark()
函数获得的书签示例:
mysql> SELECT audit_log_read_bookmark();
+-------------------------------------------------+
| audit_log_read_bookmark() |
+-------------------------------------------------+
| { "timestamp": "2020-05-18 21:03:44", "id": 0 } |
+-------------------------------------------------+
将当前书签传递给audit_log_read()
,从书签位置开始读取事件:
mysql> SELECT audit_log_read(audit_log_read_bookmark());
+-----------------------------------------------------------------------+
| audit_log_read(audit_log_read_bookmark()) |
+-----------------------------------------------------------------------+
| [ {"timestamp":"2020-05-18 22:41:24","id":0,"class":"connection", ... |
+-----------------------------------------------------------------------+
对audit_log_read()
函数的参数是可选的。如果存在,可以是一个关闭读取序列的JSON
null
值,或者一个JSON
对象。
在audit_log_read()
的哈希参数中,项目是可选项,控制读取操作的方面,如开始读取位置或要读取的事件数量。以下项目是有意义的(其他项目将被忽略):
-
start
:从audit日志中的第一个事件开始读取的位置,位置以时间戳值为准,读取从该时间戳值后出现的第一个事件。start
项目的格式是:"start": { "timestamp": "value" }
-
timestamp
,id
:audit日志中的第一个事件开始读取的位置,timestamp
和id
项目组成一个唯一标识某个事件的书签。如果audit_log_read()
参数包括任意一个项目,它必须包括两个项目,否则将发生错误。 -
max_array_length
:从日志中读取的事件数量的最大值。如果忽略该项目,默认情况下是直到日志结尾或读取缓冲区满,先到者为止。
要指定audit_log_read()
的开始位置,传递一个哈希参数,其中包括了start
项目或由timestamp
和id
项目组成的书签。如果哈希参数包括了start
项目和书签,错误将发生。
如果哈希参数不指定起始位置,继续从当前位置读取。
如果时间戳值不包含时间部分,假设时间部分为00:00:00
。
接受audit_log_read()
函数的示例参数:
-
从给定时间戳开始读取事件,直到当前位置:
audit_log_read('{ "start": { "timestamp": "2020-05-24 12:30:00" } }')
-
类似前一个示例,但最多读取3个事件:
audit_log_read('{ "start": { "timestamp": "2020-05-24 12:30:00" }, "max_array_length": 3 }')
-
从
2020-05-24 00:00:00
开始读取事件(时间戳不包含时间部分,假设为00:00:00
):audit_log_read('{ "start": { "timestamp": "2020-05-24" } }')
-
从具有精确时间戳和事件ID的事件开始读取:
audit_log_read('{ "timestamp": "2020-05-24 12:30:00", "id": 0 }')
-
类似前一个示例,但最多读取3个事件:
audit_log_read('{ "timestamp": "2020-05-24 12:30:00", "id": 0, "max_array_length": 3 }')
-
从当前读取序列位置读取事件:
audit_log_read()
-
从当前读取序列位置开始,读取至多5个事件:
audit_log_read('{ "max_array_length": 5 }')
-
关闭当前读取序列:
audit_log_read('null')
从JSON
字符串返回的结果可以根据需要进行操作。假设某个调用获取书签的函数返回该值:
mysql> SET @mark := audit_log_read_bookmark();
mysql> SELECT @mark;
+-------------------------------------------------+
| @mark |
+-------------------------------------------------+
| { "timestamp": "2020-05-18 16:10:28", "id": 2 } |
+-------------------------------------------------+
使用该参数调用audit_log_read()
函数,可以返回多个事件。要限制audit_log_read()
至最多读取N
个事件,需要将字符串添加一个max_array_length
项,例如要读取单个事件,可以将字符串修改为:
mysql> SET @mark := JSON_SET(@mark, '$.max_array_length', 1);
mysql> SELECT @mark;
+----------------------------------------------------------------------+
| @mark |
+----------------------------------------------------------------------+
| {"id": 2, "timestamp": "2020-05-18 16:10:28", "max_array_length": 1} |
+----------------------------------------------------------------------+
将该字符串传递给audit_log_read()
,结果最多包含一个事件,无论有多少可用。
如果在mysql 客户端中调用审核日志函数,二进制字符串结果将使用十六进制表示,取决于--binary-as-hex
的值。关于该选项的更多信息,请参见第6.5.1节,“mysql — MySQL 命令行客户端”。
要设置audit_log_read()
读取的字节数限制,可以设置audit_log_read_buffer_size
系统变量。该变量的默认值为32KB,可以在运行时设置。每个客户端都应该根据自己的使用情况设置audit_log_read_buffer_size
会话值。
对audit_log_read()
的每次调用返回可用事件的数量,直到缓冲区大小为止。不能在缓冲区大小内的事件将被跳过并生成警告。考虑以下因素来评估应用程序的合适缓冲区大小:
-
调用
audit_log_read()
函数和每次返回事件之间存在权衡:-
使用较小的缓冲区大小,函数返回较少事件,因此需要更多调用。
-
使用较大的缓冲区大小,函数返回更多事件,因此需要更少调用。
-
-
使用较小的缓冲区大小,如默认值32KB,事件溢出可能性更高,从而可能被跳过。
关于审核日志读取函数的详细信息,请参见审核日志函数。