擴展 MySQL 9.0  /  ...  /  使用您自己的協議追蹤外掛程式

4.4.11.2 使用您自己的協議追蹤外掛程式

注意

若要使用您自己的協議追蹤外掛程式,您必須使用 WITH_TEST_TRACE_PLUGIN CMake 選項將 MySQL 設定為 停用,因為一次只能載入一個協議追蹤外掛程式,且嘗試載入第二個外掛程式時會發生錯誤。如果您已經使用啟用測試協議追蹤外掛程式的方式來建置 MySQL 以瞭解其運作方式,則必須在您可以使用自己的外掛程式之前,重新建置不含該外掛程式的 MySQL。

本節討論如何撰寫名為 simple_trace 的基本協議追蹤外掛程式。此外掛程式提供一個架構,說明如何設定用戶端外掛程式描述符,並建立追蹤相關的回呼函式。在 simple_trace 中,這些函式很基本,除了說明必要的引數之外,幾乎沒有其他作用。若要詳細瞭解追蹤外掛程式如何使用追蹤事件資訊,請檢查測試協議追蹤外掛程式的原始碼檔案(MySQL 來源發行版 libmysql 目錄中的 test_trace_plugin.cc)。但是,請注意,其中使用的 st_mysql_client_plugin_TRACE 結構與一般用戶端外掛程式宣告巨集中使用的結構不同。特別是,前兩個成員是明確定義的,而不是由宣告巨集隱含定義的。

數個標頭檔包含與協議追蹤外掛程式相關的資訊

  • client_plugin.h:定義用戶端外掛程式的 API。這包含用戶端外掛程式描述符和用於用戶端外掛程式 C API 呼叫的函式原型(請參閱 C API 用戶端外掛程式介面)。

  • plugin_trace.h:包含 MYSQL_CLIENT_TRACE_PLUGIN 類型用戶端外掛程式的宣告。它也包含允許的協議階段、階段之間的轉換以及每個階段允許的事件類型的描述。

若要撰寫協議追蹤外掛程式,請在外掛程式原始碼檔案中包含下列標頭檔。根據外掛程式功能和需求,也可能需要其他 MySQL 或一般標頭檔。

#include <mysql/plugin_trace.h>
#include <mysql.h>

plugin_trace.h 包含 client_plugin.h,因此您不需要明確包含後者檔案。

使用 mysql_declare_client_plugin()mysql_end_client_plugin 巨集宣告用戶端外掛程式描述符(請參閱第 4.4.2.3 節「用戶端外掛程式描述符」)。對於 simple_trace 外掛程式,描述符如下所示

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 節「用戶端外掛程式描述符」

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

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() 應該解除配置記憶體。此函式不傳回任何值。

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 以繼續追蹤,如果應該停止追蹤,則會傳回非零值。

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 結構會包含事件資料。其定義如下

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 事件

plugin_name  The name of the plugin

SEND_COMMAND 事件

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 事件

pkt          Pointer to the data sent or received
pkt_len      Length of the data

PACKET_SENT 事件

pkt_len      Number of bytes sent

若要編譯和安裝外掛程式庫檔案,請使用第 4.4.3 節「編譯和安裝外掛程式庫」中的指示。若要讓程式庫檔案可供使用,請將其安裝在外掛程式目錄中(由 plugin_dir 系統變數命名的目錄)。

在外掛程式庫檔案編譯並安裝在外掛程式目錄中之後,您可以輕鬆地測試它,方法是將 LIBMYSQL_PLUGINS 環境變數設定為外掛程式名稱,這會影響使用該變數的任何用戶端程式。 mysql 就是這樣的一個程式

$> 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

若要停止載入追蹤外掛程式,請執行此操作

$> LIBMYSQL_PLUGINS=

也可以撰寫直接載入外掛程式的用戶端程式。您可以透過呼叫 mysql_options() 來設定 MYSQL_PLUGIN_DIR 選項,告訴用戶端外掛程式目錄的位置

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 用戶端外掛程式介面