扩展 MySQL 8.0  / 第 4 章 MySQL 插件 API  / 4.4 编写插件  / 4.4.11 编写协议跟踪插件  /  4.4.11.2 使用您自己的协议跟踪插件

4.4.11.2 使用您自己的协议跟踪插件

笔记

要使用您自己的协议跟踪插件,您必须在禁用CMake选项 的情况下配置 MySQL, 因为一次只能加载一个协议跟踪插件,并且尝试加载第二个插件时会发生错误。如果您已经在启用测试协议跟踪插件的情况下构建了 MySQL 以查看其工作原理,则必须在没有它的情况下重建 MySQL,然后才能使用您自己的插件。 WITH_TEST_TRACE_PLUGIN

本节讨论如何编写一个名为simple_trace. 该插件提供了一个框架,展示了如何设置客户端插件描述符和创建与跟踪相关的回调函数。在simple_trace中,这些函数是基本的,除了说明所需的参数外几乎没有其他作用。要详细了解跟踪插件如何使用跟踪事件信息,请查看测试协议跟踪插件的源文件(test_trace_plugin.cclibmysqlMySQL 源代码分发目录中)。但是,请注意 st_mysql_client_plugin_TRACE那里使用的结构与通常的客户端插件声明宏使用的结构不同。特别是,前两个成员是显式定义的,而不是由声明宏隐式定义的。

几个头文件包含与协议跟踪插件相关的信息:

  • client_plugin.h:定义客户端插件的 API。这包括用于客户端插件 C API 调用的客户端插件描述符和函数原型(请参阅 C API 客户端插件接口)。

  • plugin_trace.h: 包含 类型的客户端插件的声明 MYSQL_CLIENT_TRACE_PLUGIN。它还包含对允许的协议阶段、阶段之间的转换以及每个阶段允许的事件类型的描述。

要编写协议跟踪插件,请在插件源文件中包含以下头文件。根据插件功能和要求,可能还需要其他 MySQL 或通用头文件。

Press CTRL+C to copy
#include <mysql/plugin_trace.h> #include <mysql.h>

plugin_trace.hincludes client_plugin.h,因此您无需明确包含后一个文件。

mysql_declare_client_plugin()使用和 mysql_end_client_plugin宏 声明客户端插件描述符 (参见第 4.4.2.3 节,“客户端插件描述符”)。对于 simple_trace插件,描述符如下所示:

Press CTRL+C to copy
mysql_declare_client_plugin(TRACE) "simple_trace", /* plugin name */ "Author Name", /* author */ "Simple protocol trace plugin", /* description */ {1,0,0}, /* version = 1.0.0 */ "GPL", /* license type */ NULL, /* for internal use */ plugin_init, /* initialization function */ plugin_deinit, /* deinitialization function */ plugin_options, /* option-handling function */ trace_start, /* start-trace function */ trace_stop, /* stop-trace function */ trace_event /* event-handling function */ mysql_end_client_plugin;

从插件名称到选项处理函数的描述符成员对所有客户端插件类型都是通用的。公共成员之后的成员实现跟踪事件处理。

插件不需要处理的函数成员可以NULL在描述符中声明,在这种情况下你不需要编写任何相应的函数。出于说明目的和显示参数语法,以下讨论实现了描述符中列出的所有函数,即使其中一些函数什么都不做,

所有客户端插件通用的初始化、取消初始化和选项函数声明如下。有关参数和返回值的说明,请参阅 第 4.4.2.3 节,“客户端插件描述符”

Press CTRL+C to copy
static int plugin_init(char *errbuf, size_t errbuf_len, int argc, va_list args) { return 0; } static int plugin_deinit() { return 0; } static int plugin_options(const char *option, const void *value) { return 0; }

客户端插件描述符的特定跟踪成员是回调函数。以下描述提供了有关如何使用它们的更多详细信息。每个都有一个第一个参数,它是一个指向插件实例的指针,以防您的实现需要访问它。

trace_start():此函数在每个跟踪连接开始时调用(每个连接在插件加载后开始)。它通过连接处理程序和跟踪开始的协议阶段。trace_start()分配函数所需的内存trace_event()(如果有),并返回指向它的指针。如果不需要内存,则此函数返回NULL

Press CTRL+C to copy
static void* trace_start(struct st_mysql_client_plugin_TRACE *self, MYSQL *conn, enum protocol_stage stage) { struct st_trace_data *plugin_data= malloc(sizeof(struct st_trace_data)); fprintf(stderr, "Initializing trace: stage %d\n", stage); if (plugin_data) { memset(plugin_data, 0, sizeof(struct st_trace_data)); fprintf(stderr, "Trace initialized\n"); return plugin_data; } fprintf(stderr, "Could not initialize trace\n"); exit(1); }

trace_stop():当连接跟踪结束时调用此函数。这通常发生在连接关闭时,但也可能更早发生。例如,trace_event()可以随时返回一个非零值,这会导致连接跟踪终止。trace_stop()然后调用,即使连接尚未结束。

trace_stop()trace_start()传递给连接处理程序和指向由(NULL如果没有)分配的内存的指针 。如果指针是非的NULLtrace_stop()应该释放内存。此函数不返回任何值。

Press CTRL+C to copy
static void trace_stop(struct st_mysql_client_plugin_TRACE *self, MYSQL *conn, void *plugin_data) { fprintf(stderr, "Terminating trace\n"); if (plugin_data) free(plugin_data); }

trace_event():每次事件发生时都会调用此函数。它传递一个指向由trace_start()NULL如果没有)、连接处理程序、当前协议阶段和事件代码以及事件数据分配的内存的指针。此函数返回 0 以继续跟踪,如果跟踪应停止则返回非零。

Press CTRL+C to copy
static int trace_event(struct st_mysql_client_plugin_TRACE *self, void *plugin_data, MYSQL *conn, enum protocol_stage stage, enum trace_event event, struct st_trace_event_args args) { fprintf(stderr, "Trace event received: stage %d, event %d\n", stage, event); if (event == TRACE_EVENT_DISCONNECTED) fprintf(stderr, "Connection closed\n"); return 0; }

连接结束时,跟踪框架会关闭连接跟踪,因此 trace_event()仅当您想提前终止连接跟踪时才应返回非零值。假设您只想跟踪某个 MySQL 帐户的连接。认证后,您可以检查连接的用户名,如果不是您感兴趣的用户,则停止跟踪。

对于每次调用trace_event(),该 st_trace_event_args结构都包含事件数据。它有这个定义:

Press CTRL+C to copy
struct st_trace_event_args { const char *plugin_name; int cmd; const unsigned char *hdr; size_t hdr_len; const unsigned char *pkt; size_t pkt_len; };

对于不同的事件类型,该 st_trace_event_args结构包含以下描述的信息。所有长度都以字节为单位。未使用的成员设置为 0/ NULL

AUTH_PLUGIN事件:

Press CTRL+C to copy
plugin_name The name of the plugin

SEND_COMMAND事件:

Press CTRL+C to copy
cmd The command code hdr Pointer to the command packet header hdr_len Length of the header pkt Pointer to the command arguments pkt_len Length of the arguments

其他 及 活动: SEND_xxxxxx_RECEIVED

Press CTRL+C to copy
pkt Pointer to the data sent or received pkt_len Length of the data

PACKET_SENT事件:

Press CTRL+C to copy
pkt_len Number of bytes sent

要编译和安装插件库文件,请使用 第 4.4.3 节“编译和安装插件库”中的说明。要使库文件可用,请将其安装在插件目录(由 plugin_dir系统变量命名的目录)中。

插件库文件编译安装到插件目录后,你可以通过将 LIBMYSQL_PLUGINS环境变量设置为插件名称来轻松测试它,这会影响任何使用该变量的客户端程序。mysql就是这样一个程序:

Press CTRL+C to copy
$> export LIBMYSQL_PLUGINS=simple_trace shqll> mysql Initializing trace: stage 0 Trace initialized Trace event received: stage 0, event 1 Trace event received: stage 0, event 2 ... Welcome to the MySQL monitor. Commands end with ; or \g. Trace event received Trace event received ... mysql> SELECT 1; Trace event received: stage 4, event 12 Trace event received: stage 4, event 16 ... Trace event received: stage 8, event 14 Trace event received: stage 8, event 15 +---+ | 1 | +---+ | 1 | +---+ 1 row in set (0.00 sec) mysql> quit Trace event received: stage 4, event 12 Trace event received: stage 4, event 16 Trace event received: stage 4, event 3 Connection closed Terminating trace Bye

要停止加载跟踪插件,请执行以下操作:

Press CTRL+C to copy
$> LIBMYSQL_PLUGINS=

也可以编写直接加载插件的客户端程序。mysql_options()您可以通过调用设置 MYSQL_PLUGIN_DIR选项 来告诉客户端插件目录所在的位置 :

Press CTRL+C to copy
char *plugin_dir = "path_to_plugin_dir"; /* ... process command-line options ... */ mysql_options(&mysql, MYSQL_PLUGIN_DIR, plugin_dir);

通常,该程序还将接受一个 --plugin-dir选项,使用户能够覆盖默认值。

如果客户端程序需要较低级别的插件管理,则客户端库包含带有st_mysql_client_plugin参数的函数。请参阅 C API 客户端插件接口