Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions includes/class-bigquery-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,24 @@ public function push_metrics( $metrics ) {
rewind( $stream );
$schema = array(
'fields' => array(
array( 'name' => 'timestamp_utc', 'type' => 'TIMESTAMP' ),
array( 'name' => 'timestamp_utc', 'type' => 'TIMESTAMP' ),
array( 'name' => 'site_url', 'type' => 'STRING' ),
// Autoload.
array( 'name' => 'autoloaded_option_count', 'type' => 'INTEGER' ),
array( 'name' => 'autoloaded_option_size', 'type' => 'INTEGER' ),
array( 'name' => 'site_url', 'type' => 'STRING' ),
array( 'name' => 'autoloaded_option_size', 'type' => 'INTEGER' ),
// Plugins.
array( 'name' => 'active_plugin_count', 'type' => 'INTEGER' ),
array( 'name' => 'inactive_plugin_count', 'type' => 'INTEGER' ),
array( 'name' => 'total_plugin_count', 'type' => 'INTEGER' ),
// Hooks.
array( 'name' => 'hook_count', 'type' => 'INTEGER' ),
// Database.
array( 'name' => 'db_total_size_bytes', 'type' => 'INTEGER' ),
// WooCommerce orders.
array( 'name' => 'woo_order_items_size_bytes', 'type' => 'INTEGER' ),
array( 'name' => 'woo_order_itemmeta_size_bytes', 'type' => 'INTEGER' ),
array( 'name' => 'woo_oldest_order_age_days', 'type' => 'INTEGER' ),
array( 'name' => 'woo_archival_trigger', 'type' => 'INTEGER' ),
),
);

Expand Down
177 changes: 173 additions & 4 deletions includes/class-data-collector.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ class ProPerf_Data_Collector {
* @return array Collected metrics.
*/
public function get_data() {
return $this->collect_autoloaded_options();
return array_merge(
$this->collect_autoloaded_options(),
$this->collect_plugin_metrics(),
$this->collect_hook_metrics(),
$this->collect_db_table_metrics(),
$this->collect_woo_order_metrics()
);
}

/**
Expand Down Expand Up @@ -67,21 +73,184 @@ public function collect_autoloaded_options() {
);
}

/**
* Collect plugin metrics.
*
* Counts active and inactive plugins installed on the site.
*
* @return array Plugin metrics.
*/
public function collect_plugin_metrics() {
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

$all_plugins = get_plugins();
$active_plugins = get_option( 'active_plugins', array() );
$active_count = count( $active_plugins );
$total_count = count( $all_plugins );
$inactive_count = $total_count - $active_count;

return array(
'plugins' => array(
'active_count' => $active_count,
'inactive_count' => $inactive_count,
'total_count' => $total_count,
),
);
}

/**
* Collect hook metrics.
*
* Counts registered hooks via $wp_filter.
*
* @return array Hook metrics.
*/
public function collect_hook_metrics() {
global $wp_filter;
$hook_count = is_array( $wp_filter ) ? count( $wp_filter ) : 0;

return array(
'hooks' => array(
'registered_count' => $hook_count,
),
);
}

/**
* Collect database table size metrics.
*
* Reports total DB size and top 10 tables by size.
*
* @return array Database size metrics.
*/
public function collect_db_table_metrics() {
global $wpdb;

$total_size = $wpdb->get_var(
'SELECT SUM(data_length + index_length)
FROM information_schema.tables
WHERE table_schema = DATABASE()'
);

$top_tables = $wpdb->get_results(
'SELECT table_name, ROUND(data_length + index_length) AS size_bytes
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY size_bytes DESC LIMIT 10',
ARRAY_A
);

$top_tables_map = array();
if ( $top_tables ) {
foreach ( $top_tables as $table ) {
$name = $table['table_name'] ?? $table['TABLE_NAME'] ?? '';
$top_tables_map[ $name ] = intval( $table['size_bytes'] ?? $table['SIZE_BYTES'] ?? 0 );
}
}

return array(
'database' => array(
'total_size_bytes' => $total_size ? intval( $total_size ) : 0,
'top_tables' => $top_tables_map,
),
);
}

/**
* Collect WooCommerce order table metrics.
*
* Measures order_items and order_itemmeta table sizes, oldest order age,
* and sets an archival trigger flag when orders older than 365 days exist.
* Returns zeros with woo_active=false when WooCommerce is not installed.
*
* @return array WooCommerce order metrics.
*/
public function collect_woo_order_metrics() {
if ( ! class_exists( 'WooCommerce' ) ) {
return array(
'woo_orders' => array(
'woo_active' => false,
'order_items_size_bytes' => 0,
'order_itemmeta_size_bytes' => 0,
'oldest_order_age_days' => 0,
'archival_trigger' => false,
),
);
}

global $wpdb;

$order_items_table = $wpdb->prefix . 'woocommerce_order_items';
$order_itemmeta_table = $wpdb->prefix . 'woocommerce_order_itemmeta';

$order_items_size = $wpdb->get_var(
$wpdb->prepare(
'SELECT ROUND(data_length + index_length)
FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = %s',
$order_items_table
)
);

$order_itemmeta_size = $wpdb->get_var(
$wpdb->prepare(
'SELECT ROUND(data_length + index_length)
FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = %s',
$order_itemmeta_table
)
);

$oldest_order_age_days = $wpdb->get_var(
"SELECT DATEDIFF(NOW(), MIN(post_date))
FROM {$wpdb->posts}
WHERE post_type IN ('shop_order', 'wc_order')
AND post_status != 'trash'"
);
$oldest_order_age_days = $oldest_order_age_days ? intval( $oldest_order_age_days ) : 0;

return array(
'woo_orders' => array(
'woo_active' => true,
'order_items_size_bytes' => $order_items_size ? intval( $order_items_size ) : 0,
'order_itemmeta_size_bytes' => $order_itemmeta_size ? intval( $order_itemmeta_size ) : 0,
'oldest_order_age_days' => $oldest_order_age_days,
'archival_trigger' => $oldest_order_age_days > 365,
),
);
}

/**
* Format metrics for BigQuery.
*
* @param array $metrics Metrics data.
* @return array Formatted data for BigQuery.
*/
public function format_for_bigquery( $metrics ) {
$site_url = get_site_url();
$site_url = get_site_url();
$timestamp = gmdate( 'Y-m-d H:i:s' );

return array(
'timestamp_utc' => $timestamp,
'timestamp_utc' => $timestamp,
'site_url' => $site_url,
// Autoload.
'autoloaded_option_count' => $metrics['autoloaded_option']['count'],
'autoloaded_option_size' => $metrics['autoloaded_option']['size_bytes'],
'site_url' => $site_url,
// Plugins.
'active_plugin_count' => $metrics['plugins']['active_count'],
'inactive_plugin_count' => $metrics['plugins']['inactive_count'],
'total_plugin_count' => $metrics['plugins']['total_count'],
// Hooks.
'hook_count' => $metrics['hooks']['registered_count'],
// Database.
'db_total_size_bytes' => $metrics['database']['total_size_bytes'],
// WooCommerce orders.
'woo_order_items_size_bytes' => $metrics['woo_orders']['order_items_size_bytes'],
'woo_order_itemmeta_size_bytes' => $metrics['woo_orders']['order_itemmeta_size_bytes'],
'woo_oldest_order_age_days' => $metrics['woo_orders']['oldest_order_age_days'],
'woo_archival_trigger' => $metrics['woo_orders']['archival_trigger'] ? 1 : 0,
);
}
}
Loading