Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

jsarnowski / jsarnowski/stackable-premium   php

Repository URL to install this package:

/ includes / class-fs-logger.php

<?php
	/**
	 * @package     Freemius
	 * @copyright   Copyright (c) 2015, Freemius, Inc.
	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
	 * @since       1.0.3
	 */

	if ( ! defined( 'ABSPATH' ) ) {
		exit;
	}

	class FS_Logger {
		private $_id;
		private $_on = false;
		private $_echo = false;
		private $_file_start = 0;
		/**
		 * @var int PHP Process ID.
		 */
		private static $_processID;
		/**
		 * @var string PHP Script user name.
		 */
		private static $_ownerName;
		/**
		 * @var bool Is storage logging turned on.
		 */
		private static $_isStorageLoggingOn;
		/**
		 * @var int ABSPATH length.
		 */
		private static $_abspathLength;

		private static $LOGGERS = array();
		private static $LOG = array();
		private static $CNT = 0;
		private static $_HOOKED_FOOTER = false;

		private function __construct( $id, $on = false, $echo = false ) {
			$this->_id = $id;

			$bt     = debug_backtrace();
			$caller = $bt[2];

			if ( false !== strpos( $caller['file'], 'plugins' ) ) {
				$this->_file_start = strpos( $caller['file'], 'plugins' ) + strlen( 'plugins/' );
			} else {
				$this->_file_start = strpos( $caller['file'], 'themes' ) + strlen( 'themes/' );
			}

			if ( $on ) {
				$this->on();
			}
			if ( $echo ) {
				$this->echo_on();
			}
		}

		/**
		 * @param string $id
		 * @param bool   $on
		 * @param bool   $echo
		 *
		 * @return FS_Logger
		 */
		public static function get_logger( $id, $on = false, $echo = false ) {
			$id = strtolower( $id );

			if ( ! isset( self::$_processID ) ) {
				self::init();
			}

			if ( ! isset( self::$LOGGERS[ $id ] ) ) {
				self::$LOGGERS[ $id ] = new FS_Logger( $id, $on, $echo );
			}

			return self::$LOGGERS[ $id ];
		}

		/**
		 * Initialize logging global info.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.2.1.6
		 */
		private static function init() {
			self::$_ownerName          = function_exists( 'get_current_user' ) ?
				get_current_user() :
				'unknown';
			self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) );
			self::$_abspathLength      = strlen( ABSPATH );
			self::$_processID          = mt_rand( 0, 32000 );

			// Process ID may be `false` on errors.
			if ( ! is_numeric( self::$_processID ) ) {
				self::$_processID = 0;
			}
		}

		private static function hook_footer() {
			if ( self::$_HOOKED_FOOTER ) {
				return;
			}

			if ( is_admin() ) {
				add_action( 'admin_footer', 'FS_Logger::dump', 100 );
			} else {
				add_action( 'wp_footer', 'FS_Logger::dump', 100 );
			}
		}

		function is_on() {
			return $this->_on;
		}

		function on() {
			$this->_on = true;

			if ( ! function_exists( 'dbDelta' ) ) {
				require_once ABSPATH . 'wp-admin/includes/upgrade.php';
			}

			self::hook_footer();
		}

		function echo_on() {
			$this->on();

			$this->_echo = true;
		}

		function is_echo_on() {
			return $this->_echo;
		}

		function get_id() {
			return $this->_id;
		}

		function get_file() {
			return $this->_file_start;
		}

		private function _log( &$message, $type, $wrapper = false ) {
			if ( ! $this->is_on() ) {
				return;
			}

			$bt    = debug_backtrace();
			$depth = $wrapper ? 3 : 2;
			while ( $depth < count( $bt ) - 1 && 'eval' === $bt[ $depth ]['function'] ) {
				$depth ++;
			}

			$caller = $bt[ $depth ];

			/**
			 * Retrieve the correct call file & line number from backtrace
			 * when logging from a wrapper method.
			 *
			 * @author Vova Feldman
			 * @since  1.2.1.6
			 */
			if ( empty( $caller['line'] ) ) {
				$depth --;

				while ( $depth >= 0 ) {
					if ( ! empty( $bt[ $depth ]['line'] ) ) {
						$caller['line'] = $bt[ $depth ]['line'];
						$caller['file'] = $bt[ $depth ]['file'];
						break;
					}
				}
			}

			$log = array_merge( $caller, array(
				'cnt'       => self::$CNT ++,
				'logger'    => $this,
				'timestamp' => microtime( true ),
				'log_type'  => $type,
				'msg'       => $message,
			) );

			if ( self::$_isStorageLoggingOn ) {
				$this->db_log( $type, $message, self::$CNT, $caller );
			}

			self::$LOG[] = $log;

			if ( $this->is_echo_on() && ! Freemius::is_ajax() ) {
				echo self::format_html( $log ) . "\n";
			}
		}

		function log( $message, $wrapper = false ) {
			$this->_log( $message, 'log', $wrapper );
		}

		function info( $message, $wrapper = false ) {
			$this->_log( $message, 'info', $wrapper );
		}

		function warn( $message, $wrapper = false ) {
			$this->_log( $message, 'warn', $wrapper );
		}

		function error( $message, $wrapper = false ) {
			$this->_log( $message, 'error', $wrapper );
		}

		/**
		 * Log API error.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.2.1.5
		 *
		 * @param mixed $api_result
		 * @param bool  $wrapper
		 */
		function api_error( $api_result, $wrapper = false ) {
			$message = '';
			if ( is_object( $api_result ) &&
			     ! empty( $api_result->error ) &&
			     ! empty( $api_result->error->message )
			) {
				$message = $api_result->error->message;
			} else if ( is_object( $api_result ) ) {
				$message = var_export( $api_result, true );
			} else if ( is_string( $api_result ) ) {
				$message = $api_result;
			} else if ( empty( $api_result ) ) {
				$message = 'Empty API result.';
			}

			$message = 'API Error: ' . $message;

			$this->_log( $message, 'error', $wrapper );
		}

		function entrance( $message = '', $wrapper = false ) {
			$msg = 'Entrance' . ( empty( $message ) ? '' : ' > ' ) . $message;

			$this->_log( $msg, 'log', $wrapper );
		}

		function departure( $message = '', $wrapper = false ) {
			$msg = 'Departure' . ( empty( $message ) ? '' : ' > ' ) . $message;

			$this->_log( $msg, 'log', $wrapper );
		}

		#--------------------------------------------------------------------------------
		#region Log Formatting
		#--------------------------------------------------------------------------------

		private static function format( $log, $show_type = true ) {
			return '[' . str_pad( $log['cnt'], strlen( self::$CNT ), '0', STR_PAD_LEFT ) . '] [' . $log['logger']->_id . '] ' . ( $show_type ? '[' . $log['log_type'] . ']' : '' ) . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . ' >> ' . $log['msg'] . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ') ' : '' ) . ' [' . $log['timestamp'] . ']';
		}

		private static function format_html( $log ) {
			return '<div style="font-size: 13px; font-family: monospace; color: #7da767; padding: 8px 3px; background: #000; border-bottom: 1px solid #555;">[' . $log['cnt'] . '] [' . $log['logger']->_id . '] [' . $log['log_type'] . '] <b><code style="color: #c4b1e0;">' . ( ! empty( $log['class'] ) ? $log['class'] . $log['type'] : '' ) . $log['function'] . '</code> >> <b style="color: #f59330;">' . esc_html( $log['msg'] ) . '</b></b>' . ( isset( $log['file'] ) ? ' (' . substr( $log['file'], $log['logger']->_file_start ) . ' ' . $log['line'] . ')' : '' ) . ' [' . $log['timestamp'] . ']</div>';
		}

		#endregion

		static function dump() {
			?>
			<!-- BEGIN: Freemius PHP Console Log -->
			<script type="text/javascript">
				<?php
				foreach ( self::$LOG as $log ) {
					echo 'console.' . $log['log_type'] . '(' . json_encode( self::format( $log, false ) ) . ')' . "\n";
				}
				?>
			</script>
			<!-- END: Freemius PHP Console Log -->
			<?php
		}

		static function get_log() {
			return self::$LOG;
		}

		#--------------------------------------------------------------------------------
		#region Database Logging
		#--------------------------------------------------------------------------------

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.2.1.6
		 *
		 * @return bool
		 */
		public static function is_storage_logging_on() {
			if ( ! isset( self::$_isStorageLoggingOn ) ) {
				self::$_isStorageLoggingOn = ( 1 == get_option( 'fs_storage_logger', 0 ) );
			}

			return self::$_isStorageLoggingOn;
		}

		/**
		 * Turns on/off database persistent debugging to capture
		 * multi-session logs to debug complex flows like
		 * plugin auto-deactivate on premium version activation.
		 *
		 * @todo   Check if Theme Check has issues with DB tables for themes.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.2.1.6
		 *
		 * @param bool $is_on
		 *
		 * @return bool
		 */
		public static function _set_storage_logging( $is_on = true ) {
			global $wpdb;

			$table = "{$wpdb->prefix}fs_logger";

			if ( $is_on ) {
				/**
				 * Create logging table.
				 *
				 * NOTE:
				 *  dbDelta must use KEY and not INDEX for indexes.
				 *
				 * @link https://core.trac.wordpress.org/ticket/2695
				 */
				$result = $wpdb->query( "CREATE TABLE {$table} (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`process_id` INT UNSIGNED NOT NULL,
`user_name` VARCHAR(64) NOT NULL,
`logger` VARCHAR(128) NOT NULL,
`log_order` INT UNSIGNED NOT NULL,
`type` ENUM('log','info','warn','error') NOT NULL DEFAULT 'log',
`message` TEXT NOT NULL,
`file` VARCHAR(256) NOT NULL,
`line` INT UNSIGNED NOT NULL,
`function` VARCHAR(256) NOT NULL,
`request_type` ENUM('call','ajax','cron') NOT NULL DEFAULT 'call',
`request_url` VARCHAR(1024) NOT NULL,
`created` DECIMAL(16, 6) NOT NULL,
PRIMARY KEY (`id`),
Loading ...