Provides an opt-in observability surface that records every AI request (provider, model, duration, token counts, status, and request source) and exposes them through a React-powered dashboard under Tools → AI Request Logs. When enabled, the SDK's HTTP transporter is wrapped with a logging decorator using the public setHttpTransporter() API.
WordPress\AI\Experiments\AI_Request_Logging\AI_Request_Logging::register():- Calls
AI_Request_Log_Manager::init()to ensure the log table schema is synchronized and the cleanup cron exists. - Calls
Logging_Integration::init()so the SDK transporter is wrapped only while the feature is enabled. rest_api_init→ registersWordPress\AI\Logging\REST\AI_Request_Log_Controller, which exposes/ai/v1/logs,/summary,/filters, and per-log endpoints.admin_menu→ registersWordPress\AI\Logging\AI_Request_Log_Page, which adds theToolssubmenu and enqueues assets.
- Calls
- Database + cleanup are handled inside
AI_Request_Log_Manager::init()(schema-version-gated table sync, cron scheduling, option storage).
The logging system uses the decorator pattern to wrap the SDK's HTTP transporter:
Logging_Integration::init()is called from the feature registration flow when the experiment is enabled.- On
wp_loadedoradmin_init,Logging_Integration::wrap_transporter():- Gets the current transporter from
AiClient::defaultRegistry() - Creates a
Logging_Http_Transporterdecorator around it - Uses
registry->setHttpTransporter()to swap in the logging version
- Gets the current transporter from
- All subsequent AI requests go through the logging transporter, which records metrics before delegating to the underlying transporter.
Logging_Http_Transporteralso inspects the PHP call stack to record whether the request was initiated by a plugin, mu-plugin, theme, or WordPress core file when that can be determined.- Data extraction is handled by
Log_Data_Extractor, which parses request/response payloads and extracts provider, model, tokens, and previews.
This approach uses the SDK's public API rather than reflection or internal hacks, making it resilient to SDK updates.
The logging system exposes several filter hooks for extensibility:
Filters the provider detection patterns. The default map is derived from the connectors registry — every ai_provider connector contributes a host-substring pattern equal to its slug (with google matching googleapis since its API runs on a different domain). This filter is the extension point for non-connector providers or for connectors whose slug doesn't appear in their API host (for example, a connector whose API is served from an unrelated domain).
add_filter( 'wpai_request_log_providers', function( $patterns ) {
$patterns['my_provider'] = array( 'my-api.com', 'api.myprovider.io' );
return $patterns;
} );Filters the log context data before it's stored. Allows adding custom context or removing sensitive data.
add_filter( 'wpai_request_log_context', function( $context, $decoded, $log_data ) {
$context['custom_field'] = 'custom_value';
unset( $context['sensitive_field'] );
return $context;
}, 10, 3 );Filters the extracted token usage. Allows custom providers to supply their own token extraction logic.
add_filter( 'wpai_request_log_tokens', function( $tokens, $response ) {
if ( isset( $response['my_token_field'] ) ) {
$tokens['input'] = $response['my_token_field']['in'];
$tokens['output'] = $response['my_token_field']['out'];
}
return $tokens;
}, 10, 2 );Filters the detected request kind (text, image, embeddings, audio, metadata).
add_filter( 'wpai_request_log_kind', function( $kind, $provider, $path, $payload ) {
if ( false !== strpos( $path, '/my-custom-endpoint' ) ) {
return 'custom';
}
return $kind;
}, 10, 4 );Filters the time-based retention period in days. Logs are retained indefinitely by default (the filter returns 0). Return a positive integer to delete entries older than that many days during the daily cleanup.
add_filter( 'wpai_request_log_retention_days', function() {
return 30;
} );- When
AI Request Logsis visited,Asset_Loaderenqueuesadmin/ai-request-logs(src/admin/ai-request-logs/index.tsx) plus its stylesheet. The localized payload (window.AiRequestLogsSettings) includes REST routes, a nonce, and initial state (summary and filter metadata). - The React app:
- Configures
@wordpress/api-fetchwith the nonce/root. - Fetches logs (
GET /ai/v1/logswith search/filter params) and displays them in a table with pagination. - Uses a persisted operations multi-select that excludes
*:modelsdiscovery calls by default so capability lookups do not drown out actual request traffic unless the user opts in. - Fetches summaries (
GET /ai/v1/logs/summary) for the KPI cards, includingminute,hour,day,week,month, andallperiods, and filter metadata (GET /ai/v1/logs/filters). - Sends
DELETE /ai/v1/logsto purge the table.
- Configures
- On the backend, every AI HTTP request flows through
Logging_Http_Transporter, which records metrics viaAI_Request_Log_Manager::log()before returning the response to callers. Logs are stored in thewp_ai_request_logstable alongside JSON-encoded context for later inspection.
- Enable Experiments globally, toggle AI Request Logging, and ensure valid AI credentials exist (the experiment won't enable otherwise).
- Trigger an AI-powered feature (e.g., Type Ahead or Title Generation) so the system issues at least one completion request.
- Navigate to
Tools → AI Request Logs. Confirm the chart and table populate, and that*:modelsdiscovery calls only appear after you explicitly include them in the operations filter. - Click "Purge logs", confirm the success notice, and check the table empties.
- Disable the experiment and reload a front-end AI feature; no new rows should appear, and the logging integration should remain inactive.
- Logs are retained indefinitely by default. Add an
wpai_request_log_retention_daysfilter returning a positive integer if you want time-based cleanup. - REST endpoints require
manage_options.