You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by bo...@apache.org on 2018/05/29 19:02:42 UTC

logging-log4net git commit: LOG4NET-586 first cut at a namespace aware log4j XML layout

Repository: logging-log4net
Updated Branches:
  refs/heads/feature/LOG4NET-586 aed08e074 -> 48dfe2864


LOG4NET-586 first cut at a namespace aware log4j XML layout


Project: http://git-wip-us.apache.org/repos/asf/logging-log4net/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4net/commit/48dfe286
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4net/tree/48dfe286
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4net/diff/48dfe286

Branch: refs/heads/feature/LOG4NET-586
Commit: 48dfe28642de31ca2087e34cbdb3ffde0ed8362e
Parents: aed08e0
Author: Stefan Bodewig <bo...@apache.org>
Authored: Tue May 29 21:01:59 2018 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Tue May 29 21:01:59 2018 +0200

----------------------------------------------------------------------
 src/Layout/XmlLayoutSchemaLog4jNS.cs | 282 ++++++++++++++++++++++++++++++
 src/log4net.csproj                   |   3 +
 2 files changed, 285 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/48dfe286/src/Layout/XmlLayoutSchemaLog4jNS.cs
----------------------------------------------------------------------
diff --git a/src/Layout/XmlLayoutSchemaLog4jNS.cs b/src/Layout/XmlLayoutSchemaLog4jNS.cs
new file mode 100644
index 0000000..aa7c33b
--- /dev/null
+++ b/src/Layout/XmlLayoutSchemaLog4jNS.cs
@@ -0,0 +1,282 @@
+#region Apache License
+//
+// 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.
+//
+#endregion
+
+using System;
+using System.Text;
+using System.Xml;
+using System.IO;
+
+using log4net.Core;
+using log4net.Util;
+
+namespace log4net.Layout
+{
+	/// <summary>
+	/// Layout that formats the log events as XML elements similar to the log4j 1.2 schema
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Formats the log events according to the
+	/// http://logging.apache.org/log4j schema and actually puts the
+	/// elements into a namespace. This may break tooling that doesn't
+	/// handle XML using namespaces.
+	/// </para>
+	/// </remarks>
+	/// <author>Nicko Cadell</author>
+	public class XmlLayoutSchemaLog4jNS : XmlLayoutBaseNS
+	{
+		#region Static Members
+
+		/// <summary>
+		/// The 1st of January 1970 in UTC
+		/// </summary>
+		private static readonly DateTime s_date1970 = new DateTime(1970, 1, 1);
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs an XMLLayoutSchemaLog4jNS
+		/// </summary>
+		public XmlLayoutSchemaLog4jNS() : base()
+		{
+		}
+
+		/// <summary>
+		/// Constructs an XMLLayoutSchemaLog4jNS.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// The <b>LocationInfo</b> option takes a boolean value. By
+		/// default, it is set to false which means there will be no location
+		/// information output by this layout. If the the option is set to
+		/// true, then the file name and line number of the statement
+		/// at the origin of the log statement will be output.
+		/// </para>
+		/// <para>
+		/// If you are embedding this layout within an SMTPAppender
+		/// then make sure to set the <b>LocationInfo</b> option of that
+		/// appender as well.
+		/// </para>
+		/// </remarks>
+		public XmlLayoutSchemaLog4jNS(bool locationInfo) :  base(locationInfo)
+		{
+		}
+
+		#endregion
+
+		#region Public Properties
+
+		/// <summary>
+		/// The version of the log4j schema to use.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Only version 1.2 of the log4j schema is supported.
+		/// </para>
+		/// </remarks>
+		public string Version
+		{
+			get { return "1.2"; }
+			set
+			{
+				if (value != "1.2")
+				{
+					throw new ArgumentException("Only version 1.2 of the log4j schema is currently supported");
+				}
+			}
+		}
+
+		/// <summary>
+		/// The namespace URI to use for the elements and attributes written by this layout.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Unless configured explicitly http://logging.apache.org/log4j is used.
+		/// </para>
+		/// </remarks>
+		public override string NamespaceUri
+		{
+			get { return base.NamespaceUri == null ? LOG4J_SCHEMA : base.NamespaceUri; }
+		}
+
+		/// <summary>
+		/// The prefix to use for the elements and attributes written by this layout.
+		/// </summary>
+		/// <remarks>
+		/// <para>
+		/// Unless configured explicitly log4j is used.
+		/// </para>
+		/// </remarks>
+		public override string Prefix
+		{
+			get { return base.Prefix == null ? LOG4J_PREFIX : base.Prefix; }
+		}
+		#endregion
+
+		/* Example log4j schema event
+
+<log4j:event logger="first logger" level="ERROR" thread="Thread-3" timestamp="1051494121460" xmlns:log4j="http://logging.apache.org/log4j">
+  <log4j:message><![CDATA[errormsg 3]]></log4j:message>
+  <log4j:NDC><![CDATA[third]]></log4j:NDC>
+  <log4j:MDC>
+	<log4j:data name="some string" value="some valuethird"/>
+  </log4j:MDC>
+  <log4j:throwable><![CDATA[java.lang.Exception: someexception-third
+	at org.apache.log4j.chainsaw.Generator.run(Generator.java:94)
+]]></log4j:throwable>
+  <log4j:locationInfo class="org.apache.log4j.chainsaw.Generator"
+method="run" file="Generator.java" line="94"/>
+  <log4j:properties>
+	<log4j:data name="log4jmachinename" value="windows"/>
+	<log4j:data name="log4japp" value="udp-generator"/>
+  </log4j:properties>
+</log4j:event>
+
+		*/
+
+		/* Since log4j 1.3 the log4j:MDC has been combined into the log4j:properties element */
+
+		/// <summary>
+		/// Actually do the writing of the xml
+		/// </summary>
+		/// <param name="writer">the writer to use</param>
+		/// <param name="loggingEvent">the event to write</param>
+		/// <remarks>
+		/// <para>
+		/// Generate XML that is compatible with the log4j schema.
+		/// </para>
+		/// </remarks>
+		override protected void FormatXml(XmlWriter writer, LoggingEvent loggingEvent)
+		{
+			// Translate logging events for log4j
+
+			// Translate hostname property
+			if (loggingEvent.LookupProperty(LoggingEvent.HostNameProperty) != null &&
+				loggingEvent.LookupProperty("log4jmachinename") == null)
+			{
+				loggingEvent.GetProperties()["log4jmachinename"] = loggingEvent.LookupProperty(LoggingEvent.HostNameProperty);
+			}
+
+			// translate appdomain name
+			if (loggingEvent.LookupProperty("log4japp") == null &&
+				loggingEvent.Domain != null &&
+				loggingEvent.Domain.Length > 0)
+			{
+				loggingEvent.GetProperties()["log4japp"] = loggingEvent.Domain;
+			}
+
+			// translate identity name
+			if (loggingEvent.Identity != null &&
+				loggingEvent.Identity.Length > 0 &&
+				loggingEvent.LookupProperty(LoggingEvent.IdentityProperty) == null)
+			{
+				loggingEvent.GetProperties()[LoggingEvent.IdentityProperty] = loggingEvent.Identity;
+			}
+
+			// translate user name
+			if (loggingEvent.UserName != null &&
+				loggingEvent.UserName.Length > 0 &&
+				loggingEvent.LookupProperty(LoggingEvent.UserNameProperty) == null)
+			{
+				loggingEvent.GetProperties()[LoggingEvent.UserNameProperty] = loggingEvent.UserName;
+			}
+
+			// Write the start element
+			writer.WriteStartElement(Prefix, "event", NamespaceUri);
+			writer.WriteAttributeString("logger", loggingEvent.LoggerName);
+
+			// Calculate the timestamp as the number of milliseconds since january 1970
+			//
+			// We must convert the TimeStamp to UTC before performing any mathematical
+			// operations. This allows use to take into account discontinuities
+			// caused by daylight savings time transitions.
+			TimeSpan timeSince1970 = loggingEvent.TimeStampUtc - s_date1970;
+
+			writer.WriteAttributeString("timestamp", XmlConvert.ToString((long)timeSince1970.TotalMilliseconds));
+			writer.WriteAttributeString("level", loggingEvent.Level.DisplayName);
+			writer.WriteAttributeString("thread", loggingEvent.ThreadName);
+
+			// Append the message text
+			writer.WriteStartElement(Prefix, "message", NamespaceUri);
+			Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage,this.InvalidCharReplacement);
+			writer.WriteEndElement();
+
+			object ndcObj = loggingEvent.LookupProperty("NDC");
+			if (ndcObj != null)
+			{
+				string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(ndcObj);
+
+				if (valueStr != null && valueStr.Length > 0)
+				{
+					// Append the NDC text
+					writer.WriteStartElement(Prefix, "NDC", NamespaceUri);
+					Transform.WriteEscapedXmlString(writer, valueStr,this.InvalidCharReplacement);
+					writer.WriteEndElement();
+				}
+			}
+
+			// Append the properties text
+			PropertiesDictionary properties = loggingEvent.GetProperties();
+			if (properties.Count > 0)
+			{
+				writer.WriteStartElement(Prefix, "properties", NamespaceUri);
+				foreach(System.Collections.DictionaryEntry entry in properties)
+				{
+					writer.WriteStartElement(Prefix, "data", NamespaceUri);
+					writer.WriteAttributeString("name", (string)entry.Key);
+
+					// Use an ObjectRenderer to convert the object to a string
+					string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(entry.Value);
+					writer.WriteAttributeString("value", valueStr);
+
+					writer.WriteEndElement();
+				}
+				writer.WriteEndElement();
+			}
+
+			string exceptionStr = loggingEvent.GetExceptionString();
+			if (exceptionStr != null && exceptionStr.Length > 0)
+			{
+				// Append the stack trace line
+				writer.WriteStartElement(Prefix, "throwable", NamespaceUri);
+				Transform.WriteEscapedXmlString(writer, exceptionStr,this.InvalidCharReplacement);
+				writer.WriteEndElement();
+			}
+
+			if (LocationInfo)
+			{
+				LocationInfo locationInfo = loggingEvent.LocationInformation;
+
+				writer.WriteStartElement(Prefix, "locationInfo", NamespaceUri);
+				writer.WriteAttributeString("class", locationInfo.ClassName);
+				writer.WriteAttributeString("method", locationInfo.MethodName);
+				writer.WriteAttributeString("file", locationInfo.FileName);
+				writer.WriteAttributeString("line", locationInfo.LineNumber);
+				writer.WriteEndElement();
+			}
+
+			writer.WriteEndElement();
+		}
+
+		private const string LOG4J_SCHEMA = "http://logging.apache.org/log4j";
+		private const string LOG4J_PREFIX = "log4j";
+	}
+}

http://git-wip-us.apache.org/repos/asf/logging-log4net/blob/48dfe286/src/log4net.csproj
----------------------------------------------------------------------
diff --git a/src/log4net.csproj b/src/log4net.csproj
index b638481..2b09c54 100644
--- a/src/log4net.csproj
+++ b/src/log4net.csproj
@@ -515,6 +515,9 @@
     <Compile Include="Layout\XmlLayoutSchemaLog4j.cs">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Layout\XmlLayoutSchemaLog4jNS.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="LogicalThreadContext.cs">
       <SubType>Code</SubType>
     </Compile>