base.php (5283B)
1 <?php 2 namespace Elementor\Core\Logger\Items; 3 4 if ( ! defined( 'ABSPATH' ) ) { 5 exit; // Exit if accessed directly 6 } 7 8 class Base implements Log_Item_Interface { 9 10 const FORMAT = 'date [type] message [meta]'; 11 const TRACE_FORMAT = '#key: file(line): class type function()'; 12 const TRACE_LIMIT = 5; 13 14 protected $date; 15 protected $type; 16 protected $message; 17 protected $meta = []; 18 19 protected $times = 0; 20 protected $times_dates = []; 21 protected $args = []; 22 23 public function __construct( $args ) { 24 $this->date = current_time( 'mysql' ); 25 $this->message = ! empty( $args['message'] ) ? esc_html( $args['message'] ) : ''; 26 $this->type = ! empty( $args['type'] ) ? $args['type'] : 'info'; 27 $this->meta = ! empty( $args['meta'] ) ? $args['meta'] : []; 28 $this->args = $args; 29 30 $this->set_trace(); 31 } 32 33 public function __get( $name ) { 34 if ( property_exists( $this, $name ) ) { 35 return $this->{$name}; 36 } 37 38 return ''; 39 } 40 41 public function __toString() { 42 $vars = get_object_vars( $this ); 43 return strtr( static::FORMAT, $vars ); 44 } 45 46 public function jsonSerialize() { 47 return [ 48 'class' => get_class( $this ), 49 'item' => [ 50 'date' => $this->date, 51 'message' => $this->message, 52 'type' => $this->type, 53 'meta' => $this->meta, 54 'times' => $this->times, 55 'times_dates' => $this->times_dates, 56 'args' => $this->args, 57 ], 58 ]; 59 } 60 61 public function deserialize( $properties ) { 62 $this->date = ! empty( $properties['date'] ) && is_string( $properties['date'] ) ? $properties['date'] : ''; 63 $this->message = ! empty( $properties['message'] ) && is_string( $properties['message'] ) ? $properties['message'] : ''; 64 $this->type = ! empty( $properties['type'] ) && is_string( $properties['type'] ) ? $properties['type'] : ''; 65 $this->meta = ! empty( $properties['meta'] ) && is_array( $properties['meta'] ) ? $properties['meta'] : []; 66 $this->times = ! empty( $properties['times'] ) && is_string( $properties['times'] ) ? $properties['times'] : ''; 67 $this->times_dates = ! empty( $properties['times_dates'] ) && is_array( $properties['times_dates'] ) ? $properties['times_dates'] : []; 68 $this->args = ! empty( $properties['args'] ) && is_array( $properties['args'] ) ? $properties['args'] : []; 69 } 70 71 /** 72 * @return Log_Item_Interface | null 73 */ 74 public static function from_json( $str ) { 75 $obj = json_decode( $str, true ); 76 if ( ! array_key_exists( 'class', $obj ) ) { 77 return null; 78 } 79 $class = $obj['class']; 80 if ( class_exists( $class ) ) { 81 /** @var Base $item */ 82 $item = new $class( $obj['item']['message'] ); 83 $item->deserialize( $obj['item'] ); 84 return $item; 85 } 86 87 return null; 88 } 89 90 public function to_formatted_string( $output_format = 'html' ) { 91 $vars = get_object_vars( $this ); 92 $format = static::FORMAT; 93 if ( 'html' === $output_format ) { 94 $format = str_replace( 'message', '<strong>message</strong>', static::FORMAT ); 95 } 96 if ( empty( $vars['meta'] ) ) { 97 $format = str_replace( '[meta]', '', $format ); 98 } else { 99 $vars['meta'] = stripslashes( var_export( $vars['meta'], true ) ); // @codingStandardsIgnoreLine 100 } 101 return strtr( $format, $vars ); 102 } 103 104 public function get_fingerprint() { 105 $unique_key = $this->type . $this->message . var_export( $this->meta, true ); // @codingStandardsIgnoreLine 106 //info messages are not be aggregated: 107 if ( 'info' === $this->type ) { 108 $unique_key .= $this->date; 109 } 110 return md5( $unique_key ); 111 } 112 113 public function increase_times( $item, $truncate = true ) { 114 $this->times++; 115 $this->times_dates[] = $item->date; 116 117 if ( $truncate && ( self::MAX_LOG_ENTRIES < count( $this->times_dates ) ) ) { 118 $this->times_dates = array_slice( $this->times_dates, -self::MAX_LOG_ENTRIES ); 119 } 120 } 121 122 public function format( $format = 'html' ) { 123 $trace = $this->format_trace(); 124 if ( empty( $trace ) ) { 125 return $this->to_formatted_string( $format ); 126 } 127 $copy = clone $this; 128 $copy->meta['trace'] = $trace; 129 return $copy->to_formatted_string( $format ); 130 } 131 132 public function get_name() { 133 return 'Log'; 134 } 135 136 private function format_trace() { 137 $trace = empty( $this->meta['trace'] ) ? '' : $this->meta['trace']; 138 139 if ( is_string( $trace ) ) { 140 return $trace; 141 } 142 143 $trace_str = ''; 144 foreach ( $trace as $key => $trace_line ) { 145 $format = static::TRACE_FORMAT; 146 $trace_line['key'] = $key; 147 if ( empty( $trace_line['file'] ) ) { 148 $format = str_replace( 'file(line): ', '', $format ); 149 } 150 151 $trace_str .= PHP_EOL . strtr( $format, $trace_line ); 152 $trace_str .= empty( $trace_line['args'] ) ? '' : var_export( $trace_line['args'], true ); // @codingStandardsIgnoreLine 153 } 154 155 return $trace_str . PHP_EOL; 156 } 157 158 private function set_trace() { 159 if ( ! empty( $this->args['trace'] ) && true === $this->args['trace'] ) { 160 $limit = empty( $this->args['trace_limit'] ) ? static::TRACE_LIMIT : $this->args['trace_limit']; 161 162 $stack = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // @codingStandardsIgnoreLine 163 164 while ( ! empty( $stack ) && ! empty( $stack[0]['file'] ) && ( false !== strpos( $stack[0]['file'], 'core' . DIRECTORY_SEPARATOR . 'logger' ) ) ) { 165 array_shift( $stack ); 166 } 167 168 $this->meta['trace'] = array_slice( $stack, 0, $limit ); 169 170 return; 171 } 172 173 if ( is_array( $this->args ) ) { 174 unset( $this->args['trace'] ); 175 } 176 } 177 }