logInfo('Returned a million search results'); //Prints to the log file * $log->logFatal('Oh dear.'); //Prints to the log file * $log->logDebug('x = 5'); //Prints nothing due to current severity threshhold */ /** * Class documentation */ class Logger { const EMERG = 0; // Emergency: system is unusable const ALERT = 1; // Alert: action must be taken immediately const CRIT = 2; // Critical: critical conditions const ERR = 3; // Error: error conditions const WARN = 4; // Warning: warning conditions const NOTICE = 5; // Notice: normal but significant condition const INFO = 6; // Informational: informational messages const DEBUG = 7; // Debug: debug messages //custom logging level /** * Log nothing at all */ const OFF = 8; /** * Alias for CRIT * @deprecated */ const FATAL = 2; /** * Internal status codes */ const STATUS_LOG_OPEN = 1; const STATUS_OPEN_FAILED = 2; const STATUS_LOG_CLOSED = 3; /** * We need a default argument value in order to add the ability to easily * print out objects etc. But we can't use NULL, 0, FALSE, etc, because those * are often the values the developers will test for. So we'll make one up. */ const NO_ARGUMENTS = 'Logger::NO_ARGUMENTS'; /** * Current status of the log file * @var integer */ private $_logStatus = self::STATUS_LOG_CLOSED; /** * Holds messages generated by the class * @var array */ private $_messageQueue = array(); /** * Path to the log file * @var string */ private $_logFilePath = null; /** * Current minimum logging threshold * @var integer */ private $_severityThreshold = self::INFO; /** * This holds the file handle for this instance's log file * @var resource */ private $_fileHandle = null; /** * Standard messages produced by the class. Can be modified for il8n * @var array */ private $_messages = array( //'writefail' => 'The file exists, but could not be opened for writing. Check that appropriate permissions have been set.', 'writefail' => 'The file could not be written to. Check that appropriate permissions have been set.', 'opensuccess' => 'The log file was opened successfully.', 'openfail' => 'The file could not be opened. Check permissions.', ); /** * Default severity of log messages, if not specified * @var integer */ private static $_defaultSeverity = self::DEBUG; /** * Valid PHP date() format string for log timestamps * @var string */ private static $_dateFormat = 'Y-m-d G:i:s'; /** * Octal notation for default permissions of the log file * @var integer */ private static $_defaultPermissions = 0777; /** * Array of Logger instances, part of Singleton pattern * @var array */ private static $instances = array(); /** * Partially implements the Singleton pattern. Each $logDirectory gets one * instance. * * @param string $logDirectory File path to the logging directory * @param integer $severity One of the pre-defined severity constants * @return Logger */ public static function instance($logDirectory = false, $severity = false) { if ($severity === false) { $severity = self::$_defaultSeverity; } if ($logDirectory === false) { if (count(self::$instances) > 0) { return current(self::$instances); } else { $logDirectory = dirname(__FILE__); } } if (in_array($logDirectory, self::$instances)) { return self::$instances[$logDirectory]; } self::$instances[$logDirectory] = new self($logDirectory, $severity); return self::$instances[$logDirectory]; } /** * Class constructor * * @param string $logDirectory File path to the logging directory * @param integer $severity One of the pre-defined severity constants * @return void */ public function __construct($logDirectory, $severity) { $logDirectory = rtrim($logDirectory, '\\/'); if ($severity === self::OFF) { return; } $this->_logFilePath = $logDirectory . DIRECTORY_SEPARATOR . 'log_' . date('Y-m-d') . '.txt'; $this->_severityThreshold = $severity; if (!file_exists($logDirectory)) { mkdir($logDirectory, self::$_defaultPermissions, true); } if (file_exists($this->_logFilePath) && !is_writable($this->_logFilePath)) { $this->_logStatus = self::STATUS_OPEN_FAILED; $this->_messageQueue[] = $this->_messages['writefail']; return; } if (($this->_fileHandle = fopen($this->_logFilePath, 'a'))) { $this->_logStatus = self::STATUS_LOG_OPEN; $this->_messageQueue[] = $this->_messages['opensuccess']; } else { $this->_logStatus = self::STATUS_OPEN_FAILED; $this->_messageQueue[] = $this->_messages['openfail']; } } /** * Class destructor */ public function __destruct() { if ($this->_fileHandle) { fclose($this->_fileHandle); } } /** * Writes a $line to the log with a severity level of DEBUG * * @param string $line Information to log * @return void */ public function logDebug($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::DEBUG); } /** * Returns (and removes) the last message from the queue. * @return string */ public function getMessage() { return array_pop($this->_messageQueue); } /** * Returns the entire message queue (leaving it intact) * @return array */ public function getMessages() { return $this->_messageQueue; } /** * Empties the message queue * @return void */ public function clearMessages() { $this->_messageQueue = array(); } /** * Sets the date format used by all instances of Logger * * @param string $dateFormat Valid format string for date() */ public static function setDateFormat($dateFormat) { self::$_dateFormat = $dateFormat; } /** * Writes a $line to the log with a severity level of INFO. Any information * can be used here, or it could be used with E_STRICT errors * * @param string $line Information to log * @return void */ public function logInfo($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::INFO, $args); } /** * Writes a $line to the log with a severity level of NOTICE. Generally * corresponds to E_STRICT, E_NOTICE, or E_USER_NOTICE errors * * @param string $line Information to log * @return void */ public function logNotice($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::NOTICE, $args); } /** * Writes a $line to the log with a severity level of WARN. Generally * corresponds to E_WARNING, E_USER_WARNING, E_CORE_WARNING, or * E_COMPILE_WARNING * * @param string $line Information to log * @return void */ public function logWarn($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::WARN, $args); } /** * Writes a $line to the log with a severity level of ERR. Most likely used * with E_RECOVERABLE_ERROR * * @param string $line Information to log * @return void */ public function logError($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::ERR, $args); } /** * Writes a $line to the log with a severity level of FATAL. Generally * corresponds to E_ERROR, E_USER_ERROR, E_CORE_ERROR, or E_COMPILE_ERROR * * @param string $line Information to log * @return void * @deprecated Use logCrit */ public function logFatal($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::FATAL, $args); } /** * Writes a $line to the log with a severity level of ALERT. * * @param string $line Information to log * @return void */ public function logAlert($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::ALERT, $args); } /** * Writes a $line to the log with a severity level of CRIT. * * @param string $line Information to log * @return void */ public function logCrit($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::CRIT, $args); } /** * Writes a $line to the log with a severity level of EMERG. * * @param string $line Information to log * @return void */ public function logEmerg($line, $args = self::NO_ARGUMENTS) { $this->log($line, self::EMERG, $args); } /** * Writes a $line to the log with the given severity * * @param string $line Text to add to the log * @param integer $severity Severity level of log message (use constants) */ public function log($line, $severity, $args = self::NO_ARGUMENTS) { if ($this->_severityThreshold >= $severity) { $status = $this->_getTimeLine($severity); $line = "$status $line"; if ($args !== self::NO_ARGUMENTS) { /* Print the passed object value */ $line = $line . '; ' . var_export($args, true); } $this->writeFreeFormLine($line . PHP_EOL); } } /** * Writes a line to the log without prepending a status or timestamp * * @param string $line Line to write to the log * @return void */ public function writeFreeFormLine($line) { if ( $this->_logStatus == self::STATUS_LOG_OPEN && $this->_severityThreshold != self::OFF ) { if (fwrite($this->_fileHandle, $line) === false) { $this->_messageQueue[] = $this->_messages['writefail']; } } } private function _getTimeLine($level) { $time = date(self::$_dateFormat); switch ($level) { case self::EMERG: return "$time - EMERG -->"; case self::ALERT: return "$time - ALERT -->"; case self::CRIT: return "$time - CRIT -->"; case self::FATAL: # FATAL is an alias of CRIT return "$time - FATAL -->"; case self::NOTICE: return "$time - NOTICE -->"; case self::INFO: return "$time - INFO -->"; case self::WARN: return "$time - WARN -->"; case self::DEBUG: return "$time - DEBUG -->"; case self::ERR: return "$time - ERROR -->"; default: return "$time - LOG -->"; } } }