feat: add structured plugin logging system with admin log viewer

Introduces Peptide_News_Logger class with leveled logging (info, warning,
error, debug) to a custom DB table, auto-pruning at 2000 rows. Adds a
filterable, paginated log viewer to the admin settings page. Instruments
the LLM and Fetcher classes with structured log calls for fetch cycles,
AI processing, and error tracking. Version bumped to 2.1.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Terence Ong
2026-04-07 15:58:51 +07:00
parent e1d18ba86e
commit 6c57f6ca11
14 changed files with 1476 additions and 39 deletions

View File

@@ -75,14 +75,15 @@ class Peptide_News_LLM {
if ( ! is_wp_error( $keywords_result ) ) {
$results['keywords'] = self::sanitize_keywords( $keywords_result );
$any_success = true;
Peptide_News_Logger::debug( 'Keywords extracted for article #' . $article->id, 'llm' );
} else {
$err_msg = 'Keywords (' . $keywords_model . '): ' . $keywords_result->get_error_message();
$results['errors'][] = $err_msg;
self::log_error( 'Keyword extraction failed for article ' . $article->id . ': ' . $keywords_result->get_error_message() );
Peptide_News_Logger::error( 'Keyword extraction failed for article #' . $article->id . ': ' . $keywords_result->get_error_message(), 'llm' );
}
} elseif ( $need_keywords ) {
$results['errors'][] = 'Invalid keywords model ID: ' . $keywords_model;
self::log_error( 'Invalid keywords model ID: ' . $keywords_model );
Peptide_News_Logger::error( 'Invalid keywords model ID: ' . $keywords_model, 'llm' );
}
// --- Summarization ---
@@ -97,14 +98,15 @@ class Peptide_News_LLM {
// Strip all HTML tags from LLM output to prevent XSS.
$results['summary'] = sanitize_textarea_field( wp_strip_all_tags( $summary_result ) );
$any_success = true;
Peptide_News_Logger::info( 'AI summary generated for article #' . $article->id . ': ' . mb_substr( $article->title, 0, 60 ), 'llm' );
} else {
$err_msg = 'Summary (' . $summary_model . '): ' . $summary_result->get_error_message();
$results['errors'][] = $err_msg;
self::log_error( 'Summarization failed for article ' . $article->id . ': ' . $summary_result->get_error_message() );
Peptide_News_Logger::error( 'Summarization failed for article #' . $article->id . ': ' . $summary_result->get_error_message(), 'llm' );
}
} elseif ( $need_summary ) {
$results['errors'][] = 'Invalid summary model ID: ' . $summary_model;
self::log_error( 'Invalid summary model ID: ' . $summary_model );
Peptide_News_Logger::error( 'Invalid summary model ID: ' . $summary_model, 'llm' );
}
$results['success'] = $any_success;
@@ -198,6 +200,12 @@ class Peptide_News_LLM {
'errors' => $last_errors,
) );
if ( $processed > 0 ) {
Peptide_News_Logger::info( sprintf( 'AI batch complete: %d/%d articles processed.', $processed, count( $articles ) ), 'llm' );
} elseif ( count( $articles ) > 0 ) {
Peptide_News_Logger::warning( sprintf( 'AI batch: 0/%d articles succeeded.', count( $articles ) ), 'llm' );
}
return $processed;
}
@@ -407,6 +415,8 @@ class Peptide_News_LLM {
wp_send_json_error( 'AI Analysis is not enabled. Please enable it and set an OpenRouter API key in Peptide News → Settings.' );
}
Peptide_News_Logger::info( 'Bulk AI summary generation triggered by admin.', 'llm' );
// Auto-correct known broken model names to a working free model.
$broken_models = array(
'qwen/qwen3.6-plus:free',