/** * @package Joomla.Platform * @subpackage Log * * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; jimport('joomla.log.logger'); JLoader::register('LogException', JPATH_PLATFORM . '/joomla/log/logexception.php'); JLoader::discover('JLogger', dirname(__FILE__) . '/loggers'); // @deprecated 12.1 jimport('joomla.filesystem.path'); /** * Joomla! Log Class * * This class hooks into the global log configuration settings to allow for user configured * logging events to be sent to where the user wishes them to be sent. On high load sites * SysLog is probably the best (pure PHP function), then the text file based loggers (CSV, W3C * or plain FormattedText) and finally MySQL offers the most features (e.g. rapid searching) * but will incur a performance hit due to INSERT being issued. * * @package Joomla.Platform * @subpackage Log * @since 11.1 */ class JLog { /** * All log priorities. * @var integer * @since 11.1 */ const ALL = 30719; /** * The system is unusable. * @var integer * @since 11.1 */ const EMERGENCY = 1; /** * Action must be taken immediately. * @var integer * @since 11.1 */ const ALERT = 2; /** * Critical conditions. * @var integer * @since 11.1 */ const CRITICAL = 4; /** * Error conditions. * @var integer * @since 11.1 */ const ERROR = 8; /** * Warning conditions. * @var integer * @since 11.1 */ const WARNING = 16; /** * Normal, but significant condition. * @var integer * @since 11.1 */ const NOTICE = 32; /** * Informational message. * @var integer * @since 11.1 */ const INFO = 64; /** * Debugging message. * @var integer * @since 11.1 */ const DEBUG = 128; /** * The global JLog instance. * @var JLog * @since 11.1 */ protected static $instance; /** * The array of instances created through the deprecated getInstance method. * @var array * @since 11.1 * @see JLog::getInstance() * @deprecated 12.1 */ public static $legacy = array(); /** * Container for JLogger configurations. * @var array * @since 11.1 */ protected $configurations = array(); /** * Container for JLogger objects. * @var array * @since 11.1 */ protected $loggers = array(); /** * Lookup array for loggers. * @var array * @since 11.1 */ protected $lookup = array(); /** * Constructor. * * @since 11.1 */ protected function __construct() { } /** * Method to add an entry to the log. * * @param mixed $entry The JLogEntry object to add to the log or the message for a new JLogEntry object. * @param integer $priority Message priority. * @param string $category Type of entry * @param string $date Date of entry (defaults to now if not specified or blank) * * @return void * * @since 11.1 */ public static function add($entry, $priority = JLog::INFO, $category = '', $date = null) { // Automatically instantiate the singleton object if not already done. if (empty(self::$instance)) { self::setInstance(new JLog); } // If the entry object isn't a JLogEntry object let's make one. if (!($entry instanceof JLogEntry)) { $entry = new JLogEntry((string) $entry, $priority, $category, $date); } self::$instance->addLogEntry($entry); } /** * Method to set the way the JError will handle different error levels. * Use this if you want to override the default settings. * * @param array $options The object configuration array. * @param integer $priorities Message priority * @param array $categories Types of entry * * @return void * * @since 11.1 */ public static function addLogger(array $options, $priorities = JLog::ALL, $categories = array()) { // Automatically instantiate the singleton object if not already done. if (empty(self::$instance)) { self::setInstance(new JLog); } // The default logger is the formatted text log file. if (empty($options['logger'])) { $options['logger'] = 'formattedtext'; } $options['logger'] = strtolower($options['logger']); // Generate a unique signature for the JLog instance based on its options. $signature = md5(serialize($options)); // Register the configuration if it doesn't exist. if (empty(self::$instance->configurations[$signature])) { self::$instance->configurations[$signature] = $options; } self::$instance->lookup[$signature] = (object) array( 'priorities' => $priorities, 'categories' => array_map('strtolower', (array) $categories)); } /** * Returns a JLog object for a given log file/configuration, only creating it if it doesn't already exist. * * This method must be invoked as: * $log = JLog::getInstance($file, $options, $path); * * @param string $file The filename of the log file. * @param array $options The object configuration array. * @param string $path The base path for the log file. * * @return JLog * * @since 11.1 * * @deprecated 12.1 */ public static function getInstance($file = 'error.php', $options = null, $path = null) { // Deprecation warning. JLog::add('JLog::getInstance() is deprecated. See JLog::addLogger().', JLog::WARNING, 'deprecated'); // Get the system configuration object. $config = JFactory::getConfig(); // Set default path if not set and sanitize it. if (!$path) { $path = $config->get('log_path'); } // If no options were explicitly set use the default from configuration. if (empty($options)) { $options = (array) $config->get('log_options'); } // Fix up the options so that we use the w3c format. $options['text_entry_format'] = empty($options['format']) ? null : $options['format']; $options['text_file'] = $file; $options['text_file_path'] = $path; $options['logger'] = 'w3c'; // Generate a unique signature for the JLog instance based on its options. $signature = md5(serialize($options)); // Only create the object if not already created. if (empty(self::$legacy[$signature])) { self::$legacy[$signature] = new JLog; // Register the configuration. self::$legacy[$signature]->configurations[$signature] = $options; // Setup the lookup to catch all. self::$legacy[$signature]->lookup[$signature] = (object) array('priorities' => JLog::ALL, 'categories' => array()); } return self::$legacy[$signature]; } /** * Returns a reference to the a JLog object, only creating it if it doesn't already exist. * Note: This is principally made available for testing and internal purposes. * * @param JLog $instance The logging object instance to be used by the static methods. * * @return void * * @since 11.1 */ public static function setInstance($instance) { if (($instance instanceof JLog) || $instance === null) { self::$instance = & $instance; } } /** * Method to add an entry to the log file. * * @param array $entry Array of values to map to the format string for the log file. * * @return boolean True on success. * * @since 11.1 * * @deprecated 12.1 Use JLog::add() instead. */ public function addEntry($entry) { // Deprecation warning. JLog::add('JLog::addEntry() is deprecated, use JLog::add() instead.', JLog::WARNING, 'deprecated'); // Easiest case is we already have a JLogEntry object to add. if ($entry instanceof JLogEntry) { return $this->addLogEntry($entry); } // We have either an object or array that needs to be converted to a JLogEntry. elseif (is_array($entry) || is_object($entry)) { $tmp = new JLogEntry(''); foreach ((array) $entry as $k => $v) { switch ($k) { case 'c-ip': $tmp->clientIP = $v; break; case 'status': $tmp->category = $v; break; case 'level': $tmp->priority = $v; break; case 'comment': $tmp->message = $v; break; default: $tmp->$k = $v; break; } } } // Unrecognized type. else { return false; } return $this->addLogEntry($tmp); } /** * Method to add an entry to the appropriate loggers. * * @param JLogEntry $entry The JLogEntry object to send to the loggers. * * @return void * * @since 11.1 * @throws LogException */ protected function addLogEntry(JLogEntry $entry) { // Find all the appropriate loggers based on priority and category for the entry. $loggers = $this->findLoggers($entry->priority, $entry->category); foreach ((array) $loggers as $signature) { // Attempt to instantiate the logger object if it doesn't already exist. if (empty($this->loggers[$signature])) { $class = 'JLogger' . ucfirst($this->configurations[$signature]['logger']); if (class_exists($class)) { $this->loggers[$signature] = new $class($this->configurations[$signature]); } else { throw new LogException(JText::_('Unable to create a JLogger instance: ')); } } // Add the entry to the logger. $this->loggers[$signature]->addEntry($entry); } } /** * Method to find the loggers to use based on priority and category values. * * @param integer $priority Message priority. * @param string $category Type of entry * * @return array The array of loggers to use for the given priority and category values. * * @since 11.1 */ protected function findLoggers($priority, $category) { // Initialize variables. $loggers = array(); // Sanitize inputs. $priority = (int) $priority; $category = strtolower($category); // Let's go iterate over the loggers and get all the ones we need. foreach ((array) $this->lookup as $signature => $rules) { // Check to make sure the priority matches the logger. if ($priority & $rules->priorities) { // If either there are no set categories (meaning all) or the specific category is set, add this logger. if (empty($category) || empty($rules->categories) || in_array($category, $rules->categories)) { $loggers[] = $signature; } } } return $loggers; } }