PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.4
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.4
1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.2.0 All 28 releases
xspeed / includes / class-activity-log.php

class-activity-log.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.0.4, at includes/class-activity-log.php

89 lines 2.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Activity_Log — capped, append-only log of cache lifecycle events.
4 *
5 * Used by the Health module's dashboard panel + (later phases) by audit
6 * surfaces. Storage: one transient `xspeed_activity_log` containing at
7 * most MAX_ENTRIES events, ordered newest-first. Transient TTL is long
8 * (30 days) so we don't lose history during quiet periods, but the size
9 * cap keeps it bounded.
10 *
11 * Event shape:
12 * [ ts => int, type => string, message => string, severity => 'info' |
13 * 'warn' | 'error' | 'success' ]
14 *
15 * Callers (from Cache.php and elsewhere):
16 * Activity_Log::record('cache_purged', 'Cache purged (settings change)');
17 * Activity_Log::record('cache_enabled_event', 'Cache enabled', 'success');
18 * Activity_Log::record('conflict_detected', 'WP Rocket activated', 'warn');
19 *
20 * Event type ids are snake_case — sanitize_key (called on the way in)
21 * strips dots, so dotted ids would collapse silently.
22 *
23 * @package XSpeed
24 */
25
26 declare(strict_types=1);
27
28 namespace XSpeed;
29
30 defined( 'ABSPATH' ) || exit;
31
32 final class Activity_Log {
33
34 public const TRANSIENT_KEY = 'xspeed_activity_log';
35 public const TTL = 2592000; // 30 days
36 public const MAX_ENTRIES = 50;
37
38 public const INFO = 'info';
39 public const WARN = 'warn';
40 public const ERROR = 'error';
41 public const SUCCESS = 'success';
42
43 public static function record( string $type, string $message, string $severity = self::INFO ): void {
44 $entries = self::entries();
45 array_unshift(
46 $entries,
47 array(
48 'ts' => time(),
49 'type' => sanitize_key( $type ),
50 'message' => $message, // caller must produce already-safe text.
51 'severity' => in_array( $severity, array( self::INFO, self::WARN, self::ERROR, self::SUCCESS ), true ) ? $severity : self::INFO,
52 )
53 );
54 if ( count( $entries ) > self::MAX_ENTRIES ) {
55 $entries = array_slice( $entries, 0, self::MAX_ENTRIES );
56 }
57 set_transient( self::TRANSIENT_KEY, $entries, self::TTL );
58 }
59
60 /**
61 * Newest-first entries (up to MAX_ENTRIES). Defensive shape coercion
62 * so a malformed transient never breaks the dashboard.
63 *
64 * @return array<int,array{ts:int,type:string,message:string,severity:string}>
65 */
66 public static function entries(): array {
67 $raw = get_transient( self::TRANSIENT_KEY );
68 if ( ! is_array( $raw ) ) {
69 return array();
70 }
71 $out = array();
72 foreach ( $raw as $e ) {
73 if ( is_array( $e ) && isset( $e['ts'], $e['type'], $e['message'] ) ) {
74 $out[] = array(
75 'ts' => (int) $e['ts'],
76 'type' => (string) $e['type'],
77 'message' => (string) $e['message'],
78 'severity' => isset( $e['severity'] ) ? (string) $e['severity'] : self::INFO,
79 );
80 }
81 }
82 return $out;
83 }
84
85 public static function clear(): void {
86 delete_transient( self::TRANSIENT_KEY );
87 }
88 }
89