settings = $settings; } /** * Record a failure. * * @param string $message Summary. * @param array $context Structured detail. * @return void */ public function error( string $message, array $context = array() ): void { $entries = $this->entries(); array_unshift( $entries, array( 'time' => time(), 'message' => $message, 'context' => $this->flatten( $context ), ) ); update_option( self::OPTION, array_slice( $entries, 0, self::MAX_ENTRIES ), false ); $this->to_debug_log( 'error', $message, $context ); } /** * Record developer detail. * * Never stored in the database — this fires on every successful delivery, and writing an option * row per event would make measurement the most expensive thing the site does. * * @param string $message Summary. * @param array $context Structured detail. * @return void */ public function debug( string $message, array $context = array() ): void { if ( ! $this->settings->load()->flag( 'debug' ) ) { return; } $this->to_debug_log( 'debug', $message, $context ); } /** * Recent failures, newest first. * * @return array> */ public function entries(): array { $stored = get_option( self::OPTION, array() ); if ( ! is_array( $stored ) ) { return array(); } return array_values( array_filter( $stored, 'is_array' ) ); } /** * Empty the log. * * @return void */ public function clear(): void { delete_option( self::OPTION ); } /** * Reduce a context array to short scalar strings. * * @param array $context Structured detail. * @return array */ private function flatten( array $context ): array { $flat = array(); foreach ( $context as $key => $value ) { if ( ! is_scalar( $value ) ) { continue; } $flat[ sanitize_key( (string) $key ) ] = substr( sanitize_text_field( (string) $value ), 0, 200 ); } return $flat; } /** * Mirror an entry into the PHP error log when the site is set up to collect one. * * @param string $level Level label. * @param string $message Summary. * @param array $context Structured detail. * @return void */ private function to_debug_log( string $level, string $message, array $context ): void { if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG || ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) { return; } $line = '[AdPix Analytics] ' . strtoupper( $level ) . ': ' . $message; if ( array() !== $context ) { $encoded = wp_json_encode( $this->flatten( $context ) ); $line .= ' ' . ( is_string( $encoded ) ? $encoded : '' ); } // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Guarded by WP_DEBUG_LOG; this is the log the site asked for. error_log( $line ); } }