To use your own protocol trace plugins, you must configure
MySQL with the
WITH_TEST_TRACE_PLUGIN
CMake option
disabled because only one protocol
trace plugin can be loaded at a time and an error occurs
for attempts to load a second one. If you have already
built MySQL with the test protocol trace plugin enabled to
see how it works, you must rebuild MySQL without it before
you can use your own plugins.
This section discusses how to write a basic protocol trace
plugin named simple_trace
. This plugin
provides a framework showing how to set up the client plugin
descriptor and create the trace-related callback functions.
In simple_trace
, these functions are
rudimentary and do little other than illustrate the
arguments required. To see in detail how a trace plugin can
make use of trace event information, check the source file
for the test protocol trace plugin
(test_trace_plugin.cc
in the
libmysql
directory of a MySQL source
distribution). However, note that the
st_mysql_client_plugin_TRACE
structure
used there differs from the structures used with the usual
client plugin declaration macros. In particular, the first
two members are defined explicitly, not implicitly by
declaration macros.
Several header files contain information relevant to protocol trace plugins:
client_plugin.h
: Defines the API for client plugins. This includes the client plugin descriptor and function prototypes for client plugin C API calls (see C API Client Plugin Interface).plugin_trace.h
: Contains declarations for client-side plugins of typeMYSQL_CLIENT_TRACE_PLUGIN
. It also contains descriptions of the permitted protocol stages, transitions between stages, and the types of events permitted at each stage.
To write a protocol trace plugin, include the following header files in the plugin source file. Other MySQL or general header files might also be needed, depending on the plugin capabilities and requirements.
#include <mysql/plugin_trace.h>
#include <mysql.h>
plugin_trace.h
includes
client_plugin.h
, so you need not
include the latter file explicitly.
Declare the client-side plugin descriptor with the
mysql_declare_client_plugin()
and
mysql_end_client_plugin
macros (see
Section 4.4.2.3, “Client Plugin Descriptors”). For the
simple_trace
plugin, the descriptor looks
like this:
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;
The descriptor members from the plugin name through the option-handling function are common to all client plugin types. The members following the common members implement trace event handling.
Function members for which the plugin needs no processing
can be declared as NULL
in the
descriptor, in which case you need not write any
corresponding function. For illustration purposes and to
show the argument syntax, the following discussion
implements all functions listed in the descriptor, even
though some of them do nothing,
The initialization, deinitialization, and options functions common to all client plugins are declared as follows. For a description of the arguments and return values, see Section 4.4.2.3, “Client Plugin Descriptors”.
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;
}
The trace-specific members of the client plugin descriptor are callback functions. The following descriptions provide more detail on how they are used. Each has a first argument that is a pointer to the plugin instance in case your implementation needs to access it.
trace_start()
: This function is called at
the start of each traced connection (each connection that
starts after the plugin is loaded). It is passed the
connection handler and the protocol stage at which tracing
starts. trace_start()
allocates memory
needed by the trace_event()
function, if
any, and returns a pointer to it. If no memory is needed,
this function returns 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()
: This function is called
when tracing of the connection ends. That usually happens
when the connection is closed, but can happen earlier. For
example, trace_event()
can return a
nonzero value at any time and that causes tracing of the
connection to terminate. trace_stop()
is
then called even though the connection has not ended.
trace_stop()
is passed the connection
handler and a pointer to the memory allocated by
trace_start()
(NULL
if
none). If the pointer is non-NULL
,
trace_stop()
should deallocate the
memory. This function returns no value.
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()
: This function is called
for each event occurrence. It is passed a pointer to the
memory allocated by trace_start()
(NULL
if none), the connection handler,
the current protocol stage and event codes, and event data.
This function returns 0 to continue tracing, nonzero if
tracing should stop.
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;
}
The tracing framework shuts down tracing of the connection
when the connection ends, so
trace_event()
should return nonzero only
if you want to terminate tracing of the connection early.
Suppose that you want to trace only connections for a
certain MySQL account. After authentication, you can check
the user name for the connection and stop tracing if it is
not the user in whom you are interested.
For each call to trace_event()
, the
st_trace_event_args
structure contains
the event data. It has this definition:
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;
};
For different event types, the
st_trace_event_args
structure contains
the information described following. All lengths are in
bytes. Unused members are set to
0
/NULL
.
AUTH_PLUGIN
event:
plugin_name The name of the plugin
SEND_COMMAND
event:
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
Other SEND_
and
xxx
events:
xxx
_RECEIVED
pkt Pointer to the data sent or received
pkt_len Length of the data
PACKET_SENT
event:
pkt_len Number of bytes sent
To compile and install a plugin library file, use the
instructions in
Section 4.4.3, “Compiling and Installing Plugin Libraries”. To make the
library file available for use, install it in the plugin
directory (the directory named by the
plugin_dir
system
variable).
After the plugin library file is compiled and installed in
the plugin directory, you can test it easily by setting the
LIBMYSQL_PLUGINS
environment variable to
the plugin name, which affects any client program that uses
that variable. mysql is one such program:
$> 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
To stop the trace plugin from being loaded, do this:
$> LIBMYSQL_PLUGINS=
It is also possible to write client programs that directly
load the plugin. You can tell the client where the plugin
directory is located by calling
mysql_options()
to set the
MYSQL_PLUGIN_DIR
option:
char *plugin_dir = "path_to_plugin_dir";
/* ... process command-line options ... */
mysql_options(&mysql, MYSQL_PLUGIN_DIR, plugin_dir);
Typically, the program will also accept a
--plugin-dir
option that enables users to
override the default value.
Should a client program require lower-level plugin
management, the client library contains functions that take
an st_mysql_client_plugin
argument. See
C API Client Plugin Interface.