You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-dev@logging.apache.org by ni...@apache.org on 2005/08/24 15:26:38 UTC

cvs commit: logging-log4net/tests/src/Layout XmlLayoutTest.cs

niall       2005/08/24 06:26:38

  Modified:    src/Layout XMLLayout.cs XMLLayoutBase.cs
                        XmlLayoutSchemaLog4j.cs
               src/Util Transform.cs
               tests/src log4net.Tests.csproj
  Added:       tests/src/Layout XmlLayoutTest.cs
  Log:
  Fixes for LOG4NET-22 and LOG4NET-44 with associated tests.
  
  Characters that cannot be expressed in XML are now masked with a user specifiable charater.
  The message and property values may be base64 encoded if this is undesirable.
  
  The name of the properties node has been fixed to properties rather than global-properties.
  
  Revision  Changes    Path
  1.11      +66 -7     logging-log4net/src/Layout/XMLLayout.cs
  
  Index: XMLLayout.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Layout/XMLLayout.cs,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- XMLLayout.cs	17 Jan 2005 20:18:45 -0000	1.10
  +++ XMLLayout.cs	24 Aug 2005 13:26:37 -0000	1.11
  @@ -121,6 +121,46 @@
   			set { m_prefix = value; }
   		}
   
  +		
  +		/// <summary>
  +		/// Set whether or not to base64 encode the message.
  +		/// </summary>
  +		/// <remarks>
  +		/// <para>
  +		/// By default the log message will be written as text to the xml
  +		/// output. This can cause problems when the message contains binary
  +		/// data. By setting this to true the contents of the message will be
  +		/// base64 encoded. If this is set then invalid character replacement
  +		/// (see <see cref="InvalidCharReplacement"/>) will not be performed
  +		/// on the log message.
  +		/// </para>
  +		/// </remarks>
  +		public bool Base64EncodeMessage
  +		{
  +			get {return m_base64Message;}
  +			set {m_base64Message=value;}
  +		}
  +
  +		/// <summary>
  +		/// Set whether or not to base64 encode the property values.
  +		/// </summary>
  +		/// <remarks>
  +		/// <para>
  +		/// By default the properties will be written as text to the xml
  +		/// output. This can cause problems when one or more properties contain
  +		/// binary data. By setting this to true the values of the properties
  +		/// will be base64 encoded. If this is set then invalid character replacement
  +		/// (see <see cref="InvalidCharReplacement"/>) will not be performed
  +		/// on the property values.
  +		/// </para>
  +		/// </remarks>
  +		public bool Base64EncodeProperties
  +		{
  +			get {return m_base64Properties;}
  +			set {m_base64Properties=value;}
  +		}
  +
  +
   		#endregion Public Instance Properties
   
   		#region Implementation of IOptionHandler
  @@ -154,7 +194,6 @@
   				m_elmEvent = m_prefix + ":" + ELM_EVENT;
   				m_elmMessage = m_prefix + ":" + ELM_MESSAGE;
   				m_elmProperties = m_prefix + ":" + ELM_PROPERTIES;
  -				m_elmGlobalProperties = m_prefix + ":" + ELM_GLOBAL_PROPERTIES;
   				m_elmData = m_prefix + ":" + ELM_DATA;
   				m_elmException = m_prefix + ":" + ELM_EXCEPTION;
   				m_elmLocation = m_prefix + ":" + ELM_LOCATION;
  @@ -199,7 +238,16 @@
       
   			// Append the message text
   			writer.WriteStartElement(m_elmMessage);
  -			Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage);
  +			if (!this.Base64EncodeMessage)
  +			{
  +				string message=loggingEvent.RenderedMessage;
  +				
  +				Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage,this.InvalidCharReplacement);
  +			}
  +			else
  +			{
  +				Transform.WriteEscapedXmlString(writer, Convert.ToBase64String(Encoding.UTF8.GetBytes(loggingEvent.RenderedMessage)),this.InvalidCharReplacement);
  +			}
   			writer.WriteEndElement();
   
   			PropertiesDictionary properties = loggingEvent.GetProperties();
  @@ -207,14 +255,22 @@
   			// Append the properties text
   			if (properties.Count > 0)
   			{
  -				writer.WriteStartElement(m_elmGlobalProperties);
  +				writer.WriteStartElement(m_elmProperties);
   				foreach(System.Collections.DictionaryEntry entry in properties)
   				{
   					writer.WriteStartElement(m_elmData);
  -					writer.WriteAttributeString(ATTR_NAME, (string)entry.Key);
  +					writer.WriteAttributeString(ATTR_NAME, Transform.MaskXMLInvalidCharacters((string)entry.Key,this.InvalidCharReplacement));
   
   					// Use an ObjectRenderer to convert the object to a string
  -					string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(entry.Value);
  +					string valueStr =null;
  +					if (!this.Base64EncodeProperties)
  +					{
  +						valueStr=Transform.MaskXMLInvalidCharacters(loggingEvent.Repository.RendererMap.FindAndRender(entry.Value),this.InvalidCharReplacement);
  +					}
  +					else
  +					{
  +						valueStr=Convert.ToBase64String(Encoding.UTF8.GetBytes(loggingEvent.Repository.RendererMap.FindAndRender(entry.Value)));
  +					}
   					writer.WriteAttributeString(ATTR_VALUE, valueStr);
   
   					writer.WriteEndElement();
  @@ -227,7 +283,7 @@
   			{
   				// Append the stack trace line
   				writer.WriteStartElement(m_elmException);
  -				Transform.WriteEscapedXmlString(writer, exceptionStr);
  +				Transform.WriteEscapedXmlString(writer, exceptionStr,this.InvalidCharReplacement);
   				writer.WriteEndElement();
   			}
   
  @@ -259,10 +315,12 @@
   		private string m_elmMessage = ELM_MESSAGE;
   		private string m_elmData = ELM_DATA;
   		private string m_elmProperties = ELM_PROPERTIES;
  -		private string m_elmGlobalProperties = ELM_GLOBAL_PROPERTIES;
   		private string m_elmException = ELM_EXCEPTION;
   		private string m_elmLocation = ELM_LOCATION;
   
  +		private bool m_base64Message=false;
  +		private bool m_base64Properties=false;
  +
   		#endregion Private Instance Fields
   
   		#region Private Static Fields
  @@ -291,6 +349,7 @@
   		private const string ATTR_NAME = "name";
   		private const string ATTR_VALUE = "value";
   
  +
   		#endregion Private Static Fields
   	}
   }
  
  
  
  1.7       +23 -1     logging-log4net/src/Layout/XMLLayoutBase.cs
  
  Index: XMLLayoutBase.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Layout/XMLLayoutBase.cs,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- XMLLayoutBase.cs	17 Jan 2005 20:18:45 -0000	1.6
  +++ XMLLayoutBase.cs	24 Aug 2005 13:26:37 -0000	1.7
  @@ -110,7 +110,24 @@
   			get { return m_locationInfo; }
   			set { m_locationInfo = value; }
   		}
  -
  +		/// <summary>
  +		/// The string to replace characters that can not be expressed in XML with.
  +		/// <remarks>
  +		/// <para>
  +		/// Not all characters may be expressed in XML. This property contains the
  +		/// string to replace those that can not with. This defaults to a ?. Set it
  +		/// to the empty string to simply remove offending characters. For more
  +		/// details on the allowed character ranges see http://www.w3.org/TR/REC-xml/#charsets
  +		/// Character replacement will occur in  the log message, the property names 
  +		/// and the property values.
  +		/// </para>
  +		/// </remarks>
  +		/// </summary>
  +		public string InvalidCharReplacement
  +		{
  +			get {return m_invalidCharReplacement;}
  +			set {m_invalidCharReplacement=value;}
  +		}
   		#endregion
   
   		#region Implementation of IOptionHandler
  @@ -231,6 +248,11 @@
   		/// </summary>
   		private readonly ProtectCloseTextWriter m_protectCloseTextWriter = new ProtectCloseTextWriter(null);
   
  +		/// <summary>
  +		/// The string to replace invalid chars with
  +		/// </summary>
  +		private string m_invalidCharReplacement="?";
  +
   		#endregion Private Instance Fields
   	}
   }
  
  
  
  1.12      +3 -3      logging-log4net/src/Layout/XmlLayoutSchemaLog4j.cs
  
  Index: XmlLayoutSchemaLog4j.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Layout/XmlLayoutSchemaLog4j.cs,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- XmlLayoutSchemaLog4j.cs	7 Feb 2005 23:14:37 -0000	1.11
  +++ XmlLayoutSchemaLog4j.cs	24 Aug 2005 13:26:37 -0000	1.12
  @@ -187,7 +187,7 @@
       
   			// Append the message text
   			writer.WriteStartElement("log4j:message");
  -			Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage);
  +			Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage,this.InvalidCharReplacement);
   			writer.WriteEndElement();
   
   			object ndcObj = loggingEvent.LookupProperty("NDC");
  @@ -199,7 +199,7 @@
   				{
   					// Append the NDC text
   					writer.WriteStartElement("log4j:NDC");
  -					Transform.WriteEscapedXmlString(writer, valueStr);
  +					Transform.WriteEscapedXmlString(writer, valueStr,this.InvalidCharReplacement);
   					writer.WriteEndElement();
   				}
   			}
  @@ -228,7 +228,7 @@
   			{
   				// Append the stack trace line
   				writer.WriteStartElement("log4j:throwable");
  -				Transform.WriteEscapedXmlString(writer, exceptionStr);
  +				Transform.WriteEscapedXmlString(writer, exceptionStr,this.InvalidCharReplacement);
   				writer.WriteEndElement();
   			}
   
  
  
  
  1.7       +11 -2     logging-log4net/src/Util/Transform.cs
  
  Index: Transform.cs
  ===================================================================
  RCS file: /home/cvs/logging-log4net/src/Util/Transform.cs,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- Transform.cs	7 Feb 2005 04:05:50 -0000	1.6
  +++ Transform.cs	24 Aug 2005 13:26:37 -0000	1.7
  @@ -19,6 +19,7 @@
   using System;
   using System.Text;
   using System.Xml;
  +using System.Text.RegularExpressions;
   
   namespace log4net.Util
   {
  @@ -56,15 +57,17 @@
   		/// Write a string to an <see cref="XmlWriter"/>
   		/// </summary>
   		/// <param name="writer">the writer to write to</param>
  -		/// <param name="stringData">the string to write</param>
  +		/// <param name="textData">the string to write</param>
  +		/// <param name="invalidCharReplacement">The string to replace non XML compliant chars with</param>
   		/// <remarks>
   		/// <para>
   		/// The test is escaped either using XML escape entities
   		/// or using CDATA sections.
   		/// </para>
   		/// </remarks>
  -		public static void WriteEscapedXmlString(XmlWriter writer, string stringData)
  +		public static void WriteEscapedXmlString(XmlWriter writer, string textData, string invalidCharReplacement)
   		{
  +			string stringData=MaskXMLInvalidCharacters(textData,invalidCharReplacement);
   			// Write either escaped text or CDATA sections
   
   			int weightCData = 12 * (1 + CountSubstrings(stringData, CDATA_END));
  @@ -113,6 +116,11 @@
   			}
   		}
   
  +		public static string MaskXMLInvalidCharacters(string textData,string mask)
  +		{
  +			return INVALIDCHARS.Replace(textData,mask);
  +		}
  +
   		#endregion Public Static Methods
   
   		#region Private Helper Methods
  @@ -166,6 +174,7 @@
   		private const string CDATA_END	= "]]>";
   		private const string CDATA_UNESCAPABLE_TOKEN	= "]]";
   
  +		private static Regex INVALIDCHARS=new Regex(@"[^\x09\x0A\x0D\x20-\xFF\u00FF-\u07FF\uE000-\uFFFD]",RegexOptions.Compiled);
   		#endregion Private Static Fields
   	}
   }
  
  
  
  1.12      +5 -0      logging-log4net/tests/src/log4net.Tests.csproj
  
  Index: log4net.Tests.csproj
  ===================================================================
  RCS file: /home/cvs/logging-log4net/tests/src/log4net.Tests.csproj,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- log4net.Tests.csproj	20 Jun 2005 19:11:53 -0000	1.11
  +++ log4net.Tests.csproj	24 Aug 2005 13:26:37 -0000	1.12
  @@ -158,6 +158,11 @@
                       BuildAction = "Compile"
                   />
                   <File
  +                    RelPath = "Layout\XmlLayoutTest.cs"
  +                    SubType = "Code"
  +                    BuildAction = "Compile"
  +                />
  +                <File
                       RelPath = "Util\CyclicBufferTest.cs"
                       SubType = "Code"
                       BuildAction = "Compile"
  
  
  
  1.1                  logging-log4net/tests/src/Layout/XmlLayoutTest.cs
  
  Index: XmlLayoutTest.cs
  ===================================================================
  #region Copyright & License
  //
  // Copyright 2001-2005 The Apache Software Foundation
  //
  // Licensed 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.
  //
  #endregion
  
  using System;
  using System.IO;
  using System.Diagnostics;
  using System.Globalization;
  
  using log4net.Config;
  using log4net.Util;
  using log4net.Layout;
  using log4net.Core;
  using log4net.Appender;
  using log4net.Repository;
  
  using log4net.Tests.Appender;
  
  using NUnit.Framework;
  
  namespace log4net.Tests.Layout
  {
  	[TestFixture] public class XmlLayoutTest
  	{
  		/// <summary>
  		/// Build a basic <see cref="LoggingEventData"/> object with some default values.
  		/// </summary>
  		/// <returns>A useful LoggingEventData object</returns>
  		private LoggingEventData createBaseEvent()
  		{
  			LoggingEventData ed=new LoggingEventData();
  			ed.Domain="Tests";
  			ed.ExceptionString="";
  			ed.Identity="TestRunner";
  			ed.Level=Level.Info;
  			ed.LocationInfo=new LocationInfo(this.GetType());
  			ed.LoggerName="TestLogger";
  			ed.Message="Test message";
  			ed.ThreadName="TestThread";
  			ed.TimeStamp=new DateTime(2005,8,24,12,0,0);
  			ed.UserName="TestRunner";
  			ed.Properties=new PropertiesDictionary();
  
  			return ed;
  		}
  
  		[Test] public void TestBasicEventLogging()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message></event>\r\n",
  				writer.ToString()
  				);
  		}
  
  		[Test] public void TestIllegalCharacterMasking()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			evt.Message="This is a masked char->\uFFFF";
  
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  									"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>This is a masked char-&gt;?</message></event>\r\n",
  									writer.ToString()
  									);
  		}
  
  		[Test] public void TestCDATAEscaping1()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			//The &'s trigger the use of a cdata block
  			evt.Message="&&&&&&&Escape this ]]>. End here.";
  
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message><![CDATA[&&&&&&&Escape this ]]>]]<![CDATA[>. End here.]]></message></event>\r\n",
  				writer.ToString()
  				);
  		}
  
  		[Test] public void TestCDATAEscaping2()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			//The &'s trigger the use of a cdata block
  			evt.Message="&&&&&&&Escape the end ]]>";
  
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message><![CDATA[&&&&&&&Escape the end ]]>]]&gt;</message></event>\r\n",
  				writer.ToString()
  				);
  		}
  
  		[Test] public void TestCDATAEscaping3()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			//The &'s trigger the use of a cdata block
  			evt.Message="]]>&&&&&&&Escape the begining";
  
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message><![CDATA[]]>]]<![CDATA[>&&&&&&&Escape the begining]]></message></event>\r\n",
  				writer.ToString()
  				);
  		}
  
  		[Test] public void TestBase64EventLogging()
  		{
  			TextWriter writer=new StringWriter();
  			XmlLayout layout=new XmlLayout();
  			LoggingEventData evt=createBaseEvent();
  
  			layout.Base64EncodeMessage=true;
  			layout.Format(writer,new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>VGVzdCBtZXNzYWdl</message></event>\r\n",
  				writer.ToString()
  				);
  		}
  
  		[Test] public void TestPropertyEventLogging()
  		{
  			LoggingEventData evt=createBaseEvent();
  			evt.Properties["Property1"]="prop1";
  
  			XmlLayout layout=new XmlLayout();
  			StringAppender stringAppender = new StringAppender();
  			stringAppender.Layout = layout;
  
  			ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString());
  			BasicConfigurator.Configure(rep, stringAppender);
  			ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern");
  
  			log1.Logger.Log(new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message><properties><data name=\"Property1\" value=\"prop1\" /></properties></event>\r\n",
  				stringAppender.GetString()
  				);
  		}
  
  		[Test] public void TestBase64PropertyEventLogging()
  		{
  			LoggingEventData evt=createBaseEvent();
  			evt.Properties["Property1"]="prop1";
  
  			XmlLayout layout=new XmlLayout();
  			layout.Base64EncodeProperties=true;
  			StringAppender stringAppender = new StringAppender();
  			stringAppender.Layout = layout;
  
  			ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString());
  			BasicConfigurator.Configure(rep, stringAppender);
  			ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern");
  
  			log1.Logger.Log(new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message><properties><data name=\"Property1\" value=\"cHJvcDE=\" /></properties></event>\r\n",
  				stringAppender.GetString()
  				);
  		}
  
  		[Test] public void TestPropertyCharacterEscaping()
  		{
  			LoggingEventData evt=createBaseEvent();
  			evt.Properties["Property1"]="prop1 \"quoted\"";
  
  			XmlLayout layout=new XmlLayout();
  			StringAppender stringAppender = new StringAppender();
  			stringAppender.Layout = layout;
  
  			ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString());
  			BasicConfigurator.Configure(rep, stringAppender);
  			ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern");
  
  			log1.Logger.Log(new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message><properties><data name=\"Property1\" value=\"prop1 &quot;quoted&quot;\" /></properties></event>\r\n",
  				stringAppender.GetString()
  				);
  		}
  
  		[Test] public void TestPropertyIllegalCharacterMasking()
  		{
  			LoggingEventData evt=createBaseEvent();
  			evt.Properties["Property1"]="mask this ->\uFFFF";
  
  			XmlLayout layout=new XmlLayout();
  			StringAppender stringAppender = new StringAppender();
  			stringAppender.Layout = layout;
  
  			ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString());
  			BasicConfigurator.Configure(rep, stringAppender);
  			ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern");
  
  			log1.Logger.Log(new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message><properties><data name=\"Property1\" value=\"mask this -&gt;?\" /></properties></event>\r\n",
  				stringAppender.GetString()
  				);
  		}
  
  		[Test] public void TestPropertyIllegalCharacterMaskingInName()
  		{
  			LoggingEventData evt=createBaseEvent();
  			evt.Properties["Property\uFFFF"]="mask this ->\uFFFF";
  
  			XmlLayout layout=new XmlLayout();
  			StringAppender stringAppender = new StringAppender();
  			stringAppender.Layout = layout;
  
  			ILoggerRepository rep = LogManager.CreateRepository(Guid.NewGuid().ToString());
  			BasicConfigurator.Configure(rep, stringAppender);
  			ILog log1 = LogManager.GetLogger(rep.Name, "TestThreadProperiesPattern");
  
  			log1.Logger.Log(new LoggingEvent(evt));
  			
  			Assertion.AssertEquals	(
  				"<event logger=\"TestLogger\" timestamp=\"2005-08-24T12:00:00.0000000+01:00\" level=\"INFO\" thread=\"TestThread\" domain=\"Tests\" identity=\"TestRunner\" username=\"TestRunner\"><message>Test message</message><properties><data name=\"Property?\" value=\"mask this -&gt;?\" /></properties></event>\r\n",
  				stringAppender.GetString()
  				);
  		}
  	}
  }