123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- #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 log4net.Core;
- using log4net.Util;
- namespace log4net.Layout
- {
- /// <summary>
- /// Layout that formats the log events as XML elements.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The output of the <see cref="XmlLayout" /> consists of a series of
- /// log4net:event elements. It does not output a complete well-formed XML
- /// file. The output is designed to be included as an <em>external entity</em>
- /// in a separate file to form a correct XML file.
- /// </para>
- /// <para>
- /// For example, if <c>abc</c> is the name of the file where
- /// the <see cref="XmlLayout" /> output goes, then a well-formed XML file would
- /// be:
- /// </para>
- /// <code lang="XML">
- /// <?xml version="1.0" ?>
- ///
- /// <!DOCTYPE log4net:events SYSTEM "log4net-events.dtd" [<!ENTITY data SYSTEM "abc">]>
- ///
- /// <log4net:events version="1.2" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2>
- /// &data;
- /// </log4net:events>
- /// </code>
- /// <para>
- /// This approach enforces the independence of the <see cref="XmlLayout" />
- /// and the appender where it is embedded.
- /// </para>
- /// <para>
- /// The <c>version</c> attribute helps components to correctly
- /// interpret output generated by <see cref="XmlLayout" />. The value of
- /// this attribute should be "1.2" for release 1.2 and later.
- /// </para>
- /// <para>
- /// Alternatively the <c>Header</c> and <c>Footer</c> properties can be
- /// configured to output the correct XML header, open tag and close tag.
- /// When setting the <c>Header</c> and <c>Footer</c> properties it is essential
- /// that the underlying data store not be appendable otherwise the data
- /// will become invalid XML.
- /// </para>
- /// </remarks>
- /// <author>Nicko Cadell</author>
- /// <author>Gert Driesen</author>
- public class XmlLayout : XmlLayoutBase
- {
- #region Public Instance Constructors
- /// <summary>
- /// Constructs an XmlLayout
- /// </summary>
- public XmlLayout() : base()
- {
- }
- /// <summary>
- /// Constructs an XmlLayout.
- /// </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 XmlLayout(bool locationInfo) : base(locationInfo)
- {
- }
- #endregion Public Instance Constructors
- #region Public Instance Properties
- /// <summary>
- /// The prefix to use for all element names
- /// </summary>
- /// <remarks>
- /// <para>
- /// The default prefix is <b>log4net</b>. Set this property
- /// to change the prefix. If the prefix is set to an empty string
- /// then no prefix will be written.
- /// </para>
- /// </remarks>
- public string Prefix
- {
- get { return m_prefix; }
- 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="XmlLayoutBase.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="XmlLayoutBase.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
- /// <summary>
- /// Initialize layout options
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is part of the <see cref="IOptionHandler"/> delayed object
- /// activation scheme. The <see cref="ActivateOptions"/> method must
- /// be called on this object after the configuration properties have
- /// been set. Until <see cref="ActivateOptions"/> is called this
- /// object is in an undefined state and must not be used.
- /// </para>
- /// <para>
- /// If any of the configuration properties are modified then
- /// <see cref="ActivateOptions"/> must be called again.
- /// </para>
- /// <para>
- /// Builds a cache of the element names
- /// </para>
- /// </remarks>
- override public void ActivateOptions()
- {
- base.ActivateOptions();
- // Cache the full element names including the prefix
- if (m_prefix != null && m_prefix.Length > 0)
- {
- m_elmEvent = m_prefix + ":" + ELM_EVENT;
- m_elmMessage = m_prefix + ":" + ELM_MESSAGE;
- m_elmProperties = m_prefix + ":" + ELM_PROPERTIES;
- m_elmData = m_prefix + ":" + ELM_DATA;
- m_elmException = m_prefix + ":" + ELM_EXCEPTION;
- m_elmLocation = m_prefix + ":" + ELM_LOCATION;
- }
- }
- #endregion Implementation of IOptionHandler
- #region Override implementation of XMLLayoutBase
- /// <summary>
- /// Does the actual writing of the XML.
- /// </summary>
- /// <param name="writer">The writer to use to output the event to.</param>
- /// <param name="loggingEvent">The event to write.</param>
- /// <remarks>
- /// <para>
- /// Override the base class <see cref="XmlLayoutBase.FormatXml"/> method
- /// to write the <see cref="LoggingEvent"/> to the <see cref="XmlWriter"/>.
- /// </para>
- /// </remarks>
- override protected void FormatXml(XmlWriter writer, LoggingEvent loggingEvent)
- {
- writer.WriteStartElement(m_elmEvent);
- writer.WriteAttributeString(ATTR_LOGGER, loggingEvent.LoggerName);
- #if NET_2_0 || NETCF_2_0 || MONO_2_0 || NETSTANDARD1_3
- writer.WriteAttributeString(ATTR_TIMESTAMP, XmlConvert.ToString(loggingEvent.TimeStamp, XmlDateTimeSerializationMode.Local));
- #else
- writer.WriteAttributeString(ATTR_TIMESTAMP, XmlConvert.ToString(loggingEvent.TimeStamp));
- #endif
- writer.WriteAttributeString(ATTR_LEVEL, loggingEvent.Level.DisplayName);
- writer.WriteAttributeString(ATTR_THREAD, loggingEvent.ThreadName);
- if (loggingEvent.Domain != null && loggingEvent.Domain.Length > 0)
- {
- writer.WriteAttributeString(ATTR_DOMAIN, loggingEvent.Domain);
- }
- if (loggingEvent.Identity != null && loggingEvent.Identity.Length > 0)
- {
- writer.WriteAttributeString(ATTR_IDENTITY, loggingEvent.Identity);
- }
- if (loggingEvent.UserName != null && loggingEvent.UserName.Length > 0)
- {
- writer.WriteAttributeString(ATTR_USERNAME, loggingEvent.UserName);
- }
-
- // Append the message text
- writer.WriteStartElement(m_elmMessage);
- if (!this.Base64EncodeMessage)
- {
- Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage, this.InvalidCharReplacement);
- }
- else
- {
- byte[] messageBytes = Encoding.UTF8.GetBytes(loggingEvent.RenderedMessage);
- string base64Message = Convert.ToBase64String(messageBytes, 0, messageBytes.Length);
- Transform.WriteEscapedXmlString(writer, base64Message,this.InvalidCharReplacement);
- }
- writer.WriteEndElement();
- PropertiesDictionary properties = loggingEvent.GetProperties();
- // Append the properties text
- if (properties.Count > 0)
- {
- writer.WriteStartElement(m_elmProperties);
- foreach(System.Collections.DictionaryEntry entry in properties)
- {
- writer.WriteStartElement(m_elmData);
- writer.WriteAttributeString(ATTR_NAME, Transform.MaskXmlInvalidCharacters((string)entry.Key,this.InvalidCharReplacement));
- // Use an ObjectRenderer to convert the object to a string
- string valueStr =null;
- if (!this.Base64EncodeProperties)
- {
- valueStr = Transform.MaskXmlInvalidCharacters(loggingEvent.Repository.RendererMap.FindAndRender(entry.Value),this.InvalidCharReplacement);
- }
- else
- {
- byte[] propertyValueBytes = Encoding.UTF8.GetBytes(loggingEvent.Repository.RendererMap.FindAndRender(entry.Value));
- valueStr = Convert.ToBase64String(propertyValueBytes, 0, propertyValueBytes.Length);
- }
- writer.WriteAttributeString(ATTR_VALUE, valueStr);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- }
- string exceptionStr = loggingEvent.GetExceptionString();
- if (exceptionStr != null && exceptionStr.Length > 0)
- {
- // Append the stack trace line
- writer.WriteStartElement(m_elmException);
- Transform.WriteEscapedXmlString(writer, exceptionStr,this.InvalidCharReplacement);
- writer.WriteEndElement();
- }
- if (LocationInfo)
- {
- LocationInfo locationInfo = loggingEvent.LocationInformation;
- writer.WriteStartElement(m_elmLocation);
- writer.WriteAttributeString(ATTR_CLASS, locationInfo.ClassName);
- writer.WriteAttributeString(ATTR_METHOD, locationInfo.MethodName);
- writer.WriteAttributeString(ATTR_FILE, locationInfo.FileName);
- writer.WriteAttributeString(ATTR_LINE, locationInfo.LineNumber);
- writer.WriteEndElement();
- }
- writer.WriteEndElement();
- }
- #endregion Override implementation of XMLLayoutBase
- #region Private Instance Fields
-
- /// <summary>
- /// The prefix to use for all generated element names
- /// </summary>
- private string m_prefix = PREFIX;
- private string m_elmEvent = ELM_EVENT;
- private string m_elmMessage = ELM_MESSAGE;
- private string m_elmData = ELM_DATA;
- private string m_elmProperties = ELM_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
- private const string PREFIX = "log4net";
- private const string ELM_EVENT = "event";
- private const string ELM_MESSAGE = "message";
- private const string ELM_PROPERTIES = "properties";
- private const string ELM_GLOBAL_PROPERTIES = "global-properties";
- private const string ELM_DATA = "data";
- private const string ELM_EXCEPTION = "exception";
- private const string ELM_LOCATION = "locationInfo";
- private const string ATTR_LOGGER = "logger";
- private const string ATTR_TIMESTAMP = "timestamp";
- private const string ATTR_LEVEL = "level";
- private const string ATTR_THREAD = "thread";
- private const string ATTR_DOMAIN = "domain";
- private const string ATTR_IDENTITY = "identity";
- private const string ATTR_USERNAME = "username";
- private const string ATTR_CLASS = "class";
- private const string ATTR_METHOD = "method";
- private const string ATTR_FILE = "file";
- private const string ATTR_LINE = "line";
- private const string ATTR_NAME = "name";
- private const string ATTR_VALUE = "value";
- #endregion Private Static Fields
- }
- }
|