prefix . self::TABLE; } /** * Writes a log entry. Never throws. * * @param string $level Level. * @param string $channel Channel. * @param string $message Message. * @param array $context Context. */ public function log( string $level, string $channel, string $message, array $context = array() ): void { global $wpdb; try { $message = Redactor::mask_bearer( $message ); $json = $context ? wp_json_encode( Redactor::redact( $context ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) : null; if ( is_string( $json ) && strlen( $json ) > self::MAX_LENGTH ) { $json = substr( $json, 0, self::MAX_LENGTH ) . '…'; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- own log table. $wpdb->insert( self::table(), array( 'created_at' => gmdate( 'Y-m-d H:i:s' ), 'level' => substr( $level, 0, 10 ), 'channel' => substr( $channel, 0, 30 ), 'message' => $message, 'context' => $json, ), array( '%s', '%s', '%s', '%s', '%s' ) ); if ( in_array( $level, array( self::WARNING, self::ERROR ), true ) && function_exists( 'wc_get_logger' ) ) { wc_get_logger()->log( $level, '[' . $channel . '] ' . $message, array( 'source' => self::WC_SOURCE ) ); } } catch ( \Throwable $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch -- logging must never break a request. } } /** * Deletes entries older than the given number of days. * * @param int $days Age in days. * @return int Rows deleted. */ public static function prune( int $days ): int { global $wpdb; $table = self::table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- own table. return (int) $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE created_at < %s', $table, gmdate( 'Y-m-d H:i:s', time() - $days * DAY_IN_SECONDS ) ) ); } }