diff options
Diffstat (limited to 'framework/Log/EventLog/writers')
-rw-r--r-- | framework/Log/EventLog/writers/writer_database.php | 216 | ||||
-rw-r--r-- | framework/Log/EventLog/writers/writer_file.php | 273 | ||||
-rw-r--r-- | framework/Log/EventLog/writers/writer_unix_file.php | 100 |
3 files changed, 589 insertions, 0 deletions
diff --git a/framework/Log/EventLog/writers/writer_database.php b/framework/Log/EventLog/writers/writer_database.php new file mode 100644 index 00000000..6908a770 --- /dev/null +++ b/framework/Log/EventLog/writers/writer_database.php @@ -0,0 +1,216 @@ +<?php +/** + * File containing the ezcLogWriterDatabase class. + * + * @package EventLog + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ + +/** + * Writes log messages to the database. + * + * @package EventLog + * @version //autogentag// + */ +class ezcLogWriterDatabase implements ezcLogWriter +{ + private $db = null; + + private $properties = array(); + private $defaultColumns = array(); + private $additionalColumns = array(); + + private $map; + private $defaultTable = false; + + /** + * Construct a new database log-writer. + * + * You can set the default table to write to with the $defaultTable parameter. + * If $databaseInstance is given, that instance will be used for writing. If it + * is ommitted the default database instance will be retrieved. + * + * This constructor is a tie-in. + * + * @param string $defaultTable + * @param ezcDbHandler $databaseInstance + * + */ + public function __construct( ezcDbHandler $databaseInstance, $defaultTable = false ) + { + $this->db = $databaseInstance; + + $this->map = new ezcLogMap(); + $this->defaultTable = $defaultTable; + + $this->message = "message"; + $this->datetime = "time"; + $this->severity = "severity"; + $this->source = "source"; + $this->category = "category"; + } + + /** + * Sets the property $name to $value. + * + * @throws ezcBasePropertyNotFoundException if the property does not exist. + * @param string $name + * @param mixed $value + * @return void + */ + public function __set( $name, $value ) + { + switch ( $name ) + { + case 'table': $this->properties['table'] = $value; break; + case 'message': + case 'datetime': + case 'severity': + case 'source': + case 'category': $this->defaultColumns[ $name ] = $value; break; + default: $this->additionalColumns[ $name ] = $value; break; + } + } + + /** + * Returns the property $name. + * + * @throws ezcBasePropertyNotFoundException if the property does not exist. + * @param string $name + * @return mixed + */ + public function __get( $name ) + { + switch ( $name ) + { + case 'table': return $this->properties['table']; break; + case 'message': + case 'datetime': + case 'severity': + case 'source': + case 'category': return $this->defaultColumns[ $name ]; break; + + default: return $this->additionalColumns[ $name ]; break; + } + } + + /** + * Writes the message $message to the log. + * + * The writer can use the severity, source, and category to filter the + * incoming messages and determine the location where the messages should + * be written. + * + * $optional may contain extra information that can be added to the log. For example: + * line numbers, file names, usernames, etc. + * + * @throws ezcLogWriterException when the log writer was unable to write + * the log message. + * @param string $message + * @param int $severity + * ezcLog:: DEBUG, SUCCES_AUDIT, FAILED_AUDIT, INFO, NOTICE, WARNING, ERROR or FATAL. + * + * $param string $source + * @param string $category + * @param array(string=>string) $optional + * @return void + */ + public function writeLogMessage( $message, $severity, $source, $category, $optional = array() ) + { + $severityName = ezcLog::translateSeverityName( $severity ); + + $colStr = ""; + $valStr = ""; + + if ( is_array( $optional ) ) + { + foreach ( $optional as $key => $val ) + { + $colStr .= ", " . ( isset( $this->additionalColumns[$key] ) ? $this->additionalColumns[$key] : $key ); + $valStr .= ", " . $this->db->quote( $val ); + } + } + + $tables = $this->map->get( $severity, $source, $category ); + + $query = $this->db->createSelectQuery(); + if ( count( $tables ) > 0) + { + foreach ( $tables as $t ) + { + try + { + $this->db->exec( "INSERT INTO `{$t}` ( {$this->message}, {$this->severity}, {$this->source}, {$this->category}, {$this->datetime} $colStr ) ". + "VALUES( ".$this->db->quote( $message ).", ".$this->db->quote( $severityName ).", ".$this->db->quote( $source ).", ". + $this->db->quote( $category ).", ".$query->expr->now()." $valStr )" ); + } + catch ( PDOException $e ) + { + throw new ezcLogWriterException( "SQL query failed in ezcLogWriterDatabase.\n". $e->getMessage() ); + } + } + } + else + { + if ( $this->defaultTable !== false ) + { + try + { + $this->db->exec( "INSERT INTO `{$this->defaultTable}` ( {$this->message}, {$this->severity}, {$this->source}, {$this->category}, {$this->datetime} $colStr ) ". + "VALUES( ".$this->db->quote( $message ).", ".$this->db->quote( $severityName ).", ".$this->db->quote( $source ).", ". + $this->db->quote( $category ).", ".$query->expr->now()." $valStr )" ); + } + catch ( PDOException $e ) + { + throw new ezcLogWriterException( "SQL query failed in ezcLogWriterDatabase.\n". $e->getMessage() ); + } + } + } + } + + /** + * Returns an array that describes the coupling between the logMessage + * information and the columns in the database. + * + * @return array(string=>string) + */ + public function getColumnTranslations() + { + return array_merge( $this->defaultColumns, $this->additionalColumns ); + } + + + /** + * Maps the table $tableName to the messages specified by the {@link ezcLogFilter} $logFilter. + * + * Log messages that matches with the filter are written to the table $tableName. + * This method works the same as {@link ezclog::map()}. + * + * @param ezcLogFilter $logFilter + * @param string $tableName + * @return void + */ + public function map( ezcLogFilter $logFilter, $tableName ) + { + $this->map->map( $logFilter->severity, $logFilter->source, $logFilter->category, $tableName ); + } + + /** + * Unmaps the table $tableName from the messages specified by the {@link ezcLogFilter} $logFilter. + * + * Log messages that matches with the filter are no longer written to the table $tableName. + * This method works the same as {@link ezclog::unmap()}. + * + * @param ezcLogFilter $logFilter + * @param string $fileName + * @return void + */ + public function unmap( ezcLogFilter $logFilter, $tableName ) + { + $this->map->unmap( $logFilter->severity, $logFilter->source, $logFilter->category, $tableName ); + } +} + +?> diff --git a/framework/Log/EventLog/writers/writer_file.php b/framework/Log/EventLog/writers/writer_file.php new file mode 100644 index 00000000..46ecf13e --- /dev/null +++ b/framework/Log/EventLog/writers/writer_file.php @@ -0,0 +1,273 @@ +<?php +/** + * File containing the ezcLogWriterFile class. + * + * @package EventLog + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ + +/** + * The ezcLogWriterFile class provides functionality to write log files to the file + * system. + * + * The main purpose is to keep track of the various log files and support + * log rotation. The file format of the log should be implemented in a subclass. + * + * The following example implements a new log writer that writes the output in ({@link print_r()} format) + * to a file: + * <code> + * class MyLogWriter extends ezcLogWriterFile + * { + * // Call parent constructor. (In this case, it possible to omit the constructor.) + * public function __construct($dir, $file = null, $maxSize = 204800, $maxFiles = 3 ) + * { + * parent::__construct($dir, $file, $maxSize, $maxFiles); + * } + * + * // Implement the ezcLogWriter interface: + * public function writeLogMessage( $message, $type, $source, $category, $extraInfo = array() ) + * { + * // Create a message + * $res = print_r( array( "message" => $message, "type" => $type, "source" => $source, "category" => $category ), true ); + * + * // And call the parent class + * $this->write( $type, $source, $category, $res ); + * } + *} + * </code> + * + * @package EventLog + * @version //autogentag// + */ +abstract class ezcLogWriterFile implements ezcLogWriter +{ + /** + * Contains all the open files. The first file in the + * array is always the default file. + * + * @var array(resource) + */ + protected $openFiles = array(); + + + /** + * Keeps track of which group of messages should be stored + * in what file. + * + * @var ezcLogMap + */ + protected $fileMap; + + /** + * Directory where the log files should be placed. + * + * @var string + */ + protected $logDirectory; + + /** + * Maximum file size before rotation. + * + * @var int + */ + protected $maxSize; + + /** + * Maximum log rotation files with the same name. + * + * When rotating and the max limit is reached, the oldest log + * is discarded. + * + * @var int + */ + protected $maxFiles; + + + /** + * Constructs an ezcLogFileWriter. + * + * The log files will be placed in the directory $logDirectory. + * + * If the file $defaultFile is not null, log messages that are not {@link map() mapped} + * to any file are written to this $defaultFile. If $defaultFile is null, then + * log messages are discarded. + + * + * Set $maxLogRotationSize to specify the maximum size of a logfile. When the + * maximum size is reached, the log will be rotated. $maxLogFiles sets the maximum + * number of rotated log files. The oldest rotated log will be removed when the + * maxLogFiles exceeds. + * + * @param string $logDirectory + * @param string $defaultFile + * @param string $maxLogRotationSize + * @param string $maxLogFiles + */ + public function __construct( $logDirectory, $defaultFile = null, $maxLogRotationSize = 204800, $maxLogFiles = 3 ) + { + $this->maxSize = $maxLogRotationSize; + $this->maxFiles = $maxLogFiles; + $this->logDirectory = $logDirectory; + $this->defaultFile = $defaultFile; + + if ( !is_null( $defaultFile ) ) + { + $this->openFile( $defaultFile ); + } + + $this->fileMap = new ezcLogMap(); + } + + /** + * Destructs the object and closes all open file handles. + */ + public function __destruct() + { + foreach ( $this->openFiles as $fh ) + { + fclose( $fh ); + } + } + + + /** + * This method writes the $string to a file. + * + * The file to which the string will be written depends on the $eventType, $eventSource, and + * $eventCategory. + * + * @throws ezcLogWriterException if it was not possible to write to the log file. + * @param int $eventType + * @param string $eventSource + * @param string $eventCategory + * @param string $string + * @return void + */ + protected function write( $eventType, $eventSource, $eventCategory, $string ) + { + $fileHandles = $this->fileMap->get( $eventType, $eventSource, $eventCategory ); + + if ( count( $fileHandles ) > 0 ) + { + foreach ( $fileHandles as $fh ) + { + if ( fwrite( $fh, $string ) === false) + { + throw ezcLogWriterException( "Cannot write to the attached log file.", ezcLogWriterException::FILE_NOT_WRITABLE ); + } + } + } + else + { + if ( !is_null( $this->defaultFile ) ) + { + if ( fwrite( $this->openFiles[$this->defaultFile], $string ) === false ) + { + throw ezcLogWriterException( "Cannot write to the default log file.", ezcLogWriterException::FILE_NOT_WRITABLE ); + } + } + } + } + + /** + * Returns the filehandle of the $fileName. + * + * If the maximum file size is exceeded, the file will be rotated before opening. + * + * @return resource + */ + protected function openFile( $fileName ) + { + if ( isset( $this->openFiles[$fileName] ) ) + { + return $this->openFiles[$fileName]; + } + + clearstatcache(); + if ( file_exists( $this->logDirectory . "/". $fileName ) && + ( filesize( $this->logDirectory . "/". $fileName ) >= $this->maxSize ) ) + { + $this->rotateLog( $fileName ); + } + + $fh = @fopen( $this->logDirectory ."/". $fileName, "w" ); + if ( $fh === false ) + { + // throw exception. + throw new ezcLogFileException( "Cannot open the file <{$fileName}> for writing", ezcLogFileException::FILE_NOT_FOUND ); + } + + $this->openFiles[$fileName] = $fh; + return $fh; + } + + /** + * Rotates a log and returns true upon success. + * + * @return bool + */ + protected function rotateLog( $fileName ) + { + $file = $this->logDirectory . "/" . $fileName; + + for ( $i = $this->maxFiles; $i > 0; --$i ) + { + $logRotateName = $file. '.' . $i; + if ( file_exists( $logRotateName ) ) + { + if ( $i == $this->maxFiles ) + { + unlink( $logRotateName ); + } + else + { + $newLogRotateName = $file . '.' . ( $i + 1 ); + rename( $logRotateName, $newLogRotateName ); + } + } + } + if ( file_exists( $file ) ) + { + $newLogRotateName = $file . '.' . 1; + rename( $file, $newLogRotateName ); + return true; + } + return false; + } + + + /** + * Maps the filename $fileName to the messages specified by the {@link ezcLogFilter} $logFilter. + * + * Log messages that matches with the filter are written to the file $fileName. + * This method works the same as {@link ezclog::map()}. + * + * @param ezcLogFilter $logFilter + * @param string $fileName + * @return void + */ + public function map( ezcLogFilter $logFilter, $fileName ) + { + $fh = $this->openFile( $fileName ); + $this->fileMap->map( $logFilter->severity, $logFilter->source, $logFilter->category, $fh ); + } + + /** + * Unmaps the filename $fileName from the messages specified by the {@link ezcLogFilter} $logFilter. + * + * Log messages that matches with the filter are no longer written to the file $fileName. + * This method works the same as {@link ezclog::unmap()}. + * + * @param ezcLogFilter $logFilter + * @param string $fileName + * @return void + */ + public function unmap( $logFilter, $fileName ) + { + $this->fileMap->unmap( $logFilter->severity, $logFilter->source, $logFilter->category, $this->openFiles[ $fileName ] ); + } + +} +?> diff --git a/framework/Log/EventLog/writers/writer_unix_file.php b/framework/Log/EventLog/writers/writer_unix_file.php new file mode 100644 index 00000000..a2045217 --- /dev/null +++ b/framework/Log/EventLog/writers/writer_unix_file.php @@ -0,0 +1,100 @@ +<?php +/** + * File containing the ezcLogWriterUnix class. + * + * @package EventLog + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ + +/** + * Writes the log messages to a file in a format that is frequently used on the Unix operating system. + * + * @package EventLog + * @version //autogentag// + */ +class ezcLogWriterUnixFile extends ezcLogWriterFile +{ + /** + * Write the logEntries to a file. + * + * Each line in the log file represents a log message. The log + * messages have the following style: + * <pre> + * MMM dd HH:mm:ss [Severity] [Source] [Category] Message (ExtraInfo) + * </pre> + * + * With: + * - MMM: The 3 letter abbreviation of the month. + * - dd: The day of the month. + * - HH: The hour. + * - mm: The minutes. + * - ss: The seconds. + * + * Example: + * <pre> + * Jan 24 15:32:56 [Debug] [Paynet] [Shop] Connecting to the paynet server (file: paynet_server.php, line: 224). + * Jan 24 15:33:01 [Debug] [Paynet] [Shop] Connected with the server (file: paynet_server.php, line: 710). + * </pre> + * + * This method will be called by the {@link ezcLog} class. The $eventSource and $eventCategory are either given + * in the {@link ezcLog::log()} method or are the defaults from the {@link ezcLog} class. + * + * @param string $message + * @param int $eventType + * @param string $eventType + * @param string $eventCategory + * @param array(string=>string) $extraInfo + */ + public function writeLogMessage( $message, $eventType, $eventSource, $eventCategory, $extraInfo = array() ) + { + $extra = $this->implodeWithKey( ", ", ": ", $extraInfo ); + + if ( $eventCategory == false ) + { + $eventCategory = ""; + } + $logMsg = @date( "M d H:i:s" ) . + " [".ezcLog::translateSeverityName( $eventType ) . + "] [$eventSource] [$eventCategory] $message ($extra)\n"; + + $this->write( $eventType, $eventSource, $eventCategory, $logMsg ); + } + + /** + * Returns a string from the hash $data. + * + * The string $splitEntry specifies the string that will be inserted between the pairs. + * The string $splitKeyVal specifies the string that will be inserted in each pair. + * + * Example: + * <code> + * $this->implodeWithKey( ", ", ": ", array( "Car" => "red", "Curtains" => "blue" ); + * </code> + * + * Will create the following string: + * <pre> + * Car: red, Curtains: blue + * </pre> + * + * @param string $splitEntry + * @param string $splitKeyVal + * @param array(mixed=>mixed) $data + * @return string + */ + protected function implodeWithKey( $splitEntry, $splitKeyVal, $data) + { + $total = ""; + if ( is_array( $data ) ) + { + foreach ( $data as $key => $val ) + { + $total .= $splitEntry . $key . $splitKeyVal . $val; + } + } + + return substr( $total, strlen( $splitEntry ) ); + } +} +?> |