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 2011/12/10 12:23:51 UTC

svn commit: r1212773 - in /logging/log4php/trunk/src: changes/changes.xml main/php/LoggerLoggingEvent.php main/php/LoggerMDC.php main/php/layouts/LoggerLayoutXml.php test/php/LoggerMDCTest.php test/php/layouts/LoggerLayoutXmlTest.php

Author: ihabunek
Date: Sat Dec 10 11:23:50 2011
New Revision: 1212773

URL: http://svn.apache.org/viewvc?rev=1212773&view=rev
Log:
LOG4PHP-165: Extended LoggerLayoutXml to include MDC info

Modified:
    logging/log4php/trunk/src/changes/changes.xml
    logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php
    logging/log4php/trunk/src/main/php/LoggerMDC.php
    logging/log4php/trunk/src/main/php/layouts/LoggerLayoutXml.php
    logging/log4php/trunk/src/test/php/LoggerMDCTest.php
    logging/log4php/trunk/src/test/php/layouts/LoggerLayoutXmlTest.php

Modified: logging/log4php/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/changes/changes.xml?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/changes/changes.xml (original)
+++ logging/log4php/trunk/src/changes/changes.xml Sat Dec 10 11:23:50 2011
@@ -21,6 +21,7 @@
 	</properties>
 	<body>
 	    <release version="2.2.0" date="SVN">
+	    	<action date="2011-12-10" type="update" issue="LOG4PHP-165" dev="Ivan Habunek" due-to="Johannes Wohlgemuth" due-to-email="j dot wohlgemuth at findologic dot com">Extended LoggerLayoutXml to include MDC info</action>
 	    	<action date="2011-12-09" type="fix" issue="LOG4PHP-162" dev="Ivan Habunek">Warning for invalid appender threshold level never called.</action>
 	    	<action date="2011-12-08" type="fix" issue="LOG4PHP-114" dev="Ivan Habunek">Order of params in LoggerAppenderDailyFile configuration is significant.</action>
 	    	<action date="2011-12-08" type="update" issue="LOG4PHP-154" dev="Ivan Habunek">Rewritten LoggerAppenderSocket to use a layout.</action>

Modified: logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerLoggingEvent.php Sat Dec 10 11:23:50 2011
@@ -272,6 +272,14 @@ class LoggerLoggingEvent {
 	public function getMDC($key) {
 		return LoggerMDC::get($key);
 	}
+	
+	/**
+	 * Returns the entire MDC context.
+	 * @return array
+	 */
+	public function getMDCMap () {
+		return LoggerMDC::getMap();
+	}
 
 	/**
 	 * Render message.

Modified: logging/log4php/trunk/src/main/php/LoggerMDC.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerMDC.php?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerMDC.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerMDC.php Sat Dec 10 11:23:50 2011
@@ -21,17 +21,15 @@
 /**
  * The LoggerMDC class provides <i>mapped diagnostic contexts</i>.
  * 
- * <p>A <i>Mapped Diagnostic Context</i>, or
+ * A <i>Mapped Diagnostic Context</i>, or
  * MDC in short, is an instrument for distinguishing interleaved log
  * output from different sources. Log output is typically interleaved
  * when a server handles multiple clients near-simultaneously.
  * 
- * <p>This class is similar to the {@link LoggerNDC} class except that 
+ * This class is similar to the {@link LoggerNDC} class except that 
  * it is based on a map instead of a stack.
  * 
- * <p><b>The MDC is managed on a per thread basis</b>.
- * 
- * <p>Example:
+ * Example:
  * 
  * {@example ../../examples/php/mdc.php 19}<br>
  *
@@ -51,19 +49,12 @@
  */
 class LoggerMDC {
 	
-	/**
-	 * This is the repository of user mappings
-	 */
+	/** Holds the context map. */
 	private static $map = array();
 		
 	/**
-	 * Put a context value as identified with the key parameter into the current thread's
-	 *	context map.
-	 *
-	 * <p>If the current thread does not have a context map it is
-	 *	created as a side effect.</p>
-	 *
-	 * <p>Note that you cannot put more than {@link self::HT_SIZE} keys.</p>
+	 * Stores a context value as identified with the key parameter into the 
+	 * context map.
 	 *
 	 * @param string $key the key
 	 * @param string $value the value
@@ -73,17 +64,15 @@ class LoggerMDC {
 	}
   
 	/**
-	 * Get the context identified by the key parameter.
-	 *
-	 * <p>You can use special key identifiers to map values in 
-	 * PHP $_SERVER and $_ENV vars. Just put a 'server.' or 'env.'
-	 * followed by the var name you want to refer.</p>
+	 * Returns the context value identified by the key parameter.
 	 *
-	 * <p>This method has no side effects.</p>
-	 *
-	 * @param string $key the key
-	 * @return string the context or an empty string if no context found
-	 * 	for given key
+	 * Special key identifiers can be used to map values in the global $_SERVER
+	 * and $_ENV vars. To access them, use 'server.' or 'env.' followed by the 
+	 * desired var name as the key.
+	 *
+	 * @param string $key The key.
+	 * @return string The context or an empty string if no context found
+	 * 	for given key.
 	 */
 	public static function get($key) {
 		if(!empty($key)) {
@@ -102,13 +91,28 @@ class LoggerMDC {
 	}
 
 	/**
-	 * Remove the the context identified by the key parameter. 
+	 * Returns the contex map as an array.
+	 * @return array The MDC context map.
+	 */
+	public static function getMap() {
+		return self::$map;
+	}
+
+	/**
+	 * Removes the the context identified by the key parameter. 
 	 *
-	 * It only affects user mappings, not $_ENV or $_SERVER.
+	 * Only affects user mappings, not $_ENV or $_SERVER.
 	 *
-	 * @param string $key the key to be removed
+	 * @param string $key The key to be removed.
 	 */
 	public static function remove($key) {
 		unset(self::$map[$key]);
 	}
+	
+	/**
+	 * Clears the mapped diagnostic context.
+	 */
+	public static function clear() {
+		self::$map = array();
+	}
 }

Modified: logging/log4php/trunk/src/main/php/layouts/LoggerLayoutXml.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/layouts/LoggerLayoutXml.php?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/layouts/LoggerLayoutXml.php (original)
+++ logging/log4php/trunk/src/main/php/layouts/LoggerLayoutXml.php Sat Dec 10 11:23:50 2011
@@ -63,43 +63,35 @@ class LoggerLayoutXml extends LoggerLayo
 	const CDATA_START = '<![CDATA[';
 	const CDATA_END = ']]>';
 	const CDATA_PSEUDO_END = ']]&gt;';
-
 	const CDATA_EMBEDDED_END = ']]>]]&gt;<![CDATA[';
 
 	/**
 	 * If set to true then the file name and line number of the origin of the
 	 * log statement will be output.
-	 * 
 	 * @var boolean
 	 */
 	private $locationInfo = true;
   
 	/**
-	 * @var boolean set the elements namespace
+	 * If set to true, log4j namespace will be used instead of the log4php 
+	 * namespace.
+	 * @var boolean 
 	 */
 	private $log4jNamespace = false;
 	
+	/** The namespace in use. */
+	private $namespace = self::LOG4PHP_NS;
 	
-	/**
-	 * @var string namespace
-	 */
-	private $_namespace = self::LOG4PHP_NS;
-	
-	/**
-	 * @var string namespace prefix
-	 */
-	private $_namespacePrefix = self::LOG4PHP_NS_PREFIX;
+	/** The namespace prefix in use */
+	private $namespacePrefix = self::LOG4PHP_NS_PREFIX;
 	 
-	/** 
-	 * No options to activate. 
-	 */
 	public function activateOptions() {
 		if ($this->getLog4jNamespace()) {
-			$this->_namespace        = self::LOG4J_NS;
-			$this->_namespacePrefix  = self::LOG4J_NS_PREFIX;
+			$this->namespace        = self::LOG4J_NS;
+			$this->namespacePrefix  = self::LOG4J_NS_PREFIX;
 		} else {
-			$this->_namespace        = self::LOG4PHP_NS;
-			$this->_namespacePrefix  = self::LOG4PHP_NS_PREFIX;
+			$this->namespace        = self::LOG4PHP_NS;
+			$this->namespacePrefix  = self::LOG4PHP_NS_PREFIX;
 		}
 	}
 	
@@ -107,11 +99,11 @@ class LoggerLayoutXml extends LoggerLayo
 	 * @return string
 	 */
 	public function getHeader() {
-		return "<{$this->_namespacePrefix}:eventSet ".
-					"xmlns:{$this->_namespacePrefix}=\"{$this->_namespace}\" ".
-					"version=\"0.3\" ".
-					"includesLocationInfo=\"".($this->getLocationInfo() ? "true" : "false")."\"".
-					">\r\n";
+		return "<{$this->namespacePrefix}:eventSet ".
+			"xmlns:{$this->namespacePrefix}=\"{$this->namespace}\" ".
+			"version=\"0.3\" ".
+			"includesLocationInfo=\"".($this->getLocationInfo() ? "true" : "false")."\"".
+			">" . PHP_EOL;
 	}
 
 	/**
@@ -121,51 +113,59 @@ class LoggerLayoutXml extends LoggerLayo
 	 * @return string
 	 */
 	public function format(LoggerLoggingEvent $event) {
+		$ns = $this->namespacePrefix;
+		
 		$loggerName = $event->getLoggerName();
-		$timeStamp  = number_format((float)($event->getTimeStamp() * 1000), 0, '', '');
-		$thread     = $event->getThreadName();
-		$level      = $event->getLevel();
-		$levelStr   = $level->toString();
-
-		$buf = "<{$this->_namespacePrefix}:event logger=\"{$loggerName}\" level=\"{$levelStr}\" thread=\"{$thread}\" timestamp=\"{$timeStamp}\">".PHP_EOL;
-		$buf .= "<{$this->_namespacePrefix}:message><![CDATA["; 
-		$this->appendEscapingCDATA($buf, $event->getRenderedMessage()); 
-		$buf .= "]]></{$this->_namespacePrefix}:message>".PHP_EOL;
+		$timeStamp = number_format((float)($event->getTimeStamp() * 1000), 0, '', '');
+		$thread = $event->getThreadName();
+		$level = $event->getLevel()->toString();
+
+		$buf  = "<$ns:event logger=\"{$loggerName}\" level=\"{$level}\" thread=\"{$thread}\" timestamp=\"{$timeStamp}\">".PHP_EOL;
+		$buf .= "<$ns:message>"; 
+		$buf .= $this->encodeCDATA($event->getRenderedMessage()); 
+		$buf .= "</$ns:message>".PHP_EOL;
 
 		$ndc = $event->getNDC();
-		if($ndc != null) {
-			$buf .= "<{$this->_namespacePrefix}:NDC><![CDATA[";
-			$this->appendEscapingCDATA($buf, $ndc);
-			$buf .= "]]></{$this->_namespacePrefix}:NDC>".PHP_EOL;
+		if(!empty($ndc)) {
+			$buf .= "<$ns:NDC><![CDATA[";
+			$buf .= $this->encodeCDATA($ndc);
+			$buf .= "]]></$ns:NDC>".PHP_EOL;
+		}
+		
+		$mdcMap = $event->getMDCMap();
+		if (!empty($mdcMap)) {
+			$buf .= "<$ns:properties>".PHP_EOL;
+			foreach ($mdcMap as $name=>$value) {
+				$buf .= "<$ns:data name=\"$name\" value=\"$value\" />".PHP_EOL;
+			}
+			$buf .= "</$ns:properties>".PHP_EOL;
 		}
 
 		if ($this->getLocationInfo()) {
 			$locationInfo = $event->getLocationInformation();
-			$buf .= "<{$this->_namespacePrefix}:locationInfo ". 
+			$buf .= "<$ns:locationInfo ". 
 					"class=\"" . $locationInfo->getClassName() . "\" ".
 					"file=\"" .  htmlentities($locationInfo->getFileName(), ENT_QUOTES) . "\" ".
 					"line=\"" .  $locationInfo->getLineNumber() . "\" ".
 					"method=\"" . $locationInfo->getMethodName() . "\" ";
 			$buf .= "/>".PHP_EOL;
-
 		}
 
-		$buf .= "</{$this->_namespacePrefix}:event>".PHP_EOL.PHP_EOL;
+		$buf .= "</$ns:event>".PHP_EOL;
 		
 		return $buf;
-
 	}
 	
 	/**
 	 * @return string
 	 */
 	public function getFooter() {
-		return "</{$this->_namespacePrefix}:eventSet>\r\n";
+		return "</{$this->namespacePrefix}:eventSet>" . PHP_EOL;
 	}
 	
 	
-	/** Whether or not file name and line number will be included in the output.
-	 * 
+	/** 
+	 * Whether or not file name and line number will be included in the output.
 	 * @return boolean
 	 */
 	public function getLocationInfo() {
@@ -197,28 +197,14 @@ class LoggerLayoutXml extends LoggerLayo
 		$this->log4jNamespace = LoggerOptionConverter::toBoolean($flag, true);
 	}
 	
-	/**
-	 * Ensures that embeded CDEnd strings (]]&gt;) are handled properly
-	 * within message, NDC and throwable tag text.
-	 *
-	 * @param string $buf	String holding the XML data to this point.	The
-	 *						initial CDStart (<![CDATA[) and final CDEnd (]]>) 
-	 *						of the CDATA section are the responsibility of 
-	 *						the calling method.
-	 * @param string str	The String that is inserted into an existing 
-	 *						CDATA Section within buf.
-	 */
-	private function appendEscapingCDATA(&$buf, $str) {
-		if(empty($str)) {
-			return;
-		}
-	
-		$rStr = str_replace(
-			self::CDATA_END,
-			self::CDATA_EMBEDDED_END,
-			$str
-		);
-		$buf .= $rStr;
+	/** 
+	 * Encases a string in CDATA tags, and escapes any existing CDATA end 
+	 * tags already present in the string.
+	 * @param string $string 
+	 */
+	private function encodeCDATA($string) {
+		$string = str_replace(self::CDATA_END, self::CDATA_EMBEDDED_END, $string);
+		return self::CDATA_START . $string . self::CDATA_END;
 	}
 }
 

Modified: logging/log4php/trunk/src/test/php/LoggerMDCTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerMDCTest.php?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/LoggerMDCTest.php (original)
+++ logging/log4php/trunk/src/test/php/LoggerMDCTest.php Sat Dec 10 11:23:50 2011
@@ -52,7 +52,14 @@ class LoggerMDCTest extends PHPUnit_Fram
 	 */
 	private $patternServer = "%-5p %c: %X{server.PHP_SELF} %m";
 	
-
+	protected function setUp() {
+		LoggerMDC::clear();
+	}
+	
+	protected function tearDown() {
+		LoggerMDC::clear();
+	}
+	
 	public function testPatterns() {
 
 		// Create some data to test with
@@ -60,6 +67,15 @@ class LoggerMDCTest extends PHPUnit_Fram
 		LoggerMDC::put('key2', 'valueofkey2');
 		LoggerMDC::put(3, 'valueofkey3');
 		
+		$expected = array(
+			'key1' => 'valueofkey1',
+			'key2' => 'valueofkey2',
+			3 => 'valueofkey3',
+		);
+		$actual = LoggerMDC::getMap();
+		
+		self::assertSame($expected, $actual);
+		
 		$event = new LoggerLoggingEvent("LoggerLayoutPattern", new Logger("TEST"), LoggerLevel::getLevelInfo(), "Test message");
 
 		// Pattern with 1 key

Modified: logging/log4php/trunk/src/test/php/layouts/LoggerLayoutXmlTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/layouts/LoggerLayoutXmlTest.php?rev=1212773&r1=1212772&r2=1212773&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/layouts/LoggerLayoutXmlTest.php (original)
+++ logging/log4php/trunk/src/test/php/layouts/LoggerLayoutXmlTest.php Sat Dec 10 11:23:50 2011
@@ -19,7 +19,7 @@
  * @package    log4php
  * @subpackage appenders
  * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
- * @version    SVN: $Id$
+ * @version    $Revision$
  * @link       http://logging.apache.org/log4php
  */
 
@@ -27,55 +27,122 @@
  * @group layouts
  */
 class LoggerLayoutXmlTest extends PHPUnit_Framework_TestCase {
-        
+		
 	public function testErrorLayout() {
-		$event = new LoggerLoggingEvent("LoggerLayoutXml", new Logger("TEST"), LoggerLevel::getLevelError(), "testmessage");
+		$event = LoggerTestHelper::getErrorEvent("testmessage");
 
 		$layout = new LoggerLayoutXml();
-		$v = $layout->format($event);
+		$layout->activateOptions();
+		
+		$actual = $layout->format($event);
 
-		$e = "<log4php:event logger=\"TEST\" level=\"ERROR\" thread=\"".$event->getThreadName().
-			"\" timestamp=\"".number_format((float)($event->getTimeStamp() * 1000), 0, '', '')."\">".PHP_EOL.
-			"<log4php:message><![CDATA[testmessage]]></log4php:message>".PHP_EOL.
-			"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" " .
-			"method=\"getLocationInformation\" />".PHP_EOL.
-			"</log4php:event>".PHP_EOL . PHP_EOL;
-
-		self::assertEquals($v, $e);
-    }
-    
-    public function testWarnLayout() {
-		$event = new LoggerLoggingEvent("LoggerLayoutXml", new Logger("TEST"), LoggerLevel::getLevelWarn(), "testmessage");
+		$thread = $event->getThreadName();
+		$timestamp = number_format(($event->getTimeStamp() * 1000), 0, '', '');
+		
+		$expected = "<log4php:event logger=\"test\" level=\"ERROR\" thread=\"$thread\" timestamp=\"$timestamp\">" . PHP_EOL . 
+			"<log4php:message><![CDATA[testmessage]]></log4php:message>" . PHP_EOL . 
+			"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" " . 
+			"method=\"getLocationInformation\" />" . PHP_EOL . 
+			"</log4php:event>" . PHP_EOL;
+
+		self::assertEquals($expected, $actual);
+	}
+	
+	public function testWarnLayout() {
+		$event = LoggerTestHelper::getWarnEvent("testmessage");
 
 		$layout = new LoggerLayoutXml();
-		$v = $layout->format($event);
+		$layout->activateOptions();
+		
+		$actual = $layout->format($event);
 
-		$e = "<log4php:event logger=\"TEST\" level=\"WARN\" thread=\"".$event->getThreadName().
-			"\" timestamp=\"".number_format((float)($event->getTimeStamp() * 1000), 0, '', '')."\">".PHP_EOL.
-			"<log4php:message><![CDATA[testmessage]]></log4php:message>".PHP_EOL.
-			"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" " .
-			"method=\"getLocationInformation\" />".PHP_EOL.
-			"</log4php:event>".PHP_EOL . PHP_EOL;
-		
-		self::assertEquals($v, $e);
-    }
-    
-    public function testLog4JNamespaceErrorLayout() {
-		$event = new LoggerLoggingEvent("LoggerLayoutXml", new Logger("TEST"), LoggerLevel::getLevelError(), "testmessage");
+		$thread = $event->getThreadName();
+		$timestamp = number_format(($event->getTimeStamp() * 1000), 0, '', '');
+		
+		$expected = "<log4php:event logger=\"test\" level=\"WARN\" thread=\"$thread\" timestamp=\"$timestamp\">" . PHP_EOL . 
+			"<log4php:message><![CDATA[testmessage]]></log4php:message>" . PHP_EOL . 
+			"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" "  . 
+			"method=\"getLocationInformation\" />" . PHP_EOL . 
+			"</log4php:event>" . PHP_EOL;
+		
+		self::assertEquals($expected, $actual);
+	}
+	
+	public function testLog4JNamespaceErrorLayout() {
+		$event = LoggerTestHelper::getErrorEvent("testmessage");
 
 		$layout = new LoggerLayoutXml();
 		$layout->setLog4jNamespace(true);
 		$layout->activateOptions();
 		
-		$v = $layout->format($event);
+		$actual = $layout->format($event);
 
-		$e = "<log4j:event logger=\"TEST\" level=\"ERROR\" thread=\"".$event->getThreadName().
-			"\" timestamp=\"".number_format((float)($event->getTimeStamp() * 1000), 0, '', '')."\">".PHP_EOL.
-			"<log4j:message><![CDATA[testmessage]]></log4j:message>".PHP_EOL.
-			"<log4j:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" " .
-			"method=\"getLocationInformation\" />".PHP_EOL.
-			"</log4j:event>".PHP_EOL . PHP_EOL;
+		$thread = $event->getThreadName();
+		$timestamp = number_format(($event->getTimeStamp() * 1000), 0, '', '');
+		
+		$expected = "<log4j:event logger=\"test\" level=\"ERROR\" thread=\"$thread\" timestamp=\"$timestamp\">" . PHP_EOL . 
+			"<log4j:message><![CDATA[testmessage]]></log4j:message>" . PHP_EOL . 
+			"<log4j:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" "  . 
+			"method=\"getLocationInformation\" />" . PHP_EOL . 
+			"</log4j:event>" . PHP_EOL;
+
+		self::assertEquals($expected, $actual);
+	}
+	
+	public function testNDC()
+	{
+		LoggerNDC::push('foo');
+		LoggerNDC::push('bar');
+		
+		$event = LoggerTestHelper::getErrorEvent("testmessage");
+		
+		$layout = new LoggerLayoutXml();
+		$layout->activateOptions();
+		
+		$actual = $layout->format($event);
 
-		self::assertEquals($v, $e);
-    }
+		$thread = $event->getThreadName();
+		$timestamp = number_format(($event->getTimeStamp() * 1000), 0, '', '');
+		
+		$expected = "<log4php:event logger=\"test\" level=\"ERROR\" thread=\"$thread\" timestamp=\"$timestamp\">" . PHP_EOL . 
+			"<log4php:message><![CDATA[testmessage]]></log4php:message>" . PHP_EOL . 
+			"<log4php:NDC><![CDATA[<![CDATA[foo bar]]>]]></log4php:NDC>"  .  PHP_EOL  . 
+			"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" "  . 
+			"method=\"getLocationInformation\" />" . PHP_EOL . 
+			"</log4php:event>" . PHP_EOL;
+		
+		self::assertEquals($expected, $actual);
+		
+		LoggerNDC::clear();
+	}
+	
+	public function testMDC()
+	{
+		LoggerMDC::put('foo', 'bar');
+		LoggerMDC::put('bla', 'tra');
+	
+		$event = LoggerTestHelper::getErrorEvent("testmessage");
+	
+		$layout = new LoggerLayoutXml();
+		$layout->activateOptions();
+	
+		$actual = $layout->format($event);
+	
+		$thread = $event->getThreadName();
+		$timestamp = number_format(($event->getTimeStamp() * 1000), 0, '', '');
+		
+		$expected = "<log4php:event logger=\"test\" level=\"ERROR\" thread=\"$thread\" timestamp=\"$timestamp\">" . PHP_EOL .
+				"<log4php:message><![CDATA[testmessage]]></log4php:message>" . PHP_EOL . 
+				"<log4php:properties>" . PHP_EOL . 
+				"<log4php:data name=\"foo\" value=\"bar\" />" . PHP_EOL . 
+				"<log4php:data name=\"bla\" value=\"tra\" />" . PHP_EOL . 
+				"</log4php:properties>" . PHP_EOL . 
+				"<log4php:locationInfo class=\"LoggerLoggingEvent\" file=\"NA\" line=\"NA\" "  . 
+				"method=\"getLocationInformation\" />" . PHP_EOL . 
+				"</log4php:event>" . PHP_EOL;
+	
+		self::assertEquals($expected, $actual);
+	
+		LoggerMDC::clear();
+	}
 }