Migrate to the audit log filter component¶
Percona Server for MySQL 9.7 replaces two legacy audit sources with component_audit_log_filter. The legacy sources are the audit_log plugin and the transitional audit_log_filter plugin.
This page covers migration from either source. The page maps plugin configuration to the component’s system variables and filter JSON, and walks through a safe cutover.
Before you start, read:
- Upgrade from plugins to components — timing, general procedure, and which plugins transition before or after the server upgrade.
- Audit Log Filter overview — what the component is and why it replaces the plugin.
- Install the audit log filter — install script, component URN, and the
mysql.audit_log_filter/mysql.audit_log_usertables.
Note
The component and the plugin use different system variables and a different on-disk format. Do not enable both at the same time, and do not set audit_log_* plugin variables on a server running the component. See the deprecation notice on the plugin page.
Which source are you migrating from?¶
Two legacy sources exist. The target is component_audit_log_filter in both cases. The starting point differs:
| Source | Recommended path |
|---|---|
audit_log plugin (pre-8.4 installs, still available in 9.7 as a deprecated plugin) |
Upgrade to 9.7, install the component, translate audit_log_* variables to filter JSON, validate in parallel, then uninstall the plugin. |
audit_log_filter plugin (transitional, 8.0 and early 8.4 builds) |
Upgrade to 9.7 first, then transition to the component per Upgrade from plugins to components → Transition after upgrade. |
The following detailed mapping targets the audit_log plugin because the plugin’s configuration model — global audit_log_* variables and policy presets — differs most from the component. If you are migrating from the audit_log_filter plugin, the filter JSON you already wrote continues to work unchanged; the migration reduces to a shorter path:
- Upgrade the server to 9.7.
- Uninstall the plugin.
- Run the component install script. See Install the audit log filter. The script creates
mysql.audit_log_filterandmysql.audit_log_userand registers the component. - Re-apply each filter with
audit_log_filter_set_filter()and re-assign accounts withaudit_log_filter_set_user(). When you exported the plugin’s filter and user tables, those rows can be re-inserted directly. - Move non-filter settings (file path, format, rotation, syslog) from
audit_log_filter_*plugin variables to theaudit_log_filter.*component variables listed in the variable mapping.
See also Upgrade from plugins to components → Transition after upgrade.
What changes, at a glance¶
-
Configuration moves from global
audit_log_*system variables into JSON filter definitions stored inmysql.audit_log_filter, plus per-account assignments inmysql.audit_log_user. -
Scope moves from a single global include/exclude list to per-account assignments.
admin@%andapp@%can use different filters on the same server. -
Rule changes require no restart or plugin reinstall. Update the JSON with
audit_log_filter_set_filter(), and the next session applies the change. -
Log format names shift. The plugin’s
OLD,NEW,JSON, andCSVmap to the component’sJSONL(default),JSON, andNEW. The component does not emitOLDXML orCSV. -
The
audit_log_handler = SYSLOGpath becomesaudit_log_filter.handler = SYSLOG. The syslog sub-variables use the same values under renamed component names.
Migration steps¶
- Inventory the current configuration. On the plugin-enabled server, capture the legacy settings:
SHOW VARIABLES LIKE 'audit_log_%';
Save the output. Translate each non-default value into a component variable, a filter JSON rule, or an audit_log_filter_set_user() call.
-
Upgrade the server to 9.7 by following Upgrade procedures. The
audit_logplugin remains loadable in 9.7, so the old log keeps flowing during the transition. -
Install the component per Install the audit log filter. The install script creates
mysql.audit_log_filterandmysql.audit_log_user, then runsINSTALL COMPONENT. -
Translate configuration using the two mapping tables that follow. Apply non-filter settings (file path, format, rotation, syslog) as component variables. Apply scope settings (policy, include/exclude lists) as a filter definition plus user assignments.
-
Run in parallel (optional, recommended). Load both the plugin and the component. Verify that the events you care about appear in the component’s log. Compare record types, SQL text, and redactions.
-
Cut over. Uninstall the plugin (
UNINSTALL PLUGIN audit_log;), removeaudit_log_*entries frommy.cnf, and leave the component as the sole audit writer. When you also had the transitionalaudit_log_filterplugin loaded, uninstall that plugin as well. -
Verify. Log in as a subject account, execute a representative statement, and read the new log with
audit_log_read()or by opening the file.
Option and variable mapping¶
The following table maps plugin system variables (left) to component system variables (right). Variables not listed have no direct equivalent because the filter JSON grammar subsumes them.
| Plugin variable | Component equivalent | Notes |
|---|---|---|
audit_log_file |
audit_log_filter.file |
Default file name and data-directory placement differ; see Log file naming. |
audit_log_format (OLD/NEW/JSON/CSV) |
audit_log_filter.format (JSONL/JSON/NEW) |
Component default is JSONL. The component does not emit OLD XML or CSV; pick NEW to stay on XML or use JSONL/JSON (see JSON and JSONL). |
audit_log_strategy |
audit_log_filter.strategy |
Same ASYNCHRONOUS / PERFORMANCE / SEMISYNCHRONOUS / SYNCHRONOUS trade-offs. |
audit_log_buffer_size |
audit_log_filter.buffer_size |
Applies to ASYNCHRONOUS / PERFORMANCE. |
audit_log_rotate_on_size |
audit_log_filter.rotate_on_size |
Size-based rotation. |
audit_log_rotations |
audit_log_filter.prune_seconds + audit_log_filter.max_size |
The component prunes by age and total size instead of a fixed file count. Convert “keep N files” to an age or total-size budget. |
audit_log_flush |
audit_log_rotate() |
Manual rotation uses a UDF call instead of a variable toggle. |
audit_log_handler (FILE / SYSLOG) |
audit_log_filter.handler |
Same two values. |
audit_log_syslog_ident |
audit_log_filter.syslog_tag |
Renamed. |
audit_log_syslog_facility |
audit_log_filter.syslog_facility |
— |
audit_log_syslog_priority |
audit_log_filter.syslog_priority |
— |
audit_log_policy |
(filter JSON) | Translate to class selection — see Translating audit_log_policy. |
audit_log_include_accounts / audit_log_exclude_accounts |
(filter JSON + audit_log_filter_set_user()) |
Per-account assignment replaces global lists — see Translating include / exclude account lists. |
audit_log_include_commands / audit_log_exclude_commands |
(filter JSON) | Use log conditions that test general_sql_command.str. |
audit_log_include_databases / audit_log_exclude_databases |
(filter JSON) | Use log conditions that test table_database.str in table_access. |
Component-only features with no plugin counterpart include:
-
Block-on-match with
abort -
Field redaction with
printandreplace -
Predefined variables and functions inside conditions
-
Dynamic filter swapping with
activateandref
See Write filter definitions and the sub-pages.
Translating audit_log_policy to filter JSON¶
audit_log_policy gated what the plugin recorded. The component expresses the same four choices as filter definitions:
| Plugin policy | Equivalent filter definition |
|---|---|
ALL |
Log everything the component sees (respects audit_log_filter.event_mode): { "filter": { "log": true } } |
LOGINS |
{ "filter": { "class": { "name": "connection" } } } |
QUERIES |
{ "filter": { "class": [ { "name": "general" }, { "name": "table_access" } ] } } |
NONE |
Either do not assign a filter to the account, or bind an empty filter: { "filter": {} } |
Install any of these with audit_log_filter_set_filter() and assign them with audit_log_filter_set_user(). For example:
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
SELECT audit_log_filter_set_user('%', 'log_all');
Translating include/exclude lists¶
The plugin filtered globally. The component filters per account through audit_log_user and per event through log conditions that compare event fields. Most migrations combine both.
Accounts¶
Plugin:
SET GLOBAL audit_log_include_accounts = 'app@%,admin@localhost';
Component — assign a logging filter to the two accounts and leave the default % with no filter (or an empty filter):
SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
SELECT audit_log_filter_set_user('app@%', 'log_all');
SELECT audit_log_filter_set_user('admin@localhost','log_all');
Plugin exclude list, inverted:
SET GLOBAL audit_log_exclude_accounts = 'monitor@%';
Component — keep the default % assigned to a logging filter and assign monitor@% to an empty filter (or leave it unassigned if % has no filter):
SELECT audit_log_filter_set_filter('no_log', '{ "filter": {} }');
SELECT audit_log_filter_set_user('monitor@%', 'no_log');
Commands¶
Plugin:
SET GLOBAL audit_log_include_commands = 'select,insert,update,delete';
Component — narrow the general class with a log condition that tests general_sql_command.str:
SELECT audit_log_filter_set_filter('log_dml', '{
"filter": {
"class": {
"name": "general",
"log": {
"field": {
"name": "general_sql_command.str",
"value": ["select", "insert", "update", "delete"]
}
}
}
}
}');
For exclusion, wrap the condition in not.
Databases¶
Plugin:
SET GLOBAL audit_log_include_databases = 'app,reports';
Component — narrow table_access by table_database.str:
SELECT audit_log_filter_set_filter('log_app_reports', '{
"filter": {
"class": {
"name": "table_access",
"log": {
"field": {
"name": "table_database.str",
"value": ["app", "reports"]
}
}
}
}
}');
For a complete grammar reference (field names, logical operators, variables, functions), see Write filter definitions and Definition fields reference.
Worked example¶
Starting plugin configuration in my.cnf:
[mysqld]
plugin-load-add = audit_log.so
audit_log_format = JSON
audit_log_policy = ALL
audit_log_include_accounts = app@%,admin@localhost
audit_log_exclude_commands = set_option
audit_log_rotate_on_size = 104857600
audit_log_rotations = 10
After upgrading to 9.7 and running audit_log_filter_linux_install.sql, replace it with:
[mysqld]
audit_log_filter.format = JSON
audit_log_filter.rotate_on_size = 104857600
audit_log_filter.prune_seconds = 2592000
Then define the filter and assign accounts:
SELECT audit_log_filter_set_filter('log_all_except_set_option', '{
"filter": {
"class": [
{ "name": "connection" },
{ "name": "table_access" },
{
"name": "general",
"log": {
"not": {
"field": { "name": "general_sql_command.str", "value": "set_option" }
}
}
}
]
}
}');
SELECT audit_log_filter_set_user('app@%', 'log_all_except_set_option');
SELECT audit_log_filter_set_user('admin@localhost', 'log_all_except_set_option');
Accounts that match neither app@% nor admin@localhost, and that have no explicit assignment to the default % filter, are not audited. The setup reproduces the plugin’s include-list behavior.
Cutover and verification¶
-
Confirm the component is live:
SELECT * FROM mysql.component WHERE component_urn = 'file://component_audit_log_filter'; -
Log in as a subject account, run a representative statement, and read the new log:
SELECT audit_log_read('{}');See Read log files.
-
Uninstall the legacy plugin and clear its settings from
my.cnf:UNINSTALL PLUGIN audit_log; -
Rotate once so new writes go to a fresh file under the component’s naming scheme:
SELECT audit_log_rotate(); -
Archive any pre-existing plugin log files you want to keep. The component does not ingest those files. You can run
filter_audit_log_filter_filesto post-process component logs.
Known caveats¶
-
Log content changes slightly even when you keep the same format. Some statements that the 8.0 plugin did not record appear in current logs because the server sends additional events. The plugin page describes the
SELECT $$example. Percona does not plan to backport format changes to match 8.0 output. -
The component stores state in
mysql.audit_log_filterandmysql.audit_log_user. Back up those tables before making bulk changes, and include the tables in standardmysqldatabase backups. -
Lifecycle events —
server_startup,server_shutdown, and theauditclass itself — are not valid filter targets. See Definition fields reference. -
audit_log_filter.event_modedefaults toREDUCED. When you relied on plugin logging for classes beyondconnection,general,table_access, andmessage, setevent_mode = FULLto match the broader class set.
Additional reading¶
-
Audit log plugin — legacy reference, with the deprecation notice