#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.Text; using System.IO; using System.Collections; using log4net.Util; using log4net.Repository; namespace log4net.Util { /// /// Abstract class that provides the formatting functionality that /// derived classes need. /// /// /// /// 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. /// /// /// Nicko Cadell /// Gert Driesen public abstract class PatternConverter { #region Protected Instance Constructors /// /// Protected constructor /// /// /// /// Initializes a new instance of the class. /// /// protected PatternConverter() { } #endregion Protected Instance Constructors #region Public Instance Properties /// /// Get the next pattern converter in the chain /// /// /// the next pattern converter in the chain /// /// /// /// Get the next pattern converter in the chain /// /// public virtual PatternConverter Next { get { return m_next; } } /// /// Gets or sets the formatting info for this converter /// /// /// The formatting info for this converter /// /// /// /// Gets or sets the formatting info for this converter /// /// public virtual FormattingInfo FormattingInfo { get { return new FormattingInfo(m_min, m_max, m_leftAlign); } set { m_min = value.Min; m_max = value.Max; m_leftAlign = value.LeftAlign; } } /// /// Gets or sets the option value for this converter /// /// /// The option for this converter /// /// /// /// Gets or sets the option value for this converter /// /// public virtual string Option { get { return m_option; } set { m_option = value; } } #endregion Public Instance Properties #region Protected Abstract Methods /// /// Evaluate this pattern converter and write the output to a writer. /// /// that will receive the formatted result. /// The state object on which the pattern converter should be executed. /// /// /// Derived pattern converters must override this method in order to /// convert conversion specifiers in the appropriate way. /// /// abstract protected void Convert(TextWriter writer, object state); #endregion Protected Abstract Methods #region Public Instance Methods /// /// Set the next pattern converter in the chains /// /// the pattern converter that should follow this converter in the chain /// the next converter /// /// /// The PatternConverter can merge with its neighbor during this method (or a sub class). /// Therefore the return value may or may not be the value of the argument passed in. /// /// public virtual PatternConverter SetNext(PatternConverter patternConverter) { m_next = patternConverter; return m_next; } /// /// Write the pattern converter to the writer with appropriate formatting /// /// that will receive the formatted result. /// The state object on which the pattern converter should be executed. /// /// /// This method calls to allow the subclass to perform /// appropriate conversion of the pattern converter. If formatting options have /// been specified via the then this method will /// apply those formattings before writing the output. /// /// virtual public void Format(TextWriter writer, object state) { if (m_min < 0 && m_max == int.MaxValue) { // Formatting options are not in use Convert(writer, state); } else { string msg = null; int len; lock (m_formatWriter) { m_formatWriter.Reset(c_renderBufferMaxCapacity, c_renderBufferSize); Convert(m_formatWriter, state); StringBuilder buf = m_formatWriter.GetStringBuilder(); len = buf.Length; if (len > m_max) { msg = buf.ToString(len - m_max, m_max); len = m_max; } else { msg = buf.ToString(); } } if (len < m_min) { if (m_leftAlign) { writer.Write(msg); SpacePad(writer, m_min - len); } else { SpacePad(writer, m_min - len); writer.Write(msg); } } else { writer.Write(msg); } } } private static readonly string[] SPACES = { " ", " ", " ", " ", // 1,2,4,8 spaces " ", // 16 spaces " " }; // 32 spaces /// /// Fast space padding method. /// /// to which the spaces will be appended. /// The number of spaces to be padded. /// /// /// Fast space padding method. /// /// protected static void SpacePad(TextWriter writer, int length) { while(length >= 32) { writer.Write(SPACES[5]); length -= 32; } for(int i = 4; i >= 0; i--) { if ((length & (1< /// The option string to the converter /// private string m_option = null; private ReusableStringWriter m_formatWriter = new ReusableStringWriter(System.Globalization.CultureInfo.InvariantCulture); #endregion Private Instance Fields #region Constants /// /// Initial buffer size /// private const int c_renderBufferSize = 256; /// /// Maximum buffer size before it is recycled /// private const int c_renderBufferMaxCapacity = 1024; #endregion #region Static Methods /// /// Write an dictionary to a /// /// the writer to write to /// a to use for object conversion /// the value to write to the writer /// /// /// Writes the to a writer in the form: /// /// /// {key1=value1, key2=value2, key3=value3} /// /// /// If the specified /// is not null then it is used to render the key and value to text, otherwise /// the object's ToString method is called. /// /// protected static void WriteDictionary(TextWriter writer, ILoggerRepository repository, IDictionary value) { WriteDictionary(writer, repository, value.GetEnumerator()); } /// /// Write an dictionary to a /// /// the writer to write to /// a to use for object conversion /// the value to write to the writer /// /// /// Writes the to a writer in the form: /// /// /// {key1=value1, key2=value2, key3=value3} /// /// /// If the specified /// is not null then it is used to render the key and value to text, otherwise /// the object's ToString method is called. /// /// protected static void WriteDictionary(TextWriter writer, ILoggerRepository repository, IDictionaryEnumerator value) { writer.Write("{"); bool first = true; // Write out all the dictionary key value pairs while (value.MoveNext()) { if (first) { first = false; } else { writer.Write(", "); } WriteObject(writer, repository, value.Key); writer.Write("="); WriteObject(writer, repository, value.Value); } writer.Write("}"); } /// /// Write an object to a /// /// the writer to write to /// a to use for object conversion /// the value to write to the writer /// /// /// Writes the Object to a writer. If the specified /// is not null then it is used to render the object to text, otherwise /// the object's ToString method is called. /// /// protected static void WriteObject(TextWriter writer, ILoggerRepository repository, object value) { if (repository != null) { repository.RendererMap.FindAndRender(value, writer); } else { // Don't have a repository to render with so just have to rely on ToString if (value == null) { writer.Write( SystemInfo.NullText ); } else { writer.Write( value.ToString() ); } } } #endregion private PropertiesDictionary properties; /// /// /// public PropertiesDictionary Properties { get { return properties; } set { properties = value; } } } }