You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ih...@apache.org on 2012/02/28 08:49:23 UTC

svn commit: r1294503 [1/3] - in /logging/log4php/trunk/src: changes/ main/php/ main/php/appenders/ main/php/helpers/ main/php/layouts/ main/php/pattern/ site/xdoc/docs/layouts/ test/php/ test/php/appenders/ test/php/helpers/ test/php/layouts/ test/php/...

Author: ihabunek
Date: Tue Feb 28 07:49:21 2012
New Revision: 1294503

URL: http://svn.apache.org/viewvc?rev=1294503&view=rev
Log:
This commit deals with several interconnected issues:
LOG4PHP-172 - Rewritten pattern system to allow longer conversion words & some new ones. Also adapted LoggerAppenderPDO to use the new pattern system.
LOG4PHP-134 - Added reconnectAttempts parameter to LoggerAppenderPDO. Enables reconnect attempts if appending fails.
LOG4PHP-163 - Fixed formatting bug in LoggerLayoutPattern

Added:
    logging/log4php/trunk/src/main/php/helpers/LoggerUtils.php
    logging/log4php/trunk/src/main/php/pattern/
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverter.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterClass.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterCookie.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterDate.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterEnvironment.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterFile.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLevel.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLine.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLiteral.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLocation.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLogger.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMDC.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMessage.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMethod.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterNDC.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterNewLine.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterProcess.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterRelative.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterRequest.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterServer.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterSession.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterSessionID.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterSuperglobal.php
    logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterThrowable.php
    logging/log4php/trunk/src/test/php/helpers/LoggerUtilsTest.php
    logging/log4php/trunk/src/test/php/pattern/
    logging/log4php/trunk/src/test/php/pattern/LoggerPatternConverterTest.php
Removed:
    logging/log4php/trunk/src/main/php/helpers/LoggerBasicPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerCategoryPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerClassNamePatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerDatePatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerLiteralPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerLocationPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerMDCPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php
    logging/log4php/trunk/src/main/php/helpers/LoggerPatternConverter.php
Modified:
    logging/log4php/trunk/src/changes/changes.xml
    logging/log4php/trunk/src/main/php/LoggerAutoloader.php
    logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php
    logging/log4php/trunk/src/main/php/appenders/LoggerAppenderPDO.php
    logging/log4php/trunk/src/main/php/helpers/LoggerFormattingInfo.php
    logging/log4php/trunk/src/main/php/helpers/LoggerPatternParser.php
    logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php
    logging/log4php/trunk/src/site/xdoc/docs/layouts/pattern.xml
    logging/log4php/trunk/src/test/php/LoggerMDCTest.php
    logging/log4php/trunk/src/test/php/LoggerTestHelper.php
    logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPDOTest.php
    logging/log4php/trunk/src/test/php/bootstrap.php
    logging/log4php/trunk/src/test/php/helpers/LoggerPatternParserTest.php
    logging/log4php/trunk/src/test/php/layouts/LoggerLayoutPatternTest.php

Modified: logging/log4php/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/changes/changes.xml?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/changes/changes.xml (original)
+++ logging/log4php/trunk/src/changes/changes.xml Tue Feb 28 07:49:21 2012
@@ -20,7 +20,12 @@
 		<title>Apache log4php changelog</title>
 	</properties>
 	<body>
-	    <release version="2.2.1" date="2012-02-18.">
+		<release version="2.3.0" date="SVN">
+			<action date="2011-02-28" type="fix" issue="LOG4PHP-163" dev="Ivan Habunek">Fixed formatting bug in LoggerLayoutPattern.</action>
+			<action date="2011-02-28" type="update" issue="LOG4PHP-172" dev="Ivan Habunek">Rewritten pattern system to allow longer conversion words and some new ones.</action>
+			<action date="2011-02-28" type="add" issue="LOG4PHP-134" dev="Ivan Habunek">Added reconnectAttempts parameter to LoggerAppenderPDO. Adds support for reconnect if connection fails while appending.</action>
+		</release>
+	    <release version="2.2.1" date="2012-02-18">
 	        <action date="2011-02-07" type="fix" issue="LOG4PHP-168" dev="Ivan Habunek">Fixed a bug which prevented configuration by passing a LoggerConfigurator instance.</action>
 	    	<action date="2012-01-29" type="fix" issue="LOG4PHP-167" dev="Ivan Habunek">Fixed a bug which prevented parsing of INI configuration files when using PHP 5.2.x.</action>
 	        <action date="2011-12-22" type="update" issue="LOG4PHP-166" dev="Ivan Habunek" due-to="David Hilowitz" due-to-email="dhilowitz at gmail dot com">Added connection timeout parameter to MongoDB appender.</action>

Modified: logging/log4php/trunk/src/main/php/LoggerAutoloader.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerAutoloader.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerAutoloader.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerAutoloader.php Tue Feb 28 07:49:21 2012
@@ -42,6 +42,7 @@ class LoggerAutoloader {
 		'LoggerConfigurable' => '/LoggerConfigurable.php',
 		'LoggerConfigurator' => '/LoggerConfigurator.php',
 		'LoggerException' => '/LoggerException.php',
+		'LoggerFilter' => '/LoggerFilter.php',
 		'LoggerHierarchy' => '/LoggerHierarchy.php',
 		'LoggerLevel' => '/LoggerLevel.php',
 		'LoggerLocationInfo' => '/LoggerLocationInfo.php',
@@ -52,7 +53,7 @@ class LoggerAutoloader {
 		'LoggerReflectionUtils' => '/LoggerReflectionUtils.php',
 		'LoggerRoot' => '/LoggerRoot.php',
 		'LoggerThrowableInformation' => '/LoggerThrowableInformation.php',
-
+		
 		// Appenders
 		'LoggerAppenderConsole' => '/appenders/LoggerAppenderConsole.php',
 		'LoggerAppenderDailyFile' => '/appenders/LoggerAppenderDailyFile.php',
@@ -76,7 +77,6 @@ class LoggerAutoloader {
 		'LoggerConfiguratorDefault' => '/configurators/LoggerConfiguratorDefault.php',
 
 		// Filters
-		'LoggerFilter' => '/LoggerFilter.php',
 		'LoggerFilterDenyAll' => '/filters/LoggerFilterDenyAll.php',
 		'LoggerFilterLevelMatch' => '/filters/LoggerFilterLevelMatch.php',
 		'LoggerFilterLevelRange' => '/filters/LoggerFilterLevelRange.php',
@@ -86,18 +86,33 @@ class LoggerAutoloader {
 		'LoggerFormattingInfo' => '/helpers/LoggerFormattingInfo.php',
 		'LoggerOptionConverter' => '/helpers/LoggerOptionConverter.php',
 		'LoggerPatternParser' => '/helpers/LoggerPatternParser.php',
+		'LoggerUtils' => '/helpers/LoggerUtils.php',
+	
+		// Pattern converters
+		'LoggerPatternConverter' => '/pattern/LoggerPatternConverter.php',
+		'LoggerPatternConverterClass' => '/pattern/LoggerPatternConverterClass.php',
+		'LoggerPatternConverterCookie' => '/pattern/LoggerPatternConverterCookie.php',
+		'LoggerPatternConverterDate' => '/pattern/LoggerPatternConverterDate.php',
+		'LoggerPatternConverterEnvironment' => '/pattern/LoggerPatternConverterEnvironment.php',
+		'LoggerPatternConverterFile' => '/pattern/LoggerPatternConverterFile.php',
+		'LoggerPatternConverterLevel' => '/pattern/LoggerPatternConverterLevel.php',
+		'LoggerPatternConverterLine' => '/pattern/LoggerPatternConverterLine.php',
+		'LoggerPatternConverterLiteral' => '/pattern/LoggerPatternConverterLiteral.php',
+		'LoggerPatternConverterLogger' => '/pattern/LoggerPatternConverterLogger.php',
+		'LoggerPatternConverterMDC' => '/pattern/LoggerPatternConverterMDC.php',
+		'LoggerPatternConverterMessage' => '/pattern/LoggerPatternConverterMessage.php',
+		'LoggerPatternConverterMethod' => '/pattern/LoggerPatternConverterMethod.php',
+		'LoggerPatternConverterNDC' => '/pattern/LoggerPatternConverterNDC.php',
+		'LoggerPatternConverterNewLine' => '/pattern/LoggerPatternConverterNewLine.php',
+		'LoggerPatternConverterProcess' => '/pattern/LoggerPatternConverterProcess.php',
+		'LoggerPatternConverterRelative' => '/pattern/LoggerPatternConverterRelative.php',
+		'LoggerPatternConverterRequest' => '/pattern/LoggerPatternConverterRequest.php',
+		'LoggerPatternConverterServer' => '/pattern/LoggerPatternConverterServer.php',
+		'LoggerPatternConverterSession' => '/pattern/LoggerPatternConverterSession.php',
+		'LoggerPatternConverterSessionID' => '/pattern/LoggerPatternConverterSessionID.php',
+		'LoggerPatternConverterSuperglobal' => '/pattern/LoggerPatternConverterSuperglobal.php',
+		'LoggerPatternConverterThrowable' => '/pattern/LoggerPatternConverterThrowable.php',
 		
-		// Converters
-		'LoggerBasicPatternConverter' => '/helpers/LoggerBasicPatternConverter.php',
-		'LoggerCategoryPatternConverter' => '/helpers/LoggerCategoryPatternConverter.php',
-		'LoggerClassNamePatternConverter' => '/helpers/LoggerClassNamePatternConverter.php',
-		'LoggerDatePatternConverter' => '/helpers/LoggerDatePatternConverter.php',
-		'LoggerLiteralPatternConverter' => '/helpers/LoggerLiteralPatternConverter.php',
-		'LoggerLocationPatternConverter' => '/helpers/LoggerLocationPatternConverter.php',
-		'LoggerMDCPatternConverter' => '/helpers/LoggerMDCPatternConverter.php',
-		'LoggerNamedPatternConverter' => '/helpers/LoggerNamedPatternConverter.php',
-		'LoggerPatternConverter' => '/helpers/LoggerPatternConverter.php',
-
 		// Layouts
 		'LoggerLayoutHtml' => '/layouts/LoggerLayoutHtml.php',
 		'LoggerLayoutPattern' => '/layouts/LoggerLayoutPattern.php',
@@ -112,7 +127,7 @@ class LoggerAutoloader {
 		'LoggerRendererMap' => '/renderers/LoggerRendererMap.php',
 		'LoggerRendererObject' => '/renderers/LoggerRendererObject.php',
 	);
-
+	
 	/**
 	 * Loads a class.
 	 * @param string $className The name of the class to load.

Modified: logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php Tue Feb 28 07:49:21 2012
@@ -212,6 +212,14 @@ class LoggerLoggingEvent {
 	}
 
 	/**
+	 * Returns the logger which created the event.
+	 * @return Logger
+	 */
+	public function getLogger() {
+		return $this->logger;
+	}
+	
+	/**
 	 * Return the name of the logger. Use this form instead of directly
 	 * accessing the {@link $categoryName} field.
 	 * @return string  

Modified: logging/log4php/trunk/src/main/php/appenders/LoggerAppenderPDO.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/appenders/LoggerAppenderPDO.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/appenders/LoggerAppenderPDO.php (original)
+++ logging/log4php/trunk/src/main/php/appenders/LoggerAppenderPDO.php Tue Feb 28 07:49:21 2012
@@ -23,15 +23,18 @@
  *
  * Configurable parameters of this appender are:
  *
- * - user            - Sets the user of this database connection
- * - password        - Sets the password of this database connection
- * - createTable     - true, if the table should be created if necessary. false otherwise
- * - table           - Sets the table name (default: log4php_log)
- * - sql             - Sets the insert statement for a logging event. Defaults
+ * - dsn             - The DSN string for this connection
+ * - user            - The user of this database connection
+ * - password        - The password of this database connection
+ * - table           - Name of the database table into which log entries will be inserted (default: log4php_log)
+ * - insertSQL       - Sets the insert statement for a logging event. Defaults
  *                     to the correct one - change only if you are sure what you are doing.
- * - dsn             - Sets the DSN string for this connection
+ * - insertPattern   - The conversion pattern to use in conjuction with insert 
+ *                     SQL. Must contain the same number of comma separated 
+ *                     conversion patterns as there are question marks in the 
+ *                     insertSQL.
  *
- * If $sql is set then $table and $sql are used, else $table, $insertSql and $insertPattern.
+ * If $sql is set then $table and $sql are used, else $table, $insertSQL and $insertPattern.
  *
  * An example:
  *
@@ -46,265 +49,246 @@
  */
 class LoggerAppenderPDO extends LoggerAppender {
 
-	/** 
-	 * Create the log table if it does not exists (optional).
-	 * @var string 
-	 */
-	protected $createTable = true;
+	// ******************************************
+	// *** Configurable parameters            ***
+	// ******************************************
 	
 	/** 
-	 * Database user name.
-	 * @var string 
+	 * DSN string used to connect to the database.
+	 * @see http://www.php.net/manual/en/pdo.construct.php
 	 */
+	protected $dsn;
+
+	/** Database user name. */
 	protected $user;
 	
-	/** 
-	 * Database password
-	 * @var string 
-	 */
+	/** Database password. */
 	protected $password;
 	
 	/** 
-	 * DSN string for enabling a connection.
-	 * @var string 
-	 */
-	protected $dsn;
-	
-	/** 
-	 * A {@link LoggerPatternLayout} string used to format a valid insert query.
-	 * @deprecated Use {@link $insertSql} and {@link $insertPattern} which properly handle quotes in the messages!
-	 * @var string 
-	 */
-	protected $sql;
-	
-	/** 
-	 * Can be set to a complete insert statement with ? that are replaced using {@link insertPattern}.
-	 * @var string 
+	 * The insert query.
+	 * 
+	 * The __TABLE__ placeholder will be replaced by the table name from 
+	 * {@link $table}.
+	 *  
+	 * The questionmarks are part of the prepared statement, and they must 
+	 * match the number of conversion specifiers in {@link insertPattern}.
 	 */
-	protected $insertSql = "INSERT INTO __TABLE__ (timestamp, logger, level, message, thread, file, line) VALUES (?,?,?,?,?,?,?)";
+	protected $insertSQL = "INSERT INTO __TABLE__ (timestamp, logger, level, message, thread, file, line) VALUES (?, ?, ?, ?, ?, ?, ?)";
 
 	/** 
-	 * A comma separated list of {@link LoggerPatternLayout} format strings that replace the "?" in {@link $sql}.
-	 * @var string 
+	 * A comma separated list of {@link LoggerPatternLayout} format strings 
+	 * which replace the "?" in {@link $insertSQL}.
+	 * 
+	 * Must contain the same number of comma separated conversion patterns as 
+	 * there are question marks in {@link insertSQL}.
+ 	 * 
+ 	 * @see LoggerPatternLayout For conversion patterns.
 	 */
-	protected $insertPattern = "%d,%c,%p,%m,%t,%F,%L";
+	protected $insertPattern = "%date{Y-m-d H:i:s},%logger,%level,%message,%pid,%file,%line";
 
-	/** 
-	 * Table name to write events. Used only for CREATE TABLE if {@link $createTable} is true.
-	 * @var string 
-	 */
+	/** Name of the table to which to append log events. */
 	protected $table = 'log4php_log';
 	
+	/** The number of recconect attempts to make on failed append. */
+	protected $reconnectAttempts = 3;
+	
+	
+	// ******************************************
+	// *** Private memebers                   ***
+	// ******************************************
+	
 	/** 
 	 * The PDO instance.
 	 * @var PDO 
 	 */
-	protected $db = null;
+	protected $db;
 	
 	/** 
-	 * Prepared statement for the INSERT INTO query.
+	 * Prepared statement for the insert query.
 	 * @var PDOStatement 
 	 */
 	protected $preparedInsert;
-
-	/** 
-	 * Set in activateOptions() and later used in append() to check if all conditions to append are true.
-	 * @var boolean 
-	 */
-	protected $canAppend = true;
 	
-	/**
-	 * This appender does not require a layout.
-	 */
+	/** This appender does not require a layout. */
 	protected $requiresLayout = false;
 	
+
+	// ******************************************
+	// *** Appender methods                   ***
+	// ******************************************
+	
 	/**
-	 * Setup db connection.
-	 * Based on defined options, this method connects to db defined in {@link $dsn}
-	 * and creates a {@link $table} table if {@link $createTable} is true.
-	 * @return boolean true if all ok.
-	 * @throws a PDOException if the attempt to connect to the requested database fails.
+	 * Acquires a database connection based on parameters.
+	 * Parses the insert pattern to create a chain of converters which will be
+	 * used in forming query parameters from logging events.
 	 */
 	public function activateOptions() {
 		try {
-			if($this->user === null) {
-				$this->db = new PDO($this->dsn);
-			} else if($this->password === null) {
-				$this->db = new PDO($this->dsn, $this->user);
-			} else {
-				$this->db = new PDO($this->dsn,$this->user,$this->password);
-			}
-			$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-			
-			// test if log table exists
-			try {
-				$result = $this->db->query('SELECT * FROM ' . $this->table . ' WHERE 1 = 0');
-				$result->closeCursor(); 
-			} catch (PDOException $e) {
-				// It could be something else but a "no such table" is the most likely
-				$result = false;
-			}
-			
-			// create table if necessary
-			if ($result == false and $this->createTable) {
-				// The syntax should at least be compatible with MySQL, PostgreSQL, SQLite and Oracle.
-				$query = "CREATE TABLE {$this->table} (".
-							"timestamp varchar(32)," .
-							"logger varchar(64)," .
-							"level varchar(32)," .
-							"message varchar(9999)," .
-							"thread varchar(32)," .
-							"file varchar(255)," .
-							"line varchar(6))";
-				$result = $this->db->query($query);
-			}
+			$this->establishConnection();
 		} catch (PDOException $e) {
-			$this->canAppend = false;
-			throw new LoggerException($e);
+			$this->warn("Failed connecting to database: " . $e->getMessage());
+			$this->close();
+			return;
+		}
+
+		// Parse the insert patterns; pattern parts are comma delimited
+		$pieces = explode(',', $this->insertPattern);
+		$converterMap = LoggerLayoutPattern::getDefaultConverterMap();
+		foreach($pieces as $pattern) {
+			$parser = new LoggerPatternParser($pattern, $converterMap);
+			$this->converters[] = $parser->parse(); 
 		}
 		
-		$this->layout = new LoggerLayoutPattern();
+		$this->closed = false;
+	}
+	
+	/** 
+	 * Connects to the database, and prepares the insert query.
+	 * @throws PDOException If connect or prepare fails.  
+	 */
+	protected function establishConnection() {
+		// Acquire database connection
+		$this->db = new PDO($this->dsn, $this->user, $this->password);
+		$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 		
-		//
-		// Keep compatibility to legacy option $sql which already included the format patterns!
-		//
-		if (empty($this->sql)) {
-			// new style with prepared Statment and $insertSql and $insertPattern
-			// Maybe the tablename has to be substituted.
-			$this->insertSql = preg_replace('/__TABLE__/', $this->table, $this->insertSql);
-			$this->preparedInsert = $this->db->prepare($this->insertSql);
-			$this->layout->setConversionPattern($this->insertPattern);
-		} else {
-			// Old style with format strings in the $sql query should be used.
-		$this->layout->setConversionPattern($this->sql);
-		}
-
-		$this->canAppend = true;
-		return true;
+		// Prepare the insert statement
+		$insertSQL = str_replace('__TABLE__', $this->table, $this->insertSQL);
+		$this->preparedInsert = $this->db->prepare($insertSQL);
 	}
 	
 	/**
 	 * Appends a new event to the database.
 	 * 
-	 * @throws LoggerException If the pattern conversion or the INSERT statement fails.
+	 * If writing to database fails, it will retry by re-establishing the 
+	 * connection up to $reconnectAttempts times. If writing still fails, 
+	 * the appender will close.
 	 */
 	public function append(LoggerLoggingEvent $event) {
-		// TODO: Can't activateOptions() simply throw an Exception if it encounters problems?
-		if ( ! $this->canAppend) return;
-
+		
+		for ($attempt = 1; $attempt <= $this->reconnectAttempts; $attempt++) {
 			try {
-			if (empty($this->sql)) {
-				// new style with prepared statement
-				$params = $this->layout->formatToArray($event);
-				$this->preparedInsert->execute($params);
-			} else {
-				// old style
-				$query = $this->layout->format($event);
-				$this->db->exec($query);
+				// If it's a retry, reestablish the connection
+				if ($attempt > 1) {
+					$this->establishConnection();
+				}
+				
+				// Write to database
+				@$this->preparedInsert->execute($this->format($event));
+				@$this->preparedInsert->closeCursor();
+				break;
+			} catch (PDOException $e) {
+				$this->warn("Failed writing to database: ". $e->getMessage());
+				
+				// Close the appender if it's the last attempt
+				if ($attempt == $this->reconnectAttempts) {
+					$this->warn("Failed after {$this->reconnectAttempts} attempts. Closing appender.");
+					$this->close();
+				} else {
+					$this->warn("Attempting a reconnect (attempt $attempt of {$this->reconnectAttempts}).");
+				}
 			}
-			} catch (Exception $e) {
-				throw new LoggerException($e);
+		}
+	}
+	
+	/**
+	 * Converts the logging event to a series of database parameters by using 
+	 * the converter chain which was set up on activation. 
+	 */
+	protected function format(LoggerLoggingEvent $event) {
+		$params = array();
+		foreach($this->converters as $converter) {
+			$buffer = '';
+			while ($converter !== null) {
+				$converter->format($buffer, $event);
+				$converter = $converter->next;
 			}
+			$params[] = $buffer;
 		}
+		return $params;
+	}
 	
 	/**
 	 * Closes the connection to the logging database
 	 */
 	public function close() {
-		if($this->closed != true) {
-			if ($this->db !== null) {
-				$this->db = null;
-			}
-			$this->closed = true;
-		}
+		// Close the connection (if any)
+		$this->db = null;
+		
+		// Close the appender
+		$this->closed = true;
 	}
 	
+	// ******************************************
+	// *** Accessor methods                   ***
+	// ******************************************
+	
 	/**
-	 * Sets the username for this connection. 
-	 * Defaults to ''
+	 * Returns the active database handle or null if not established.
+	 * @return PDO
 	 */
+	public function getDatabaseHandle() {
+		return $this->db;
+	}
+	
+	/** Sets the username. */
 	public function setUser($user) {
 		$this->setString('user', $user);
 	}
 	
-	/**
-	 * Sets the password for this connection. 
-	 * Defaults to ''
-	 */
+	/** Returns the username. */
+	public function getUser($user) {
+		return $this->user;
+	}
+	
+	/** Sets the password. */
 	public function setPassword($password) {
 		$this->setString('password', $password);
 	}
 	
-	/**
-	 * Indicator if the logging table should be created on startup,
-	 * if its not existing.
-	 */
-	public function setCreateTable($flag) {
-		$this->setBoolean('createTable', $flag);
+	/** Returns the password. */
+	public function getPassword($password) {
+		return $this->password;
 	}
-   
-   	/**
-	 * Sets the SQL string into which the event should be transformed.
-	 * Defaults to:
-	 * 
-	 * INSERT INTO $this->table 
-	 * ( timestamp, logger, level, message, thread, file, line) 
-	 * VALUES 
-	 * ('%d','%c','%p','%m','%t','%F','%L')
-	 * 
-	 * It's not necessary to change this except you have customized logging'
-	 *
-	 * @deprecated See {@link setInsertSql} and {@link setInsertPattern}.
-	 */
-	public function setSql($sql) {
-		$this->setString('sql', $sql);
+	
+	/** Sets the insert SQL. */
+	public function setInsertSQL($sql) {
+		$this->setString('insertSQL', $sql);
 	}
 	
-	/**
-	 * Sets the SQL INSERT string to use with {@link $insertPattern}.
-	 *
-	 * @param $sql		  A complete INSERT INTO query with "?" that gets replaced.
-	 */
-	public function setInsertSql($sql) {
-		$this->setString('insertSql', $sql);
+	/** Returns the insert SQL. */
+	public function getInsertSQL($sql) {
+		return $this->insertSQL;
 	}
 
-	/**
-	 * Sets the {@link LoggerLayoutPattern} format strings for {@link $insertSql}.
-	 *
-	 * It's not necessary to change this except you have customized logging.
-	 *
-	 * @param $pattern		  Comma separated format strings like "%p,%m,%C"
-	 */
+	/** Sets the insert pattern. */
 	public function setInsertPattern($pattern) {
 		$this->setString('insertPattern', $pattern);
 	}
+	
+	/** Returns the insert pattern. */
+	public function getInsertPattern($pattern) {
+		return $this->insertPattern;
+	}
 
-	/**
-	 * Sets the tablename to which this appender should log.
-	 * Defaults to log4php_log
-	 */
+	/** Sets the table name. */
 	public function setTable($table) {
 		$this->setString('table', $table);
 	}
 	
-	/**
-	 * Sets the DSN string for this connection. In case of
-	 * SQLite it could look like this: 'sqlite:appenders/pdotest.sqlite'
-	 */
+	/** Returns the table name. */
+	public function getTable($table) {
+		return $this->table;
+	}
+	
+	/** Sets the DSN string. */
 	public function setDSN($dsn) {
 		$this->setString('dsn', $dsn);
 	}
 	
-	/**
-	 * Sometimes databases allow only one connection to themselves in one thread.
-	 * SQLite has this behaviour. In that case this handle is needed if the database
-	 * must be checked for events.
-	 *
-	 * @return PDO
-	 */
-	public function getDatabaseHandle() {
-		return $this->db;
-	}
+	/** Returns the DSN string. */
+	public function getDSN($dsn) {
+		return $this->setString('dsn', $dsn);
+	}	
 }
 

Modified: logging/log4php/trunk/src/main/php/helpers/LoggerFormattingInfo.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/helpers/LoggerFormattingInfo.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/helpers/LoggerFormattingInfo.php (original)
+++ logging/log4php/trunk/src/main/php/helpers/LoggerFormattingInfo.php Tue Feb 28 07:49:21 2012
@@ -27,24 +27,28 @@
  * @since 0.3
  */
 class LoggerFormattingInfo {
-
-	public $min = -1;
-	public $max = 0x7FFFFFFF;
-	public $leftAlign = false;
-
+	
+	/** 
+	 * Minimal output length. If output is shorter than this value, it will be
+	 * padded with spaces. 
+	 */
+	public $min = 0;
+	
+	/** 
+	 * Maximum output length. If output is longer than this value, it will be 
+	 * trimmed.
+	 */
+	public $max = PHP_INT_MAX;
+	
 	/**
-	 * Constructor
+	 * Whether to pad the string from the left. If set to false, the string 
+	 * will be padded from the right. 
 	 */
-	public function __construct() {}
+	public $padLeft = true;
 	
-	public function reset() {
-		$this->min = -1;
-		$this->max = 0x7FFFFFFF;
-		$this->leftAlign = false;
-	}
-
-	public function dump() {
-		// TODO: other option to dump?
-		// LoggerLog::debug("LoggerFormattingInfo::dump() min={$this->min}, max={$this->max}, leftAlign={$this->leftAlign}");
-	}
+	/**
+	 * Whether to trim the string from the left. If set to false, the string
+	 * will be trimmed from the right.
+	 */
+	public $trimLeft = false;
 }

Modified: logging/log4php/trunk/src/main/php/helpers/LoggerPatternParser.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/helpers/LoggerPatternParser.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/helpers/LoggerPatternParser.php (original)
+++ logging/log4php/trunk/src/main/php/helpers/LoggerPatternParser.php Tue Feb 28 07:49:21 2012
@@ -33,299 +33,206 @@
  */
 class LoggerPatternParser {
 
+	/** Escape character for conversion words in the conversion pattern. */
 	const ESCAPE_CHAR = '%';
 	
-	const LITERAL_STATE = 0;
-	const CONVERTER_STATE = 1;
-	const MINUS_STATE = 2;
-	const DOT_STATE = 3;
-	const MIN_STATE = 4;
-	const MAX_STATE = 5;
-	
-	const FULL_LOCATION_CONVERTER = 1000;
-	const METHOD_LOCATION_CONVERTER = 1001;
-	const CLASS_LOCATION_CONVERTER = 1002;
-	const FILE_LOCATION_CONVERTER = 1003;
-	const LINE_LOCATION_CONVERTER = 1004;
-	
-	const RELATIVE_TIME_CONVERTER = 2000;
-	const THREAD_CONVERTER = 2001;
-	const LEVEL_CONVERTER = 2002;
-	const NDC_CONVERTER = 2003;
-	const MESSAGE_CONVERTER = 2004;
-	
-	const DATE_FORMAT_ISO8601 = 'Y-m-d H:i:s,u'; 
-	const DATE_FORMAT_ABSOLUTE = 'H:i:s';
-	const DATE_FORMAT_DATE = 'd M Y H:i:s,u';
-
-	private $state;
-	private $currentLiteral;
-	private $patternLength;
-	private $i;
+	/** Maps conversion words to relevant converters. */
+	private $converterMap;
 	
-	/**
-	 * @var LoggerPatternConverter
-	 */
-	private $head = null;
-	 
-	/**
+	/** Conversion pattern used in layout. */
+	private $pattern;
+	
+	/** Regex pattern used for parsing the conversion pattern. */
+	private $regex;
+	
+	/** 
+	 * First converter in the chain. 
 	 * @var LoggerPatternConverter
 	 */
-	private $tail = null;
+	private $head;
 	
-	/**
-	 * @var LoggerFormattingInfo
-	 */
-	private $formattingInfo;
+	/** Last converter in the chain. */
+	private $tail;
 	
-	/**
-	 * @var string pattern to parse
+	public function __construct($pattern, $converterMap) {
+		$this->pattern = $pattern;
+		$this->converterMap = $converterMap;
+		
+		// Construct the regex pattern
+		$this->regex = 
+			'/' .                       // Starting regex pattern delimiter
+			self::ESCAPE_CHAR .         // Character which marks the start of the conversion pattern
+			'(?P<modifiers>[0-9.-]*)' . // Format modifiers (optional)
+			'(?P<word>[a-zA-Z]+)' .     // The conversion word
+			'(?P<option>{[^}]*})?' .   // Conversion option in braces (optional)
+			'/';                        // Ending regex pattern delimiter
+	}
+	
+	/** 
+	 * Parses the conversion pattern string, converts it to a chain of pattern
+	 * converters and returns the first converter in the chain.
+	 * 
+	 * @return LoggerPatternConverter
 	 */
-	private $pattern;
+	public function parse() {
+		
+		// Skip parsing if the pattern is empty
+		if (empty($this->pattern)) {
+			$this->addLiteral('');
+			return $this->head;
+		}
+		
+		// Find all conversion words in the conversion pattern
+		$count = preg_match_all($this->regex, $this->pattern, $matches, PREG_OFFSET_CAPTURE);
+		if ($count === false) {
+			$error = error_get_last();
+			throw new LoggerException("Failed parsing layotut pattern: {$error['message']}");
+		}
+		
+		$prevEnd = 0;
+		
+		foreach($matches[0] as $key => $item) {
+			
+			// Locate where the conversion command starts and ends
+			$length = strlen($item[0]);
+			$start = $item[1];
+			$end = $item[1] + $length;
+		
+			// Find any literal expressions between matched commands
+			if ($start > $prevEnd) {
+				$literal = substr($this->pattern, $prevEnd, $start - $prevEnd);
+				$this->addLiteral($literal);
+			}
+			
+			// Extract the data from the matched command
+			$word = !empty($matches['word'][$key]) ? $matches['word'][$key][0] : null;
+			$modifiers = !empty($matches['modifiers'][$key]) ? $matches['modifiers'][$key][0] : null;
+			$option = !empty($matches['option'][$key]) ? $matches['option'][$key][0] : null;
+			
+			// Create a converter and add it to the chain
+			$this->addConverter($word, $modifiers, $option);
+			
+			$prevEnd = $end;
+		}
 
-	/**
-	 * Constructor 
-	 *
-	 * @param string $pattern
+		// Add any trailing literals
+		if ($end < strlen($this->pattern)) {
+			$literal = substr($this->pattern, $end);
+			$this->addLiteral($literal);
+		}
+		
+		return $this->head;
+	}
+	
+	/** 
+	 * Adds a literal converter to the converter chain. 
+	 * @param string $string The string for the literal converter.
 	 */
-	public function __construct($pattern) {
-		$this->pattern = $pattern;
-		$this->patternLength =	strlen($pattern);
-		$this->formattingInfo = new LoggerFormattingInfo();
-		$this->state = self::LITERAL_STATE;
+	private function addLiteral($string) {
+		$converter = new LoggerPatternConverterLiteral($string);
+		$this->addToChain($converter);
 	}
-
+	
 	/**
-	 * @param LoggerPatternConverter $pc
-	 */
-	public function addToList($pc) {
-		if($this->head == null) {
-			$this->head = $pc;
-			$this->tail = $this->head;
+	 * Adds a non-literal converter to the converter chain.
+	 * 
+	 * @param string $word The conversion word, used to determine which 
+	 *  converter will be used.
+	 * @param string $modifiers Formatting modifiers.
+	 * @param string $option Option to pass to the converter.
+	 */
+	private function addConverter($word, $modifiers, $option) {
+ 		$formattingInfo = $this->parseModifiers($modifiers);
+		$option = trim($option, "{} ");
+		
+		if (isset($this->converterMap[$word])) {
+			$converter = $this->getConverter($word, $formattingInfo, $option);
+			$this->addToChain($converter);	
 		} else {
-			$this->tail->next = $pc;
-			$this->tail = $this->tail->next;
+			trigger_error("log4php: Invalid keyword '%$word' in converison pattern. Ignoring keyword.", E_USER_WARNING);
 		}
 	}
-
+	
 	/**
-	 * @return string
+	 * Determines which converter to use based on the conversion word. Creates 
+	 * an instance of the converter using the provided formatting info and 
+	 * option and returns it.
+	 * 
+	 * @param string $word The conversion word.
+	 * @param LoggerFormattingInfo $info Formatting info.
+	 * @param string $option Converter option.
+	 * 
+	 * @throws LoggerException 
+	 * 
+	 * @return LoggerPatternConverter
 	 */
-	public function extractOption() {
-		if(($this->i < $this->patternLength) and ($this->pattern{$this->i} == '{')) {
-			$end = strpos($this->pattern, '}' , $this->i);
-			if($end !== false) {
-				$r = substr($this->pattern, ($this->i + 1), ($end - $this->i - 1));
-				$this->i= $end + 1;
-				return $r;
-			}
+	private function getConverter($word, $info, $option) {
+		if (!isset($this->converterMap[$word])) {
+			throw new LoggerException("Invalid keyword '%$word' in converison pattern. Ignoring keyword.");
 		}
-		return null;
+		
+		$converterClass = $this->converterMap[$word];
+		if(!class_exists($converterClass)) {
+			throw new LoggerException("Class '$converterClass' does not exist.");
+		}
+		
+		$converter = new $converterClass($info, $option);
+		if(!($converter instanceof LoggerPatternConverter)) {
+			throw new LoggerException("Class '$converterClass' is not an instance of LoggerPatternConverter.");
+		}
+		
+		return $converter;
 	}
-
-	/**
-	 * The option is expected to be in decimal and positive. In case of
-	 * error, zero is returned.	 
-	 */
-	public function extractPrecisionOption() {
-		$opt = $this->extractOption();
-		$r = 0;
-		if($opt !== null) {
-			if(is_numeric($opt)) {
-				$r = (int)$opt;
-				if($r <= 0) {
-					$r = 0;
-				}
-			}
+	
+	/** Adds a converter to the chain and updates $head and $tail pointers. */
+	private function addToChain(LoggerPatternConverter $converter) {
+		if (!isset($this->head)) {
+			$this->head = $converter;
+			$this->tail = $this->head;
+		} else {
+			$this->tail->next = $converter;
+			$this->tail = $this->tail->next;
 		}
-		return $r;
 	}
-
 	
-	/** Parser.
+	/**
+	 * Parses the formatting modifiers and produces the corresponding 
+	 * LoggerFormattingInfo object.
 	 * 
-	 * @return LoggerPatternConverter Returns $this->head.
-	 */
-	public function parse() {
-		$c = '';
-		$this->i = 0;
-		$this->currentLiteral = '';
-		while($this->i < $this->patternLength) {
-			$c = $this->pattern{$this->i++};
-
-			switch($this->state) {
-				case self::LITERAL_STATE:
-					// In literal state, the last char is always a literal.
-					if($this->i == $this->patternLength) {
-						$this->currentLiteral .= $c;
-						continue;
-					}
-					if($c == self::ESCAPE_CHAR) {
-						// peek at the next char.
-						switch($this->pattern{$this->i}) {
-							case self::ESCAPE_CHAR:
-								$this->currentLiteral .= $c;
-								$this->i++; // move pointer
-								break;
-							case 'n':
-								$this->currentLiteral .= PHP_EOL;
-								$this->i++; // move pointer
-								break;
-							default:
-								if(strlen($this->currentLiteral) != 0) {
-									$this->addToList(new LoggerLiteralPatternConverter($this->currentLiteral));
-								}
-								$this->currentLiteral = $c;
-								$this->state = self::CONVERTER_STATE;
-								$this->formattingInfo->reset();
-						}
-					} else {
-						$this->currentLiteral .= $c;
-					}
-					break;
-				case self::CONVERTER_STATE:
-						$this->currentLiteral .= $c;
-						switch($c) {
-						case '-':
-							$this->formattingInfo->leftAlign = true;
-							break;
-						case '.':
-							$this->state = self::DOT_STATE;
-								break;
-						default:
-							if(ord($c) >= ord('0') and ord($c) <= ord('9')) {
-								$this->formattingInfo->min = ord($c) - ord('0');
-								$this->state = self::MIN_STATE;
-							} else {
-								$this->finalizeConverter($c);
-							}
-						} // switch
-					break;
-				case self::MIN_STATE:
-					$this->currentLiteral .= $c;
-					if(ord($c) >= ord('0') and ord($c) <= ord('9')) {
-						$this->formattingInfo->min = ($this->formattingInfo->min * 10) + (ord($c) - ord('0'));
-					} else if ($c == '.') {
-						$this->state = self::DOT_STATE;
-					} else {
-						$this->finalizeConverter($c);
-					}
-					break;
-				case self::DOT_STATE:
-					$this->currentLiteral .= $c;
-					if(ord($c) >= ord('0') and ord($c) <= ord('9')) {
-						$this->formattingInfo->max = ord($c) - ord('0');
-						$this->state = self::MAX_STATE;
-					} else {
-						$this->state = self::LITERAL_STATE;
-					}
-					break;
-				case self::MAX_STATE:
-					$this->currentLiteral .= $c;
-					if(ord($c) >= ord('0') and ord($c) <= ord('9')) {
-						$this->formattingInfo->max = ($this->formattingInfo->max * 10) + (ord($c) - ord('0'));
-					} else {
-						$this->finalizeConverter($c);
-						$this->state = self::LITERAL_STATE;
-					}
-					break;
-			} // switch
-		} // while
-		if(strlen($this->currentLiteral) != 0) {
-			$this->addToList(new LoggerLiteralPatternConverter($this->currentLiteral));
+	 * @param string $modifier
+	 * @return LoggerFormattingInfo
+	 * @throws LoggerException
+	 */
+	private function parseModifiers($modifiers) {
+		$info = new LoggerFormattingInfo();
+	
+		// If no modifiers are given, return default values
+		if (empty($modifiers)) {
+			return $info;
 		}
-		return $this->head;
-	}
-
-	public function finalizeConverter($c) {
-		$pc = null;
-		switch($c) {
-			case 'c':
-				$pc = new LoggerCategoryPatternConverter($this->formattingInfo, $this->extractPrecisionOption());
-				$this->currentLiteral = '';
-				break;
-			case 'C':
-				$pc = new LoggerClassNamePatternConverter($this->formattingInfo, self::CLASS_LOCATION_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'd':
-				$dateFormatStr = self::DATE_FORMAT_ISO8601; // ISO8601_DATE_FORMAT;
-				$dOpt = $this->extractOption();
-
-				if($dOpt !== null)
-					$dateFormatStr = $dOpt;
-					
-				if($dateFormatStr == 'ISO8601') {
-					$df = self::DATE_FORMAT_ISO8601;
-				} else if($dateFormatStr == 'ABSOLUTE') {
-					$df = self::DATE_FORMAT_ABSOLUTE;
-				} else if($dateFormatStr == 'DATE') {
-					$df = self::DATE_FORMAT_DATE;
-				} else {
-					$df = $dateFormatStr;
-					if($df == null) {
-						$df = self::DATE_FORMAT_ISO8601;
-					}
-				}
-				$pc = new LoggerDatePatternConverter($this->formattingInfo, $df);
-				$this->currentLiteral = '';
-				break;
-			case 'F':
-				$pc = new LoggerLocationPatternConverter($this->formattingInfo, self::FILE_LOCATION_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'l':
-				$pc = new LoggerLocationPatternConverter($this->formattingInfo, self::FULL_LOCATION_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'L':
-				$pc = new LoggerLocationPatternConverter($this->formattingInfo, self::LINE_LOCATION_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'm':
-				$pc = new LoggerBasicPatternConverter($this->formattingInfo, self::MESSAGE_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'M':
-				$pc = new LoggerLocationPatternConverter($this->formattingInfo, self::METHOD_LOCATION_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'p':
-				$pc = new LoggerBasicPatternConverter($this->formattingInfo, self::LEVEL_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'r':
-				$pc = new LoggerBasicPatternConverter($this->formattingInfo, self::RELATIVE_TIME_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 't':
-				$pc = new LoggerBasicPatternConverter($this->formattingInfo, self::THREAD_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'x':
-				$pc = new LoggerBasicPatternConverter($this->formattingInfo, self::NDC_CONVERTER);
-				$this->currentLiteral = '';
-				break;
-			case 'X':
-				$xOpt = $this->extractOption();
-				$pc = new LoggerMDCPatternConverter($this->formattingInfo, $xOpt);
-				$this->currentLiteral = '';
-				break;
-			default:
-				$pc = new LoggerLiteralPatternConverter($this->currentLiteral);
-				$this->currentLiteral = '';
+	
+		// Validate
+		$pattern = '/^(-?[0-9]+)?\.?-?[0-9]+$/';
+		if (!preg_match($pattern, $modifiers)) {
+			trigger_error("log4php: Invalid modifier in conversion pattern: [$modifiers]. Ignoring modifier.", E_USER_WARNING);
+			return $info;
 		}
-		$this->addConverter($pc);
-	}
-
-	public function addConverter($pc) {
-		$this->currentLiteral = '';
-		// Add the pattern converter to the list.
-		$this->addToList($pc);
-		// Next pattern is assumed to be a literal.
-		$this->state = self::LITERAL_STATE;
-		// Reset formatting info
-		$this->formattingInfo->reset();
+	
+		$parts = explode('.', $modifiers);
+	
+		if (!empty($parts[0])) {
+			$minPart = (integer) $parts[0];
+			$info->min = abs($minPart);
+			$info->padLeft = ($minPart > 0);
+		}
+	
+		if (!empty($parts[1])) {
+			$maxPart = (integer) $parts[1];
+			$info->max = abs($maxPart);
+			$info->trimLeft = ($maxPart > 0);
+		}
+	
+		return $info;
 	}
 }
 

Added: logging/log4php/trunk/src/main/php/helpers/LoggerUtils.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/helpers/LoggerUtils.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/helpers/LoggerUtils.php (added)
+++ logging/log4php/trunk/src/main/php/helpers/LoggerUtils.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Contains various helper methods.
+ * 
+ * @package log4php
+ * @subpackage helpers
+ * @since 2.3
+ */
+class LoggerUtils {
+	
+	/**
+ 	 * Splits a fully qualified class name into fragments delimited by the 
+ 	 * namespace separator (\). 
+ 	 * 
+ 	 * For backward compatibility, a dot (.) can be used as a delimiter as
+ 	 * well. 
+	 * 
+	 * @param string $name
+	 * 
+	 * @return array Class name split into fragments.
+	 */
+	public static function tokenizeClassName($name) {
+		$name = str_replace('.', '\\', $name);
+		$name = trim($name, ' \\');
+		$fragments = explode('\\', $name);
+		
+		foreach($fragments as $key => $fragment) {
+			if (trim($fragment) === '') {
+				unset($fragments[$key]);
+			}
+		}
+		
+		return $fragments;
+	}
+	
+	/**
+	 * Attempts to shorten the given class name to the desired length.
+	 * 
+	 * This is done by separating the class name into fragments (delimited
+	 * by \ or .) and trimming individual fragments, starting with the left,
+	 * until desired length has been reached. 
+	 * 
+	 * The final fragment (i.e. class name) will never be shortened so the 
+	 * result may still be longer than given length.
+	 * 
+	 * @param string $name The (qualified) class name.  
+	 * @param integer $length The length to shorten to. If null or 0 is given,
+	 * the name will be returned without shortening. 
+	 */
+	public static function shortenClassName($name, $length) {
+		if ($length === null || $length < 0) {
+			return $name;
+		}
+		
+		$name = str_replace('.', '\\', $name);
+		$name = trim($name, ' \\');
+		
+		// Check if any shortening is required
+		$currentLength = strlen($name);
+		if ($currentLength <= $length) {
+			return $name;
+		}
+	
+		// Split name into fragments
+		$fragments = explode('\\', $name);
+
+		// If zero length is specified, return only last fragment
+		if ($length == 0) {
+			return array_pop($fragments);
+		}
+		
+		// If the name splits to only one fragment, then it cannot be shortened
+		$count = count($fragments);
+		if ($count == 1) {
+			return $name;
+		}
+	
+		foreach($fragments as $key => &$fragment) {
+	
+			// Never shorten last fragment
+			if ($key == $count - 1) {
+				break;
+			}
+	
+			// Check for empty fragments (shouldn't happen but it's possible)
+			$fragLen = strlen($fragment);
+			if ($fragLen <= 1) {
+				continue;
+			}
+	
+			// Shorten fragment to one character and check if total length satisfactory
+			$fragment = substr($fragment, 0, 1);
+			$currentLength = $currentLength - $fragLen + 1;
+	
+			if ($currentLength <= $length) {
+				break;
+			}
+		}
+		unset($fragment);
+	
+		return implode('\\', $fragments);
+	}
+}
+

Modified: logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php?rev=1294503&r1=1294502&r2=1294503&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php (original)
+++ logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php Tue Feb 28 07:49:21 2012
@@ -21,122 +21,10 @@
 /**
  * A flexible layout configurable with pattern string.
  *
- * <p>Example:</p>
- * 
- * {@example ../../examples/php/layout_pattern.php 19}<br>
- * 
- * <p>with the following properties file:</p>
- * 
- * {@example ../../examples/resources/layout_pattern.properties 18}<br>
- * 
- * <p>would print the following:</p>
- * 
- * <pre>
- * 2009-09-09 00:27:35,787 [INFO] root: Hello World! (at src/examples/php/layout_pattern.php line 6)
- * 2009-09-09 00:27:35,787 [DEBUG] root: Second line (at src/examples/php/layout_pattern.php line 7)
- * </pre>
- *
- * <p>The conversion pattern is closely related to the conversion pattern of the printf function in C.
- * A conversion pattern is composed of literal text and format control expressions called conversion specifiers.
- * You are free to insert any literal text within the conversion pattern.</p> 
- *
- * <p>Each conversion specifier starts with a percent sign (%) and is followed by optional 
- * format modifiers and a conversion character.</p>
- * 
- * <p>The conversion character specifies the type of data, e.g. category, priority, date, thread name. 
- * The format modifiers control such things as field width, padding, left and right justification.</p>
- * 
- * <p>Note that there is no explicit separator between text and conversion specifiers.</p>
- * 
- * <p>The pattern parser knows when it has reached the end of a conversion specifier when it reads a conversion character. 
- * In the example above the conversion specifier %-5p means the priority of the logging event should be 
- * left justified to a width of five characters.</p> 
- *
- * Not all log4j conversion characters are implemented. The recognized conversion characters are:
- * - <b>c</b> Used to output the category of the logging event. The category conversion specifier can be optionally followed by precision specifier, that is a decimal constant in brackets. 
- *         If a precision specifier is given, then only the corresponding number of right most components of the category name will be printed. 
- *         By default the category name is printed in full. 
- *         For example, for the category name "a.b.c" the pattern %c{2} will output "b.c". 
- * - <b>C</b> Used to output the fully qualified class name of the caller issuing the logging request. 
- *         This conversion specifier can be optionally followed by precision specifier, that is a decimal constant in brackets. 
- *         If a precision specifier is given, then only the corresponding number of right most components of the class name will be printed. 
- *         By default the class name is output in fully qualified form. 
- *         For example, for the class name "org.apache.xyz.SomeClass", the pattern %C{1} will output "SomeClass". 
- * - <b>d</b> Used to output the date of the logging event. 
- *         The date conversion specifier may be followed by a date format specifier enclosed between braces.
- *         The format specifier follows the {@link PHP_MANUAL#date} function.
- *         Note that the special character <b>u</b> is used to as microseconds replacement (to avoid replacement,
- *         use <b>\u</b>).  
- *         For example, %d{H:i:s,u} or %d{d M Y H:i:s,u}. If no date format specifier is given then ISO8601 format is assumed. 
- *         The date format specifier admits the same syntax as the time pattern string of the SimpleDateFormat. 
- *         It is recommended to use the predefined log4php date formatters. 
- *         These can be specified using one of the strings "ABSOLUTE", "DATE" and "ISO8601" for specifying 
- *         AbsoluteTimeDateFormat, DateTimeDateFormat and respectively ISO8601DateFormat. 
- *         For example, %d{ISO8601} or %d{ABSOLUTE}. 
- * - <b>F</b> Used to output the file name where the logging request was issued. 
- * - <b>l</b> Used to output location information of the caller which generated the logging event. 
- * - <b>L</b> Used to output the line number from where the logging request was issued.
- * - <b>m</b> Used to output the application supplied message associated with the logging event.
- * - <b>M</b> Used to output the method name where the logging request was issued.  
- * - <b>p</b> Used to output the priority of the logging event.
- * - <b>r</b> Used to output the number of milliseconds elapsed since the start of 
- *            the application until the creation of the logging event. 
- * - <b>t</b> Used to output the name of the thread that generated the logging event.
- * - <b>x</b> Used to output the NDC (nested diagnostic context) associated with 
- *            the thread that generated the logging event.  
- * - <b>X</b> Used to output the MDC (mapped diagnostic context) associated with 
- *            the thread that generated the logging event. 
- *            The X conversion character must be followed by the key for the map placed between braces, 
- *            as in <i>%X{clientNumber}</i> where clientNumber is the key.
- *            The value in the MDC corresponding to the key will be output.
- *            See {@link LoggerMDC} class for more details. 
- * - <b>%</b> The sequence %% outputs a single percent sign.  
- *
- * <p>By default the relevant information is output as is. 
- *  However, with the aid of format modifiers it is possible to change the minimum field width, 
- *  the maximum field width and justification.</p> 
- *
- * <p>The optional format modifier is placed between the percent sign and the conversion character.</p>
- * <p>The first optional format modifier is the left justification flag which is just the minus (-) character. 
- *  Then comes the optional minimum field width modifier. 
- *  This is a decimal constant that represents the minimum number of characters to output. 
- *  If the data item requires fewer characters, it is padded on either the left or the right until the minimum width is reached. The default is to pad on the left (right justify) but you can specify right padding with the left justification flag. The padding character is space. If the data item is larger than the minimum field width, the field is expanded to accommodate the data. 
- *  The value is never truncated.</p>
- * 
- * <p>This behavior can be changed using the maximum field width modifier which is designated by a period 
- *  followed by a decimal constant. 
- *  If the data item is longer than the maximum field, 
- *  then the extra characters are removed from the beginning of the data item and not from the end. 
- *  For example, it the maximum field width is eight and the data item is ten characters long, 
- *  then the first two characters of the data item are dropped. 
- *  This behavior deviates from the printf function in C where truncation is done from the end.</p> 
- *
- * <p>Below are various format modifier examples for the category conversion specifier.</p> 
- * <pre>
- *   Format modifier  left justify  minimum width  maximum width  comment
- *   %20c             false         20             none           Left pad with spaces if the category name 
- *                                                                is less than 20 characters long.
- *   %-20c            true          20             none           Right pad with spaces if the category name 
- *                                                                is less than 20 characters long.  
- *   %.30c            NA            none           30             Truncate from the beginning if the category name 
- *                                                                is longer than 30 characters.  
- *   %20.30c          false         20             30             Left pad with spaces if the category name 
- *                                                                is shorter than 20 characters. 
- *                                                                However, if category name is longer than 30 chars, 
- *                                                                then truncate from the beginning.  
- *   %-20.30c         true          20             30             Right pad with spaces if the category name is 
- *                                                                shorter than 20 chars. 
- *                                                                However, if category name is longer than 30 chars, 
- *                                                                then truncate from the beginning.  
- * </pre>
- * 
- * @version $Revision$
- * @package log4php
- * @subpackage layouts
- * @since 0.3 
  */
 class LoggerLayoutPattern extends LoggerLayout {
-	/** Default conversion Pattern */
+	
+	/** Default conversion pattern */
 	const DEFAULT_CONVERSION_PATTERN = '%m%n';
 
 	/** Default conversion TTCC Pattern */
@@ -144,13 +32,89 @@ class LoggerLayoutPattern extends Logger
 
 	/** The conversion pattern. */ 
 	protected $pattern = self::DEFAULT_CONVERSION_PATTERN;
+	
+	/** Maps conversion keywords to the relevant converter. */
+	protected static $defaultConverterMap = array(
+		'c' => 'LoggerPatternConverterLogger',
+		'lo' => 'LoggerPatternConverterLogger',
+		'logger' => 'LoggerPatternConverterLogger',
+		
+		'C' => 'LoggerPatternConverterClass',
+		'class' => 'LoggerPatternConverterClass',
+		
+		'cookie' => 'LoggerPatternConverterCookie',
+		
+		'd' => 'LoggerPatternConverterDate',
+		'date' => 'LoggerPatternConverterDate',
+		
+		'e' => 'LoggerPatternConverterEnvironment',
+		'env' => 'LoggerPatternConverterEnvironment',
+		
+		'ex' => 'LoggerPatternConverterThrowable',
+		'throwable' => 'LoggerPatternConverterThrowable',
+		
+		'F' => 'LoggerPatternConverterFile',
+		'file' => 'LoggerPatternConverterFile',
+		
+		'L' => 'LoggerPatternConverterLine',
+		'line' => 'LoggerPatternConverterLine',
+		
+		'm' => 'LoggerPatternConverterMessage',
+		'msg' => 'LoggerPatternConverterMessage',
+		'message' => 'LoggerPatternConverterMessage',
+		
+		'M' => 'LoggerPatternConverterMethod',
+		'method' => 'LoggerPatternConverterMethod',
+		
+		'n' => 'LoggerPatternConverterNewLine',
+		'newline' => 'LoggerPatternConverterNewLine',
+		
+		'p' => 'LoggerPatternConverterLevel',
+		'le' => 'LoggerPatternConverterLevel',
+		'level' => 'LoggerPatternConverterLevel',
+	
+		'r' => 'LoggerPatternConverterRelative',
+		'relative' => 'LoggerPatternConverterRelative',
+		
+		'req' => 'LoggerPatternConverterRequest',
+		'request' => 'LoggerPatternConverterRequest',
+		
+		's' => 'LoggerPatternConverterServer',
+		'server' => 'LoggerPatternConverterServer',
+		
+		'ses' => 'LoggerPatternConverterSession',
+		'session' => 'LoggerPatternConverterSession',
+		
+		'sid' => 'LoggerPatternConverterSessionID',
+		'sessionid' => 'LoggerPatternConverterSessionID',
+	
+		't' => 'LoggerPatternConverterProcess',
+		'pid' => 'LoggerPatternConverterProcess',
+		'process' => 'LoggerPatternConverterProcess',
+		
+		'x' => 'LoggerPatternConverterNDC',
+		'ndc' => 'LoggerPatternConverterNDC',
+			
+		'X' => 'LoggerPatternConverterMDC',
+		'mdc' => 'LoggerPatternConverterMDC',
+	);
 
+	protected $converterMap = array();
+	
 	/** 
 	 * Head of a chain of Converters.
 	 * @var LoggerPatternConverter 
 	 */
 	private $head;
 
+	public static function getDefaultConverterMap() {
+		return self::$defaultConverterMap;
+	}
+	
+	public function __construct() {
+		$this->converterMap = self::$defaultConverterMap;
+	}
+	
 	/**
 	 * Set the <b>ConversionPattern</b> option. This is the string which
 	 * controls formatting and consists of a mix of literal content and
@@ -158,10 +122,17 @@ class LoggerLayoutPattern extends Logger
 	 */
 	public function setConversionPattern($conversionPattern) {
 		$this->pattern = $conversionPattern;
-		$patternParser = new LoggerPatternParser($this->pattern);
-		$this->head = $patternParser->parse();
 	}
-
+	
+	public function activateOptions() {
+		if (!isset($this->pattern)) {
+			throw new LoggerException("Mandatory parameter 'conversionPattern' is not set.");
+		}
+		
+		$parser = new LoggerPatternParser($this->pattern, $this->converterMap);
+		$this->head = $parser->parse();
+	}
+	
 	/**
 	 * Produces a formatted string as specified by the conversion pattern.
 	 *
@@ -170,36 +141,11 @@ class LoggerLayoutPattern extends Logger
 	 */
 	public function format(LoggerLoggingEvent $event) {
 		$sbuf = '';
-		$c = $this->head;
-		while ($c !== null) {
-			$c->format($sbuf, $event);
-			$c = $c->next;
+		$converter = $this->head;
+		while ($converter !== null) {
+			$converter->format($sbuf, $event);
+			$converter = $converter->next;
 		}
 		return $sbuf;
 	}
-	
-	/**
-	 * Returns an array with the formatted elements.
-	 * 
-	 * This method is mainly used for the prepared statements of {@see LoggerAppenderPDO}.
-	 * 
-	 * It requires {@link $this->pattern} to be a comma separated string of patterns like
-	 * e.g. <code>%d,%c,%p,%m,%t,%F,%L</code>.
-	 * 
-	 * @return array(string)   An array of the converted elements i.e. timestamp, message, filename etc.
-	 */
-	public function formatToArray(LoggerLoggingEvent $event) {
-		$results = array();
-		$c = $this->head;
-		while ($c !== null) {
-			if ( ! $c instanceOf LoggerLiteralPatternConverter) {
-				$sbuf = null;
-				$c->format($sbuf, $event);
-				$results[] = $sbuf;
-			}
-			$c = $c->next;
-		}
-		return $results;
-	}
-	
 }
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverter.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverter.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverter.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverter.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * LoggerPatternConverter is an abstract class that provides the formatting 
+ * functionality that derived classes need.
+ * 
+ * <p>Conversion specifiers in a conversion patterns are parsed to
+ * individual PatternConverters. Each of which is responsible for
+ * converting a logging event in a converter specific manner.</p>
+ * 
+ * @version $Revision: 1166187 $
+ * @package log4php
+ * @subpackage helpers
+ * @since 0.3
+ */
+abstract class LoggerPatternConverter {
+	
+	/**
+	 * Next converter in the converter chain.
+	 * @var LoggerPatternConverter 
+	 */
+	public $next = null;
+	
+	/**
+	 * Formatting information, parsed from pattern modifiers. 
+	 * @var LoggerFormattingInfo
+	 */
+	protected $formattingInfo;
+	
+	/**
+	 * Converter-specific formatting options.
+	 * @var array
+	 */
+	protected $option;
+
+	/**
+	 * Constructor 
+	 * @param LoggerFormattingInfo $formattingInfo
+	 * @param array $option
+	 */
+	public function __construct(LoggerFormattingInfo $formattingInfo = null, $option = null) {  
+		$this->formattingInfo = $formattingInfo;
+		$this->option = $option;
+		$this->activateOptions();
+	}
+	
+	/**
+	 * Called in constructor. Converters which need to process the options 
+	 * can override this method. 
+	 */
+	public function activateOptions() { }
+  
+	/**
+	 * Converts the logging event to the desired format. Derived pattern 
+	 * converters must implement this method.
+	 *
+	 * @param LoggerLoggingEvent $event
+	 */
+	abstract public function convert(LoggerLoggingEvent $event);
+
+	/**
+	 * Converts the event and formats it according to setting in the 
+	 * Formatting information object.
+	 *
+	 * @param string &$sbuf string buffer to write to
+	 * @param LoggerLoggingEvent $event Event to be formatted.
+	 */
+	public function format(&$sbuf, $event) {
+		$string = $this->convert($event);
+		
+		if (!isset($this->formattingInfo)) {
+			$sbuf .= $string;
+			return;	
+		}
+		
+		$fi = $this->formattingInfo;
+		
+		// Empty string
+		if($string === '' || is_null($string)) {
+			if($fi->min > 0) {
+				$sbuf .= str_repeat(' ', $fi->min);
+			}
+			return;
+		}
+		
+		$len = strlen($string);
+	
+		// Trim the string if needed
+		if($len > $fi->max) {
+			if ($fi->trimLeft) {
+				$sbuf .= substr($string, $len - $fi->max, $fi->max);
+			} else {
+				$sbuf .= substr($string , 0, $fi->max);
+			}
+		}
+		
+		// Add padding if needed
+		else if($len < $fi->min) {
+			if($fi->padLeft) {
+				$sbuf .= str_repeat(' ', $fi->min - $len);
+				$sbuf .= $string;
+			} else {
+				$sbuf .= $string;
+				$sbuf .= str_repeat(' ', $fi->min - $len);
+			}
+		}
+		
+		// No action needed
+		else {
+			$sbuf .= $string;
+		}
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterClass.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterClass.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterClass.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterClass.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the fully qualified class name of the class from which the logging 
+ * request was issued.
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterClass extends LoggerPatternConverter {
+
+	public function convert(LoggerLoggingEvent $event) {
+		return $event->getLocationInformation()->getClassName();
+	}
+}
+ 
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterCookie.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterCookie.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterCookie.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterCookie.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns a value from the $_COOKIE superglobal array corresponding to the 
+ * given key. If no key is given, return all values.
+ * 
+ * Options:
+ *  [0] $_COOKIE key value
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterCookie extends LoggerPatternConverterSuperglobal {
+	protected $name = '_COOKIE';
+}
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterDate.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterDate.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterDate.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterDate.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the date/time of the logging request.
+ * 
+ * Option: the datetime format, as used by the date() function. If 
+ * the option is not given, the default format 'c' will be used.
+ * 
+ * There are several "special" values which can be given for this option:
+ * 'ISO8601', 'ABSOLUTE' and 'DATE'.
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterDate extends LoggerPatternConverter {
+
+	const DATE_FORMAT_ISO8601 = 'c';
+	
+	const DATE_FORMAT_ABSOLUTE = 'H:i:s';
+	
+	const DATE_FORMAT_DATE = 'd M Y H:i:s.u';
+	
+	private $format = self::DATE_FORMAT_ISO8601;
+	
+	private $specials = array(
+		'ISO8601' => self::DATE_FORMAT_ISO8601,
+		'ABSOLUTE' => self::DATE_FORMAT_ABSOLUTE,
+		'DATE' => self::DATE_FORMAT_DATE,
+	);
+	
+	private $useLocalDate = false;
+	
+	public function activateOptions() {
+		
+		// Parse the option (date format)
+		if (isset($this->option)) {
+			if(isset($this->specials[$this->option])) {
+				$this->format = $this->specials[$this->option];
+			} else {
+				$this->format = $this->option;
+			}
+		}
+		
+		// Check whether the pattern contains milliseconds (u)
+		if (preg_match('/(?<!\\\\)u/', $this->format)) {
+			$this->useLocalDate = true;
+		}
+	}
+	
+	public function convert(LoggerLoggingEvent $event) {
+		if ($this->useLocalDate) {
+			return $this->date($this->format, $event->getTimeStamp());
+		}
+		return date($this->format, $event->getTimeStamp());
+	}
+	
+	/**
+	 * Currently, PHP date() function always returns zeros for milliseconds (u)
+	 * on Windows. This is a replacement function for date() which correctly 
+	 * displays milliseconds on all platforms. 
+	 * 
+	 * It is slower than PHP date() so it should only be used if necessary. 
+	 */
+	private function date($format, $utimestamp) {
+		$timestamp = floor($utimestamp);
+		$ms = floor(($utimestamp - $timestamp) * 1000);
+		$ms = str_pad($ms, 3, '0', STR_PAD_LEFT);
+	
+		return date(preg_replace('`(?<!\\\\)u`', $ms, $format), $timestamp);
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterEnvironment.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterEnvironment.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterEnvironment.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterEnvironment.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns a value from the $_ENV superglobal array corresponding to the 
+ * given key.
+ * 
+ * Options:
+ *  [0] $_ENV key value
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterEnvironment extends LoggerPatternConverterSuperglobal {
+	protected $name = '_ENV';
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterFile.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterFile.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterFile.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterFile.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the name of the file from which the logging request was issued. 
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterFile extends LoggerPatternConverter {
+
+	public function convert(LoggerLoggingEvent $event) {
+		return $event->getLocationInformation()->getFileName();
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLevel.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLevel.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLevel.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLevel.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the event's level.
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterLevel extends LoggerPatternConverter {
+
+	public function convert(LoggerLoggingEvent $event) {
+		return $event->getLevel()->toString();
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLine.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLine.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLine.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLine.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the line number within the file from which the logging request was 
+ * issued. 
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterLine extends LoggerPatternConverter {
+
+	public function convert(LoggerLoggingEvent $event) {
+		return $event->getLocationInformation()->getLineNumber();
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLiteral.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLiteral.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLiteral.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLiteral.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the literal value passed in the constructor, without modifications.
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterLiteral extends LoggerPatternConverter {
+
+	private $literalValue;
+	
+	public function __construct($literalValue) {
+		$this->literalValue = $literalValue;
+	}
+	
+	public function convert(LoggerLoggingEvent $event) {
+		return $this->literalValue;
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLocation.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLocation.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLocation.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLocation.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the line number within the file from which the logging request was 
+ * issued. 
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterLine extends LoggerPatternConverter {
+
+	public function convert(LoggerLoggingEvent $event) {
+		return 
+			$event->getLocationInformation()->getClassName() . '.' .
+			$event->getLocationInformation()->getMethodName() . '(' .
+			$event->getLocationInformation()->getFileName() . ':' .
+			$event->getLocationInformation()->getLineNumber() . ')';
+	}
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLogger.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLogger.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLogger.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterLogger.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the name of the logger which created the logging request.
+ * 
+ * Takes one option, which is an integer. If the option is given, the logger 
+ * name will be shortened to the given length, if possible.
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterLogger extends LoggerPatternConverter {
+
+	/** Length to which to shorten the name. */
+	private $length;
+	
+	/** Holds processed logger names. */
+	private $cache = array();
+	
+	public function activateOptions() {
+		// Parse the option (desired output length)
+		if (isset($this->option) && is_numeric($this->option) && $this->option >= 0) {
+			$this->length = (integer) $this->option;
+		}
+	}
+	
+	public function convert(LoggerLoggingEvent $event) {
+		$name = $event->getLoggerName();
+		
+		if (!isset($this->cache[$name])) {
+
+			// If length is set return shortened logger name 
+			if (isset($this->length)) {
+				$this->cache[$name] = $this->shorten($name, $this->length);
+			} 
+			 
+			// If no length is specified return full logger name
+			else {
+				$this->cache[$name] = $name;
+			}
+		} 
+		
+		return $this->cache[$name];
+	}
+	
+	/** 
+	 * Attempts to shorten the given name to the desired length by trimming 
+	 * name fragments. See docs for examples.
+	 */
+	private function shorten($name, $length) {
+	
+		$currentLength = strlen($name);
+	
+		// Check if any shortening is required
+		if ($currentLength <= $length) {
+			return $name;
+		}
+	
+		// Split name into fragments
+		$name = str_replace('.', '\\', $name);
+		$name = trim($name, ' \\');
+		$fragments = explode('\\', $name);
+		$count = count($fragments);
+	
+		// If the name splits to only one fragment, then it cannot be shortened
+		if ($count == 1) {
+			return $name;
+		}
+		
+		foreach($fragments as $key => &$fragment) {
+	
+			// Never shorten last fragment
+			if ($key == $count - 1) {
+				break;
+			}
+	
+			// Check for empty fragments (shouldn't happen but it's possible)
+			$fragLen = strlen($fragment);
+			if ($fragLen <= 1) {
+				continue;
+			}
+	
+			// Shorten fragment to one character and check if total length satisfactory
+			$fragment = substr($fragment, 0, 1);
+			$currentLength = $currentLength - $fragLen + 1;
+	
+			if ($currentLength <= $length) {
+				break;
+			}
+		}
+		unset($fragment);
+	
+		return implode('\\', $fragments);
+	}
+	
+}

Added: logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMDC.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMDC.php?rev=1294503&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMDC.php (added)
+++ logging/log4php/trunk/src/main/php/pattern/LoggerPatternConverterMDC.php Tue Feb 28 07:49:21 2012
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *	   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @package log4php
+ */
+
+/**
+ * Returns the Mapped Diagnostic Context value corresponding to the given key.
+ * 
+ * Options:
+ *  [0] the MDC key
+ * 
+ * @package log4php
+ * @subpackage pattern
+ */
+class LoggerPatternConverterMDC extends LoggerPatternConverter {
+
+	private $key;
+
+	public function activateOptions() {
+		if (isset($this->option) && $this->option !== '') {
+			$this->key = $this->option;
+		}
+	}
+	
+	public function convert(LoggerLoggingEvent $event) {
+		if (isset($this->key)) {
+			return $event->getMDC($this->key);
+		} else {
+			$buff = array();
+			$map = $event->getMDCMap();
+			foreach($map as $key => $value) {
+				$buff []= "$key=$value";
+			}
+			return implode(', ', $buff);
+		}
+	}
+}
+ 
\ No newline at end of file