#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.Collections; using System.IO; using log4net.Core; using log4net.Layout.Pattern; using log4net.Util; using log4net.Util.PatternStringConverters; using AppDomainPatternConverter=log4net.Layout.Pattern.AppDomainPatternConverter; using DatePatternConverter=log4net.Layout.Pattern.DatePatternConverter; using IdentityPatternConverter=log4net.Layout.Pattern.IdentityPatternConverter; using PropertyPatternConverter=log4net.Layout.Pattern.PropertyPatternConverter; using UserNamePatternConverter=log4net.Layout.Pattern.UserNamePatternConverter; using UtcDatePatternConverter=log4net.Layout.Pattern.UtcDatePatternConverter; namespace log4net.Layout { /// /// A flexible layout configurable with pattern string. /// /// /// /// The goal of this class is to a /// as a string. The results /// depend on the conversion pattern. /// /// /// The conversion pattern is closely related to the conversion /// pattern of the printf function in C. A conversion pattern is /// composed of literal text and format control expressions called /// conversion specifiers. /// /// /// You are free to insert any literal text within the conversion /// pattern. /// /// /// Each conversion specifier starts with a percent sign (%) and is /// followed by optional format modifiers and a conversion /// pattern name. The conversion pattern name specifies the type of /// data, e.g. logger, level, date, thread name. The format /// modifiers control such things as field width, padding, left and /// right justification. The following is a simple example. /// /// /// Let the conversion pattern be "%-5level [%thread]: %message%newline" and assume /// that the log4net environment was set to use a PatternLayout. Then the /// statements /// /// /// ILog log = LogManager.GetLogger(typeof(TestApp)); /// log.Debug("Message 1"); /// log.Warn("Message 2"); /// /// would yield the output /// /// DEBUG [main]: Message 1 /// WARN [main]: Message 2 /// /// /// Note that there is no explicit separator between text and /// conversion specifiers. The pattern parser knows when it has reached /// the end of a conversion specifier when it reads a conversion /// character. In the example above the conversion specifier /// %-5level means the level of the logging event should be left /// justified to a width of five characters. /// /// /// The recognized conversion pattern names are: /// /// /// /// Conversion Pattern Name /// Effect /// /// /// a /// Equivalent to appdomain /// /// /// appdomain /// /// Used to output the friendly name of the AppDomain where the /// logging event was generated. /// /// /// /// aspnet-cache /// /// /// Used to output all cache items in the case of %aspnet-cache or just one named item if used as %aspnet-cache{key} /// /// /// This pattern is not available for Compact Framework or Client Profile assemblies. /// /// /// /// /// aspnet-context /// /// /// Used to output all context items in the case of %aspnet-context or just one named item if used as %aspnet-context{key} /// /// /// This pattern is not available for Compact Framework or Client Profile assemblies. /// /// /// /// /// aspnet-request /// /// /// Used to output all request parameters in the case of %aspnet-request or just one named param if used as %aspnet-request{key} /// /// /// This pattern is not available for Compact Framework or Client Profile assemblies. /// /// /// /// /// aspnet-session /// /// /// Used to output all session items in the case of %aspnet-session or just one named item if used as %aspnet-session{key} /// /// /// This pattern is not available for Compact Framework or Client Profile assemblies. /// /// /// /// /// c /// Equivalent to logger /// /// /// C /// Equivalent to type /// /// /// class /// Equivalent to type /// /// /// d /// Equivalent to date /// /// /// date /// /// /// Used to output the date of the logging event in the local time zone. /// To output the date in universal time use the %utcdate pattern. /// The date conversion /// specifier may be followed by a date format specifier enclosed /// between braces. For example, %date{HH:mm:ss,fff} or /// %date{dd MMM yyyy HH:mm:ss,fff}. If no date format specifier is /// given then ISO8601 format is /// assumed (). /// /// /// The date format specifier admits the same syntax as the /// time pattern string of the . /// /// /// For better results it is recommended to use the log4net date /// formatters. These can be specified using one of the strings /// "ABSOLUTE", "DATE" and "ISO8601" for specifying /// , /// and respectively /// . For example, /// %date{ISO8601} or %date{ABSOLUTE}. /// /// /// These dedicated date formatters perform significantly /// better than . /// /// /// /// /// exception /// /// /// Used to output the exception passed in with the log message. /// /// /// If an exception object is stored in the logging event /// it will be rendered into the pattern output with a /// trailing newline. /// If there is no exception then nothing will be output /// and no trailing newline will be appended. /// It is typical to put a newline before the exception /// and to have the exception as the last data in the pattern. /// /// /// /// /// F /// Equivalent to file /// /// /// file /// /// /// Used to output the file name where the logging request was /// issued. /// /// /// WARNING Generating caller location information is /// extremely slow. Its use should be avoided unless execution speed /// is not an issue. /// /// /// See the note below on the availability of caller location information. /// /// /// /// /// identity /// /// /// Used to output the user name for the currently active user /// (Principal.Identity.Name). /// /// /// WARNING Generating caller information is /// extremely slow. Its use should be avoided unless execution speed /// is not an issue. /// /// /// /// /// l /// Equivalent to location /// /// /// L /// Equivalent to line /// /// /// location /// /// /// Used to output location information of the caller which generated /// the logging event. /// /// /// The location information depends on the CLI implementation but /// usually consists of the fully qualified name of the calling /// method followed by the callers source the file name and line /// number between parentheses. /// /// /// The location information can be very useful. However, its /// generation is extremely slow. Its use should be avoided /// unless execution speed is not an issue. /// /// /// See the note below on the availability of caller location information. /// /// /// /// /// level /// /// /// Used to output the level of the logging event. /// /// /// /// /// line /// /// /// Used to output the line number from where the logging request /// was issued. /// /// /// WARNING Generating caller location information is /// extremely slow. Its use should be avoided unless execution speed /// is not an issue. /// /// /// See the note below on the availability of caller location information. /// /// /// /// /// logger /// /// /// Used to output the logger of the logging event. The /// logger conversion specifier can be optionally followed by /// precision specifier, that is a decimal constant in /// brackets. /// /// /// If a precision specifier is given, then only the corresponding /// number of right most components of the logger name will be /// printed. By default the logger name is printed in full. /// /// /// For example, for the logger name "a.b.c" the pattern /// %logger{2} will output "b.c". /// /// /// /// /// m /// Equivalent to message /// /// /// M /// Equivalent to method /// /// /// message /// /// /// Used to output the application supplied message associated with /// the logging event. /// /// /// /// /// mdc /// /// /// The MDC (old name for the ThreadContext.Properties) is now part of the /// combined event properties. This pattern is supported for compatibility /// but is equivalent to property. /// /// /// /// /// method /// /// /// Used to output the method name where the logging request was /// issued. /// /// /// WARNING Generating caller location information is /// extremely slow. Its use should be avoided unless execution speed /// is not an issue. /// /// /// See the note below on the availability of caller location information. /// /// /// /// /// n /// Equivalent to newline /// /// /// newline /// /// /// Outputs the platform dependent line separator character or /// characters. /// /// /// This conversion pattern offers the same performance as using /// non-portable line separator strings such as "\n", or "\r\n". /// Thus, it is the preferred way of specifying a line separator. /// /// /// /// /// ndc /// /// /// Used to output the NDC (nested diagnostic context) associated /// with the thread that generated the logging event. /// /// /// /// /// p /// Equivalent to level /// /// /// P /// Equivalent to property /// /// /// properties /// Equivalent to property /// /// /// property /// /// /// Used to output the an event specific property. The key to /// lookup must be specified within braces and directly following the /// pattern specifier, e.g. %property{user} would include the value /// from the property that is keyed by the string 'user'. Each property value /// that is to be included in the log must be specified separately. /// Properties are added to events by loggers or appenders. By default /// the log4net:HostName property is set to the name of machine on /// which the event was originally logged. /// /// /// If no key is specified, e.g. %property then all the keys and their /// values are printed in a comma separated list. /// /// /// The properties of an event are combined from a number of different /// contexts. These are listed below in the order in which they are searched. /// /// /// /// the event properties /// /// The event has that can be set. These /// properties are specific to this event only. /// /// /// /// the thread properties /// /// The that are set on the current /// thread. These properties are shared by all events logged on this thread. /// /// /// /// the global properties /// /// The that are set globally. These /// properties are shared by all the threads in the AppDomain. /// /// /// /// /// /// /// /// r /// Equivalent to timestamp /// /// /// stacktrace /// /// /// Used to output the stack trace of the logging event /// The stack trace level specifier may be enclosed /// between braces. For example, %stacktrace{level}. /// If no stack trace level specifier is given then 1 is assumed /// /// /// Output uses the format: /// type3.MethodCall3 > type2.MethodCall2 > type1.MethodCall1 /// /// /// This pattern is not available for Compact Framework assemblies. /// /// /// /// /// stacktracedetail /// /// /// Used to output the stack trace of the logging event /// The stack trace level specifier may be enclosed /// between braces. For example, %stacktracedetail{level}. /// If no stack trace level specifier is given then 1 is assumed /// /// /// Output uses the format: /// type3.MethodCall3(type param,...) > type2.MethodCall2(type param,...) > type1.MethodCall1(type param,...) /// /// /// This pattern is not available for Compact Framework assemblies. /// /// /// /// /// t /// Equivalent to thread /// /// /// timestamp /// /// /// Used to output the number of milliseconds elapsed since the start /// of the application until the creation of the logging event. /// /// /// /// /// thread /// /// /// Used to output the name of the thread that generated the /// logging event. Uses the thread number if no name is available. /// /// /// /// /// type /// /// /// Used to output the fully qualified type name of the caller /// issuing the logging request. This conversion specifier /// can be optionally followed by precision specifier, that /// is a decimal constant in brackets. /// /// /// If a precision specifier is given, then only the corresponding /// number of right most components of the class name will be /// printed. By default the class name is output in fully qualified form. /// /// /// For example, for the class name "log4net.Layout.PatternLayout", the /// pattern %type{1} will output "PatternLayout". /// /// /// WARNING Generating the caller class information is /// slow. Thus, its use should be avoided unless execution speed is /// not an issue. /// /// /// See the note below on the availability of caller location information. /// /// /// /// /// u /// Equivalent to identity /// /// /// username /// /// /// Used to output the WindowsIdentity for the currently /// active user. /// /// /// WARNING Generating caller WindowsIdentity information is /// extremely slow. Its use should be avoided unless execution speed /// is not an issue. /// /// /// /// /// utcdate /// /// /// Used to output the date of the logging event in universal time. /// The date conversion /// specifier may be followed by a date format specifier enclosed /// between braces. For example, %utcdate{HH:mm:ss,fff} or /// %utcdate{dd MMM yyyy HH:mm:ss,fff}. If no date format specifier is /// given then ISO8601 format is /// assumed (). /// /// /// The date format specifier admits the same syntax as the /// time pattern string of the . /// /// /// For better results it is recommended to use the log4net date /// formatters. These can be specified using one of the strings /// "ABSOLUTE", "DATE" and "ISO8601" for specifying /// , /// and respectively /// . For example, /// %utcdate{ISO8601} or %utcdate{ABSOLUTE}. /// /// /// These dedicated date formatters perform significantly /// better than . /// /// /// /// /// w /// Equivalent to username /// /// /// x /// Equivalent to ndc /// /// /// X /// Equivalent to mdc /// /// /// % /// /// /// The sequence %% outputs a single percent sign. /// /// /// /// /// /// The single letter patterns are deprecated in favor of the /// longer more descriptive pattern names. /// /// /// By default the relevant information is output as is. However, /// with the aid of format modifiers it is possible to change the /// minimum field width, the maximum field width and justification. /// /// /// The optional format modifier is placed between the percent sign /// and the conversion pattern name. /// /// /// The first optional format modifier is the left justification /// flag which is just the minus (-) character. Then comes the /// optional minimum field width modifier. This is a decimal /// constant that represents the minimum number of characters to /// output. If the data item requires fewer characters, it is padded on /// either the left or the right until the minimum width is /// reached. The default is to pad on the left (right justify) but you /// can specify right padding with the left justification flag. The /// padding character is space. If the data item is larger than the /// minimum field width, the field is expanded to accommodate the /// data. The value is never truncated. /// /// /// This behavior can be changed using the maximum field /// width modifier which is designated by a period followed by a /// decimal constant. If the data item is longer than the maximum /// field, then the extra characters are removed from the /// beginning of the data item and not from the end. For /// example, it the maximum field width is eight and the data item is /// ten characters long, then the first two characters of the data item /// are dropped. This behavior deviates from the printf function in C /// where truncation is done from the end. /// /// /// Below are various format modifier examples for the logger /// conversion specifier. /// ///
/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// ///
Format modifierleft justifyminimum widthmaximum widthcomment
%20loggerfalse20none /// /// Left pad with spaces if the logger name is less than 20 /// characters long. /// ///
%-20loggertrue20none /// /// Right pad with spaces if the logger /// name is less than 20 characters long. /// ///
%.30loggerNAnone30 /// /// Truncate from the beginning if the logger /// name is longer than 30 characters. /// ///
%20.30loggerfalse2030 /// /// Left pad with spaces if the logger name is shorter than 20 /// characters. However, if logger name is longer than 30 characters, /// then truncate from the beginning. /// ///
%-20.30loggertrue2030 /// /// Right pad with spaces if the logger name is shorter than 20 /// characters. However, if logger name is longer than 30 characters, /// then truncate from the beginning. /// ///
///
/// /// Note about caller location information.
/// The following patterns %type %file %line %method %location %class %C %F %L %l %M /// all generate caller location information. /// Location information uses the System.Diagnostics.StackTrace class to generate /// a call stack. The caller's information is then extracted from this stack. ///
/// /// /// The System.Diagnostics.StackTrace class is not supported on the /// .NET Compact Framework 1.0 therefore caller location information is not /// available on that framework. /// /// /// /// /// The System.Diagnostics.StackTrace class has this to say about Release builds: /// /// /// "StackTrace information will be most informative with Debug build configurations. /// By default, Debug builds include debug symbols, while Release builds do not. The /// debug symbols contain most of the file, method name, line number, and column /// information used in constructing StackFrame and StackTrace objects. StackTrace /// might not report as many method calls as expected, due to code transformations /// that occur during optimization." /// /// /// This means that in a Release build the caller information may be incomplete or may /// not exist at all! Therefore caller location information cannot be relied upon in a Release build. /// /// /// /// Additional pattern converters may be registered with a specific /// instance using the method. /// ///
/// /// This is a more detailed pattern. /// %timestamp [%thread] %level %logger %ndc - %message%newline /// /// /// A similar pattern except that the relative time is /// right padded if less than 6 digits, thread name is right padded if /// less than 15 characters and truncated if longer and the logger /// name is left padded if shorter than 30 characters and truncated if /// longer. /// %-6timestamp [%15.15thread] %-5level %30.30logger %ndc - %message%newline /// /// Nicko Cadell /// Gert Driesen /// Douglas de la Torre /// Daniel Cazzulino public class PatternLayout : LayoutSkeleton { #region Constants /// /// Default pattern string for log output. /// /// /// /// Default pattern string for log output. /// Currently set to the string "%message%newline" /// which just prints the application supplied message. /// /// public const string DefaultConversionPattern ="%message%newline"; /// /// A detailed conversion pattern /// /// /// /// A conversion pattern which includes Time, Thread, Logger, and Nested Context. /// Current value is %timestamp [%thread] %level %logger %ndc - %message%newline. /// /// public const string DetailConversionPattern = "%timestamp [%thread] %level %logger %ndc - %message%newline"; #endregion #region Static Fields /// /// Internal map of converter identifiers to converter types. /// /// /// /// This static map is overridden by the m_converterRegistry instance map /// /// private static Hashtable s_globalRulesRegistry; #endregion Static Fields #region Member Variables /// /// the pattern /// private string m_pattern; /// /// the head of the pattern converter chain /// private PatternConverter m_head; /// /// patterns defined on this PatternLayout only /// private Hashtable m_instanceRulesRegistry = new Hashtable(); #endregion #region Static Constructor /// /// Initialize the global registry /// /// /// /// Defines the builtin global rules. /// /// static PatternLayout() { s_globalRulesRegistry = new Hashtable(45); s_globalRulesRegistry.Add("literal", typeof(LiteralPatternConverter)); s_globalRulesRegistry.Add("newline", typeof(NewLinePatternConverter)); s_globalRulesRegistry.Add("n", typeof(NewLinePatternConverter)); // .NET Compact Framework 1.0 has no support for ASP.NET // SSCLI 1.0 has no support for ASP.NET #if !NETCF && !SSCLI && !CLIENT_PROFILE && !NETSTANDARD s_globalRulesRegistry.Add("aspnet-cache", typeof(AspNetCachePatternConverter)); s_globalRulesRegistry.Add("aspnet-context", typeof(AspNetContextPatternConverter)); s_globalRulesRegistry.Add("aspnet-request", typeof(AspNetRequestPatternConverter)); s_globalRulesRegistry.Add("aspnet-session", typeof(AspNetSessionPatternConverter)); #endif s_globalRulesRegistry.Add("c", typeof(LoggerPatternConverter)); s_globalRulesRegistry.Add("logger", typeof(LoggerPatternConverter)); s_globalRulesRegistry.Add("C", typeof(TypeNamePatternConverter)); s_globalRulesRegistry.Add("class", typeof(TypeNamePatternConverter)); s_globalRulesRegistry.Add("type", typeof(TypeNamePatternConverter)); s_globalRulesRegistry.Add("d", typeof(DatePatternConverter)); s_globalRulesRegistry.Add("date", typeof(DatePatternConverter)); s_globalRulesRegistry.Add("exception", typeof(ExceptionPatternConverter)); s_globalRulesRegistry.Add("F", typeof(FileLocationPatternConverter)); s_globalRulesRegistry.Add("file", typeof(FileLocationPatternConverter)); s_globalRulesRegistry.Add("l", typeof(FullLocationPatternConverter)); s_globalRulesRegistry.Add("location", typeof(FullLocationPatternConverter)); s_globalRulesRegistry.Add("L", typeof(LineLocationPatternConverter)); s_globalRulesRegistry.Add("line", typeof(LineLocationPatternConverter)); s_globalRulesRegistry.Add("m", typeof(MessagePatternConverter)); s_globalRulesRegistry.Add("message", typeof(MessagePatternConverter)); s_globalRulesRegistry.Add("M", typeof(MethodLocationPatternConverter)); s_globalRulesRegistry.Add("method", typeof(MethodLocationPatternConverter)); s_globalRulesRegistry.Add("p", typeof(LevelPatternConverter)); s_globalRulesRegistry.Add("level", typeof(LevelPatternConverter)); s_globalRulesRegistry.Add("P", typeof(PropertyPatternConverter)); s_globalRulesRegistry.Add("property", typeof(PropertyPatternConverter)); s_globalRulesRegistry.Add("properties", typeof(PropertyPatternConverter)); s_globalRulesRegistry.Add("r", typeof(RelativeTimePatternConverter)); s_globalRulesRegistry.Add("timestamp", typeof(RelativeTimePatternConverter)); #if !NETCF && !NETSTANDARD1_3 s_globalRulesRegistry.Add("stacktrace", typeof(StackTracePatternConverter)); s_globalRulesRegistry.Add("stacktracedetail", typeof(StackTraceDetailPatternConverter)); #endif s_globalRulesRegistry.Add("t", typeof(ThreadPatternConverter)); s_globalRulesRegistry.Add("thread", typeof(ThreadPatternConverter)); // For backwards compatibility the NDC patterns s_globalRulesRegistry.Add("x", typeof(NdcPatternConverter)); s_globalRulesRegistry.Add("ndc", typeof(NdcPatternConverter)); // For backwards compatibility the MDC patterns just do a property lookup s_globalRulesRegistry.Add("X", typeof(PropertyPatternConverter)); s_globalRulesRegistry.Add("mdc", typeof(PropertyPatternConverter)); s_globalRulesRegistry.Add("a", typeof(AppDomainPatternConverter)); s_globalRulesRegistry.Add("appdomain", typeof(AppDomainPatternConverter)); s_globalRulesRegistry.Add("u", typeof(IdentityPatternConverter)); s_globalRulesRegistry.Add("identity", typeof(IdentityPatternConverter)); s_globalRulesRegistry.Add("utcdate", typeof(UtcDatePatternConverter)); s_globalRulesRegistry.Add("utcDate", typeof(UtcDatePatternConverter)); s_globalRulesRegistry.Add("UtcDate", typeof(UtcDatePatternConverter)); s_globalRulesRegistry.Add("w", typeof(UserNamePatternConverter)); s_globalRulesRegistry.Add("username", typeof(UserNamePatternConverter)); } #endregion Static Constructor #region Constructors /// /// Constructs a PatternLayout using the DefaultConversionPattern /// /// /// /// The default pattern just produces the application supplied message. /// /// /// Note to Inheritors: This constructor calls the virtual method /// . If you override this method be /// aware that it will be called before your is called constructor. /// /// /// As per the contract the /// method must be called after the properties on this object have been /// configured. /// /// public PatternLayout() : this(DefaultConversionPattern) { } /// /// Constructs a PatternLayout using the supplied conversion pattern /// /// the pattern to use /// /// /// Note to Inheritors: This constructor calls the virtual method /// . If you override this method be /// aware that it will be called before your is called constructor. /// /// /// When using this constructor the method /// need not be called. This may not be the case when using a subclass. /// /// public PatternLayout(string pattern) { // By default we do not process the exception IgnoresException = true; m_pattern = pattern; if (m_pattern == null) { m_pattern = DefaultConversionPattern; } ActivateOptions(); } #endregion /// /// The pattern formatting string /// /// /// /// The ConversionPattern option. This is the string which /// controls formatting and consists of a mix of literal content and /// conversion specifiers. /// /// public string ConversionPattern { get { return m_pattern; } set { m_pattern = value; } } /// /// Create the pattern parser instance /// /// the pattern to parse /// The that will format the event /// /// /// Creates the used to parse the conversion string. Sets the /// global and instance rules on the . /// /// protected virtual PatternParser CreatePatternParser(string pattern) { PatternParser patternParser = new PatternParser(pattern); // Add all the builtin patterns foreach(DictionaryEntry entry in s_globalRulesRegistry) { ConverterInfo converterInfo = new ConverterInfo(); converterInfo.Name = (string)entry.Key; converterInfo.Type = (Type)entry.Value; patternParser.PatternConverters[entry.Key] = converterInfo; } // Add the instance patterns foreach(DictionaryEntry entry in m_instanceRulesRegistry) { patternParser.PatternConverters[entry.Key] = entry.Value; } return patternParser; } #region Implementation of IOptionHandler /// /// Initialize layout options /// /// /// /// This is part of the delayed object /// activation scheme. The method must /// be called on this object after the configuration properties have /// been set. Until is called this /// object is in an undefined state and must not be used. /// /// /// If any of the configuration properties are modified then /// must be called again. /// /// public override void ActivateOptions() { m_head = CreatePatternParser(m_pattern).Parse(); PatternConverter curConverter = m_head; while(curConverter != null) { PatternLayoutConverter layoutConverter = curConverter as PatternLayoutConverter; if (layoutConverter != null) { if (!layoutConverter.IgnoresException) { // Found converter that handles the exception this.IgnoresException = false; break; } } curConverter = curConverter.Next; } } #endregion #region Override implementation of LayoutSkeleton /// /// Produces a formatted string as specified by the conversion pattern. /// /// the event being logged /// The TextWriter to write the formatted event to /// /// /// Parse the using the patter format /// specified in the property. /// /// public override void Format(TextWriter writer, LoggingEvent loggingEvent) { if (writer == null) { throw new ArgumentNullException("writer"); } if (loggingEvent == null) { throw new ArgumentNullException("loggingEvent"); } PatternConverter c = m_head; // loop through the chain of pattern converters while(c != null) { c.Format(writer, loggingEvent); c = c.Next; } } #endregion /// /// Add a converter to this PatternLayout /// /// the converter info /// /// /// This version of the method is used by the configurator. /// Programmatic users should use the alternative method. /// /// public void AddConverter(ConverterInfo converterInfo) { if (converterInfo == null) throw new ArgumentNullException("converterInfo"); if (!typeof(PatternConverter).IsAssignableFrom(converterInfo.Type)) { throw new ArgumentException("The converter type specified [" + converterInfo.Type + "] must be a subclass of log4net.Util.PatternConverter", "converterInfo"); } m_instanceRulesRegistry[converterInfo.Name] = converterInfo; } /// /// Add a converter to this PatternLayout /// /// the name of the conversion pattern for this converter /// the type of the converter /// /// /// Add a named pattern converter to this instance. This /// converter will be used in the formatting of the event. /// This method must be called before . /// /// /// The specified must extend the /// type. /// /// public void AddConverter(string name, Type type) { if (name == null) throw new ArgumentNullException("name"); if (type == null) throw new ArgumentNullException("type"); ConverterInfo converterInfo = new ConverterInfo(); converterInfo.Name = name; converterInfo.Type = type; AddConverter(converterInfo); } } }