0, 'error_count' => 0, 'warning_count' => 0, 'info_count' => 0, 'debug_count' => 0, 'daily_stats' => array(), 'hourly_stats' => array(), 'top_errors' => array(), 'subscription_stats' => array(), 'payment_stats' => array(), 'performance_issues' => array() ); foreach ($logs as $log_line) { $parsed_log = self::parse_log_line($log_line); if (!$parsed_log || $parsed_log['timestamp'] < $cutoff_date) { continue; } $analysis['total_logs']++; // 统计日志级别 $level = $parsed_log['level']; if (isset($analysis[$level . '_count'])) { $analysis[$level . '_count']++; } // 按日统计 $date = date('Y-m-d', strtotime($parsed_log['timestamp'])); if (!isset($analysis['daily_stats'][$date])) { $analysis['daily_stats'][$date] = array( 'total' => 0, 'error' => 0, 'warning' => 0, 'info' => 0, 'debug' => 0 ); } $analysis['daily_stats'][$date]['total']++; $analysis['daily_stats'][$date][$level]++; // 按小时统计 $hour = date('H', strtotime($parsed_log['timestamp'])); if (!isset($analysis['hourly_stats'][$hour])) { $analysis['hourly_stats'][$hour] = 0; } $analysis['hourly_stats'][$hour]++; // 收集错误信息 if ($level === 'error') { $error_key = md5($parsed_log['message']); if (!isset($analysis['top_errors'][$error_key])) { $analysis['top_errors'][$error_key] = array( 'message' => $parsed_log['message'], 'count' => 0, 'first_seen' => $parsed_log['timestamp'], 'last_seen' => $parsed_log['timestamp'] ); } $analysis['top_errors'][$error_key]['count']++; $analysis['top_errors'][$error_key]['last_seen'] = $parsed_log['timestamp']; } // 订阅相关统计 if (strpos($parsed_log['message'], 'subscription') !== false) { $analysis['subscription_stats']['total'] = ($analysis['subscription_stats']['total'] ?? 0) + 1; if (strpos($parsed_log['message'], 'created') !== false) { $analysis['subscription_stats']['created'] = ($analysis['subscription_stats']['created'] ?? 0) + 1; } elseif (strpos($parsed_log['message'], 'cancelled') !== false) { $analysis['subscription_stats']['cancelled'] = ($analysis['subscription_stats']['cancelled'] ?? 0) + 1; } elseif (strpos($parsed_log['message'], 'renewed') !== false) { $analysis['subscription_stats']['renewed'] = ($analysis['subscription_stats']['renewed'] ?? 0) + 1; } } // 支付相关统计 if (strpos($parsed_log['message'], 'payment') !== false) { $analysis['payment_stats']['total'] = ($analysis['payment_stats']['total'] ?? 0) + 1; if (strpos($parsed_log['message'], 'success') !== false) { $analysis['payment_stats']['success'] = ($analysis['payment_stats']['success'] ?? 0) + 1; } elseif (strpos($parsed_log['message'], 'failed') !== false) { $analysis['payment_stats']['failed'] = ($analysis['payment_stats']['failed'] ?? 0) + 1; } } // 性能问题检测 if (strpos($parsed_log['message'], 'timeout') !== false || strpos($parsed_log['message'], 'slow') !== false || strpos($parsed_log['message'], 'memory') !== false) { $analysis['performance_issues'][] = array( 'timestamp' => $parsed_log['timestamp'], 'message' => $parsed_log['message'], 'level' => $level ); } } // 排序错误统计 uasort($analysis['top_errors'], function($a, $b) { return $b['count'] - $a['count']; }); // 只保留前10个错误 $analysis['top_errors'] = array_slice($analysis['top_errors'], 0, 10, true); return $analysis; } /** * 生成健康报告 * * @return array 健康报告 */ public static function generate_health_report() { $analysis = self::analyze_recent_logs(7); $health_score = 100; $issues = array(); $recommendations = array(); // 错误率检查 $error_rate = $analysis['total_logs'] > 0 ? ($analysis['error_count'] / $analysis['total_logs']) * 100 : 0; if ($error_rate > 10) { $health_score -= 30; $issues[] = sprintf(__('错误率过高: %.1f%%', 'yoone-subscriptions'), $error_rate); $recommendations[] = __('检查并修复频繁出现的错误', 'yoone-subscriptions'); } elseif ($error_rate > 5) { $health_score -= 15; $issues[] = sprintf(__('错误率较高: %.1f%%', 'yoone-subscriptions'), $error_rate); } // 警告率检查 $warning_rate = $analysis['total_logs'] > 0 ? ($analysis['warning_count'] / $analysis['total_logs']) * 100 : 0; if ($warning_rate > 20) { $health_score -= 20; $issues[] = sprintf(__('警告率过高: %.1f%%', 'yoone-subscriptions'), $warning_rate); $recommendations[] = __('关注警告信息,预防潜在问题', 'yoone-subscriptions'); } // 支付失败率检查 if (isset($analysis['payment_stats']['total']) && $analysis['payment_stats']['total'] > 0) { $payment_failure_rate = (($analysis['payment_stats']['failed'] ?? 0) / $analysis['payment_stats']['total']) * 100; if ($payment_failure_rate > 15) { $health_score -= 25; $issues[] = sprintf(__('支付失败率过高: %.1f%%', 'yoone-subscriptions'), $payment_failure_rate); $recommendations[] = __('检查支付网关配置和网络连接', 'yoone-subscriptions'); } } // 性能问题检查 if (count($analysis['performance_issues']) > 5) { $health_score -= 20; $issues[] = sprintf(__('发现 %d 个性能问题', 'yoone-subscriptions'), count($analysis['performance_issues'])); $recommendations[] = __('优化代码性能,检查服务器资源', 'yoone-subscriptions'); } // 频繁错误检查 foreach ($analysis['top_errors'] as $error) { if ($error['count'] > 10) { $health_score -= 10; $issues[] = sprintf(__('频繁错误: %s (出现 %d 次)', 'yoone-subscriptions'), substr($error['message'], 0, 50) . '...', $error['count']); break; } } // 确保分数不低于0 $health_score = max(0, $health_score); // 健康等级 if ($health_score >= 90) { $health_level = 'excellent'; $health_text = __('优秀', 'yoone-subscriptions'); } elseif ($health_score >= 70) { $health_level = 'good'; $health_text = __('良好', 'yoone-subscriptions'); } elseif ($health_score >= 50) { $health_level = 'fair'; $health_text = __('一般', 'yoone-subscriptions'); } else { $health_level = 'poor'; $health_text = __('较差', 'yoone-subscriptions'); } return array( 'score' => $health_score, 'level' => $health_level, 'text' => $health_text, 'issues' => $issues, 'recommendations' => $recommendations, 'analysis' => $analysis ); } /** * 获取趋势数据 * * @param int $days 天数 * @return array 趋势数据 */ public static function get_trend_data($days = 30) { $analysis = self::analyze_recent_logs($days); $trends = array( 'daily_errors' => array(), 'daily_warnings' => array(), 'daily_total' => array(), 'subscription_activity' => array(), 'payment_activity' => array() ); // 填充每日数据 for ($i = $days - 1; $i >= 0; $i--) { $date = date('Y-m-d', strtotime("-{$i} days")); $trends['daily_errors'][$date] = $analysis['daily_stats'][$date]['error'] ?? 0; $trends['daily_warnings'][$date] = $analysis['daily_stats'][$date]['warning'] ?? 0; $trends['daily_total'][$date] = $analysis['daily_stats'][$date]['total'] ?? 0; } return $trends; } /** * 检测异常模式 * * @return array 异常模式 */ public static function detect_anomalies() { $analysis = self::analyze_recent_logs(7); $anomalies = array(); // 检测错误激增 $daily_errors = array(); foreach ($analysis['daily_stats'] as $date => $stats) { $daily_errors[] = $stats['error']; } if (count($daily_errors) >= 3) { $avg_errors = array_sum($daily_errors) / count($daily_errors); $latest_errors = end($daily_errors); if ($latest_errors > $avg_errors * 2 && $latest_errors > 5) { $anomalies[] = array( 'type' => 'error_spike', 'severity' => 'high', 'message' => sprintf(__('今日错误数量异常增加: %d (平均: %.1f)', 'yoone-subscriptions'), $latest_errors, $avg_errors), 'timestamp' => current_time('mysql') ); } } // 检测重复错误 foreach ($analysis['top_errors'] as $error) { if ($error['count'] > 20) { $anomalies[] = array( 'type' => 'repeated_error', 'severity' => 'medium', 'message' => sprintf(__('重复错误: %s (出现 %d 次)', 'yoone-subscriptions'), substr($error['message'], 0, 100), $error['count']), 'timestamp' => $error['last_seen'] ); } } // 检测支付问题 if (isset($analysis['payment_stats']['failed']) && $analysis['payment_stats']['failed'] > 10) { $anomalies[] = array( 'type' => 'payment_issues', 'severity' => 'high', 'message' => sprintf(__('支付失败次数过多: %d', 'yoone-subscriptions'), $analysis['payment_stats']['failed']), 'timestamp' => current_time('mysql') ); } return $anomalies; } /** * 生成报告摘要 * * @param array $analysis 分析数据 * @return string 报告摘要 */ public static function generate_summary($analysis) { $summary = array(); $summary[] = sprintf(__('总计 %d 条日志记录', 'yoone-subscriptions'), $analysis['total_logs']); if ($analysis['error_count'] > 0) { $summary[] = sprintf(__('%d 个错误', 'yoone-subscriptions'), $analysis['error_count']); } if ($analysis['warning_count'] > 0) { $summary[] = sprintf(__('%d 个警告', 'yoone-subscriptions'), $analysis['warning_count']); } if (isset($analysis['subscription_stats']['total'])) { $summary[] = sprintf(__('%d 个订阅相关事件', 'yoone-subscriptions'), $analysis['subscription_stats']['total']); } if (isset($analysis['payment_stats']['total'])) { $summary[] = sprintf(__('%d 个支付相关事件', 'yoone-subscriptions'), $analysis['payment_stats']['total']); } return implode(',', $summary); } /** * 解析日志行 * * @param string $log_line 日志行 * @return array|false 解析结果 */ private static function parse_log_line($log_line) { // 匹配WooCommerce日志格式 if (preg_match('/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2})\s+(\w+)\s+(.+)$/', $log_line, $matches)) { return array( 'timestamp' => $matches[1], 'level' => strtolower($matches[2]), 'message' => $matches[3] ); } return false; } /** * 导出分析报告 * * @param string $format 格式 (json|csv|html) * @param int $days 分析天数 * @return string 报告内容 */ public static function export_report($format = 'json', $days = 7) { $health_report = self::generate_health_report(); $trends = self::get_trend_data($days); $anomalies = self::detect_anomalies(); $report_data = array( 'generated_at' => current_time('mysql'), 'period_days' => $days, 'health' => $health_report, 'trends' => $trends, 'anomalies' => $anomalies ); switch ($format) { case 'json': return json_encode($report_data, JSON_PRETTY_PRINT); case 'csv': return self::convert_to_csv($report_data); case 'html': return self::convert_to_html($report_data); default: return json_encode($report_data); } } /** * 转换为CSV格式 * * @param array $data 数据 * @return string CSV内容 */ private static function convert_to_csv($data) { $csv = "Yoone Subscriptions Log Analysis Report\n"; $csv .= "Generated: " . $data['generated_at'] . "\n"; $csv .= "Period: " . $data['period_days'] . " days\n\n"; $csv .= "Health Score," . $data['health']['score'] . "\n"; $csv .= "Health Level," . $data['health']['text'] . "\n\n"; if (!empty($data['health']['issues'])) { $csv .= "Issues:\n"; foreach ($data['health']['issues'] as $issue) { $csv .= "," . $issue . "\n"; } $csv .= "\n"; } if (!empty($data['anomalies'])) { $csv .= "Anomalies:\n"; $csv .= "Type,Severity,Message,Timestamp\n"; foreach ($data['anomalies'] as $anomaly) { $csv .= $anomaly['type'] . "," . $anomaly['severity'] . "," . $anomaly['message'] . "," . $anomaly['timestamp'] . "\n"; } } return $csv; } /** * 转换为HTML格式 * * @param array $data 数据 * @return string HTML内容 */ private static function convert_to_html($data) { $html = 'Yoone Subscriptions Log Analysis Report'; $html .= ''; $html .= '

Yoone Subscriptions 日志分析报告

'; $html .= '

生成时间: ' . $data['generated_at'] . '

'; $html .= '

分析周期: ' . $data['period_days'] . ' 天

'; $html .= '
'; $html .= '健康评分: ' . $data['health']['score'] . '/100 (' . $data['health']['text'] . ')'; $html .= '
'; if (!empty($data['health']['issues'])) { $html .= '

发现的问题

'; } if (!empty($data['health']['recommendations'])) { $html .= '

建议

'; } if (!empty($data['anomalies'])) { $html .= '

异常检测

'; $html .= ''; foreach ($data['anomalies'] as $anomaly) { $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; $html .= ''; } $html .= '
类型严重程度描述时间
' . htmlspecialchars($anomaly['type']) . '' . htmlspecialchars($anomaly['severity']) . '' . htmlspecialchars($anomaly['message']) . '' . htmlspecialchars($anomaly['timestamp']) . '
'; } $html .= ''; return $html; } }