Current File : /home/kelaby89/public_html/wp/wp-content/plugins/ai-engine/classes/logging.php |
<?php
/**
* Class Meow_MWAI_Logging
*
* A logging utility that uses the WordPress Filesystem API for storage,
* with fallback to PHP error_log when necessary.
*/
class Meow_MWAI_Logging {
private static $plugin_name;
private static $option_name;
private static $log_file_path;
private static $fs;
private static $log_count = 0;
private static $rotate_check_frequency = 10;
private static $max_log_size = 5 * 1024 * 1024; // 5 MB
/**
* Initialize the logger.
*
* @param string $option_name Option key for settings.
* @param string $plugin_name Plugin identifier for error log prefix.
*/
public static function init( $option_name, $plugin_name ) {
self::$plugin_name = $plugin_name;
self::$option_name = $option_name;
if ( ! function_exists( 'request_filesystem_credentials' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
$creds = request_filesystem_credentials( site_url(), '', false, false, [] );
if ( ! WP_Filesystem( $creds ) ) {
error_log( self::$plugin_name . " : Unable to initialize WP_Filesystem." );
self::$fs = null;
}
else {
global $wp_filesystem;
self::$fs = $wp_filesystem;
}
self::$log_file_path = self::get_logs_path( true );
}
/**
* Determine or create the log file path using WP_Filesystem.
*
* @param bool $create Whether to generate a new file if none exists.
* @return string|false Path to log file or false if unavailable.
*/
private static function get_logs_path( $create = false ) {
$options = get_option( self::$option_name, null );
if ( is_null( $options ) ) {
return null;
}
if ( empty( self::$fs ) ) {
return null;
}
$path = empty( $options['logs_path'] ) ? '' : $options['logs_path'];
if ( $path && self::$fs->exists( $path ) ) {
return $path;
}
if ( ! $create ) {
return null;
}
$uploads = wp_upload_dir();
$base_dir = trailingslashit( $uploads['basedir'] );
if ( ! self::$fs->is_dir( $base_dir ) ) {
self::$fs->mkdir( $base_dir );
}
$filename = MWAI_PREFIX . '_' . self::random_ascii_chars() . '.log';
$new_path = $base_dir . $filename;
self::$fs->put_contents( $new_path, '', FS_CHMOD_FILE );
$options['logs_path'] = $new_path;
update_option( self::$option_name, $options );
return $new_path;
}
/**
* Check if logging is enabled via plugin options and FS availability.
*
* @return bool
*/
private static function is_logging_enabled() {
$options = get_option( self::$option_name, null );
if ( is_null( $options ) ) {
return false;
}
$module_devtools = empty( $options['module_devtools'] ) ? false : $options['module_devtools'];
$server_debug_mode = empty( $options['server_debug_mode'] ) ? false : $options['server_debug_mode'];
return ( $module_devtools && $server_debug_mode && ! empty( self::$fs ) );
}
/**
* Internal log writer. Appends to file and/or error_log.
*/
private static function add( $message = null, $icon = '', $error_log = false ) {
$date = date( 'Y-m-d H:i:s' );
$message = is_string( $message ) ? strip_tags( $message ) : $message;
if ( empty( $message ) ) {
$entry = "\n";
}
else if ( ! empty( $icon ) ) {
$entry = "$date: $icon $message\n";
}
else {
$entry = "$date: $message\n";
}
if ( self::is_logging_enabled() && self::$log_file_path ) {
if ( self::$fs->exists( self::$log_file_path ) ) {
$current = self::$fs->get_contents( self::$log_file_path );
self::$fs->put_contents( self::$log_file_path, $current . $entry, FS_CHMOD_FILE );
}
else {
self::$fs->put_contents( self::$log_file_path, $entry, FS_CHMOD_FILE );
}
}
if ( $error_log && ! empty( $message ) ) {
error_log( self::$plugin_name . " : $message" );
}
self::$log_count++;
if ( self::$log_count >= self::$rotate_check_frequency ) {
self::maybe_rotate_log();
self::$log_count = 0;
}
}
/**
* Logs a general message.
*
* @param string $message The message to log.
* @param string $icon Optional icon to prepend.
*/
public static function log( $message = null, $icon = '' ) {
self::add( $message, $icon );
}
/**
* Logs a warning message.
*
* @param string $message The warning message to log.
* @param string $icon Optional icon to prepend (default ⚠️).
*/
public static function warn( $message = null, $icon = '⚠️' ) {
self::add( $message, $icon );
}
/**
* Logs an error message and sends to PHP error_log.
*
* @param string $message The error message to log.
* @param string $icon Optional icon to prepend (default ❌).
*/
public static function error( $message = null, $icon = '❌' ) {
self::add( $message, $icon, true );
}
/**
* Logs a deprecated feature notice.
*
* @param string $message The message to log.
*/
public static function deprecated( $message = null ) {
self::add( $message, '🚨', true );
}
/**
* Clears the log file and resets the option.
*/
public static function clear() {
if ( self::$fs && self::$log_file_path && self::$fs->exists( self::$log_file_path ) ) {
self::$fs->delete( self::$log_file_path );
$options = get_option( self::$option_name, null );
$options['logs_path'] = '';
update_option( self::$option_name, $options );
self::$log_file_path = '';
}
}
/**
* Retrieves the log contents in reverse order (newest first).
*
* @return string
*/
public static function get() {
if ( self::$fs && self::$log_file_path && self::$fs->exists( self::$log_file_path ) ) {
$content = self::$fs->get_contents( self::$log_file_path );
$lines = explode( "\n", $content );
$lines = array_filter( $lines );
$lines = array_reverse( $lines );
return implode( "\n", $lines );
}
return 'Empty log file.';
}
/**
* Checks file size and rotates if exceeding maximum.
*/
private static function maybe_rotate_log() {
if ( empty( self::$fs ) || empty( self::$log_file_path ) ) {
return;
}
if ( self::$fs->exists( self::$log_file_path ) ) {
$size = self::$fs->size( self::$log_file_path );
if ( $size > self::$max_log_size ) {
$info = pathinfo( self::$log_file_path );
$archived = $info['dirname'] . '/' . $info['filename'] . '_' . date( 'Y-m-d_H-i-s' ) . '.' . $info['extension'];
self::$fs->move( self::$log_file_path, $archived, true );
self::$fs->put_contents( self::$log_file_path, '', FS_CHMOD_FILE );
}
}
}
/**
* Generates a random ASCII string.
*
* @param int $length String length.
* @return string
*/
private static function random_ascii_chars( $length = 8 ) {
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$result = '';
for ( $i = 0; $i < $length; $i++ ) {
$result .= $characters[ rand( 0, strlen( $characters ) - 1 ) ];
}
return $result;
}
}