| #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 System.Runtime.Serialization; |
| using System.Security; |
| #if !NETCF && !NETSTANDARD1_3 |
| using System.Security.Principal; |
| #endif |
| using log4net.Util; |
| using log4net.Repository; |
| |
| namespace log4net.Core |
| { |
| /// <summary> |
| /// Portable data structure used by <see cref="LoggingEvent"/> |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Portable data structure used by <see cref="LoggingEvent"/> |
| /// </para> |
| /// </remarks> |
| /// <author>Nicko Cadell</author> |
| public struct LoggingEventData |
| { |
| #region Public Instance Fields |
| |
| /// <summary> |
| /// The logger name. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The logger name. |
| /// </para> |
| /// </remarks> |
| public string LoggerName; |
| |
| /// <summary> |
| /// Level of logging event. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Level of logging event. Level cannot be Serializable |
| /// because it is a flyweight. Due to its special serialization it |
| /// cannot be declared final either. |
| /// </para> |
| /// </remarks> |
| public Level Level; |
| |
| /// <summary> |
| /// The application supplied message. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The application supplied message of logging event. |
| /// </para> |
| /// </remarks> |
| public string Message; |
| |
| /// <summary> |
| /// The name of thread |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The name of thread in which this logging event was generated |
| /// </para> |
| /// </remarks> |
| public string ThreadName; |
| |
| /// <summary> |
| /// Gets or sets the local time the event was logged |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Prefer using the <see cref="TimeStampUtc"/> setter, since local time can be ambiguous. |
| /// </para> |
| /// </remarks> |
| [Obsolete( |
| "Prefer using TimeStampUtc, since local time can be ambiguous in time zones with daylight savings time.")] |
| public DateTime TimeStamp; |
| |
| /// <summary> |
| /// Gets or sets the UTC time the event was logged |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The TimeStamp is stored in the UTC time zone. |
| /// </para> |
| /// </remarks> |
| #pragma warning disable 618 // Suppress warnings that TimeStamp field is obsolete |
| public DateTime TimeStampUtc |
| { |
| get |
| { |
| if (TimeStamp != default(DateTime) && |
| _timeStampUtc == default(DateTime)) |
| { |
| // TimeStamp field has been set explicitly but TimeStampUtc hasn't |
| // => use TimeStamp |
| return TimeStamp.ToUniversalTime(); |
| } |
| |
| return _timeStampUtc; |
| } |
| set |
| { |
| _timeStampUtc = value; |
| // For backwards compatibility |
| TimeStamp = _timeStampUtc.ToLocalTime(); |
| } |
| } |
| |
| private DateTime _timeStampUtc; |
| #pragma warning restore 618 |
| |
| /// <summary> |
| /// Location information for the caller. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Location information for the caller. |
| /// </para> |
| /// </remarks> |
| public LocationInfo LocationInfo; |
| |
| /// <summary> |
| /// String representation of the user |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// String representation of the user's windows name, |
| /// like DOMAIN\username |
| /// </para> |
| /// </remarks> |
| public string UserName; |
| |
| /// <summary> |
| /// String representation of the identity. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// String representation of the current thread's principal identity. |
| /// </para> |
| /// </remarks> |
| public string Identity; |
| |
| /// <summary> |
| /// The string representation of the exception |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The string representation of the exception |
| /// </para> |
| /// </remarks> |
| public string ExceptionString; |
| |
| /// <summary> |
| /// String representation of the AppDomain. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// String representation of the AppDomain. |
| /// </para> |
| /// </remarks> |
| public string Domain; |
| |
| /// <summary> |
| /// Additional event specific properties |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// A logger or an appender may attach additional |
| /// properties to specific events. These properties |
| /// have a string key and an object value. |
| /// </para> |
| /// </remarks> |
| public PropertiesDictionary Properties; |
| |
| #endregion Public Instance Fields |
| } |
| |
| /// <summary> |
| /// The internal representation of logging events. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// When an affirmative decision is made to log then a |
| /// <see cref="LoggingEvent"/> instance is created. This instance |
| /// is passed around to the different log4net components. |
| /// </para> |
| /// <para> |
| /// This class is of concern to those wishing to extend log4net. |
| /// </para> |
| /// <para> |
| /// Some of the values in instances of <see cref="LoggingEvent"/> |
| /// are considered volatile, that is the values are correct at the |
| /// time the event is delivered to appenders, but will not be consistent |
| /// at any time afterwards. If an event is to be stored and then processed |
| /// at a later time these volatile values must be fixed by calling |
| /// <see cref="M:FixVolatileData()"/>. There is a performance penalty |
| /// for incurred by calling <see cref="M:FixVolatileData()"/> but it |
| /// is essential to maintaining data consistency. |
| /// </para> |
| /// </remarks> |
| /// <author>Nicko Cadell</author> |
| /// <author>Gert Driesen</author> |
| /// <author>Douglas de la Torre</author> |
| /// <author>Daniel Cazzulino</author> |
| #if !NETCF |
| [Serializable] |
| #endif |
| public class LoggingEvent |
| #if !NETCF |
| : ISerializable |
| #endif |
| { |
| private static readonly Type declaringType = typeof(LoggingEvent); |
| |
| #region Public Instance Constructors |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="LoggingEvent" /> class |
| /// from the supplied parameters. |
| /// </summary> |
| /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is |
| /// the stack boundary into the logging system for this call.</param> |
| /// <param name="repository">The repository this event is logged in.</param> |
| /// <param name="loggerName">The name of the logger of this event.</param> |
| /// <param name="level">The level of this event.</param> |
| /// <param name="message">The message of this event.</param> |
| /// <param name="exception">The exception for this event.</param> |
| /// <remarks> |
| /// <para> |
| /// Except <see cref="TimeStamp"/>, <see cref="Level"/> and <see cref="LoggerName"/>, |
| /// all fields of <c>LoggingEvent</c> are filled when actually needed. Call |
| /// <see cref="M:FixVolatileData()"/> to cache all data locally |
| /// to prevent inconsistencies. |
| /// </para> |
| /// <para>This method is called by the log4net framework |
| /// to create a logging event. |
| /// </para> |
| /// </remarks> |
| public LoggingEvent(Type callerStackBoundaryDeclaringType, |
| log4net.Repository.ILoggerRepository repository, |
| string loggerName, |
| Level level, |
| object message, |
| Exception exception) |
| { |
| m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType; |
| m_message = message; |
| m_repository = repository; |
| m_thrownException = exception; |
| |
| m_data.LoggerName = loggerName; |
| m_data.Level = level; |
| |
| // Store the event creation time |
| m_data.TimeStampUtc = DateTime.UtcNow; |
| } |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="LoggingEvent" /> class |
| /// using specific data. |
| /// </summary> |
| /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is |
| /// the stack boundary into the logging system for this call.</param> |
| /// <param name="repository">The repository this event is logged in.</param> |
| /// <param name="data">Data used to initialize the logging event.</param> |
| /// <param name="fixedData">The fields in the <paranref name="data"/> struct that have already been fixed.</param> |
| /// <remarks> |
| /// <para> |
| /// This constructor is provided to allow a <see cref="LoggingEvent" /> |
| /// to be created independently of the log4net framework. This can |
| /// be useful if you require a custom serialization scheme. |
| /// </para> |
| /// <para> |
| /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an |
| /// instance of the <see cref="LoggingEventData"/> class. |
| /// </para> |
| /// <para> |
| /// The <paramref name="fixedData"/> parameter should be used to specify which fields in the |
| /// <paramref name="data"/> struct have been preset. Fields not specified in the <paramref name="fixedData"/> |
| /// will be captured from the environment if requested or fixed. |
| /// </para> |
| /// </remarks> |
| public LoggingEvent(Type callerStackBoundaryDeclaringType, |
| log4net.Repository.ILoggerRepository repository, |
| LoggingEventData data, |
| FixFlags fixedData) |
| { |
| m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType; |
| m_repository = repository; |
| |
| m_data = data; |
| m_fixFlags = fixedData; |
| } |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="LoggingEvent" /> class |
| /// using specific data. |
| /// </summary> |
| /// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is |
| /// the stack boundary into the logging system for this call.</param> |
| /// <param name="repository">The repository this event is logged in.</param> |
| /// <param name="data">Data used to initialize the logging event.</param> |
| /// <remarks> |
| /// <para> |
| /// This constructor is provided to allow a <see cref="LoggingEvent" /> |
| /// to be created independently of the log4net framework. This can |
| /// be useful if you require a custom serialization scheme. |
| /// </para> |
| /// <para> |
| /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an |
| /// instance of the <see cref="LoggingEventData"/> class. |
| /// </para> |
| /// <para> |
| /// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>, |
| /// this assumes that all the data relating to this event is passed in via the <paramref name="data"/> |
| /// parameter and no other data should be captured from the environment. |
| /// </para> |
| /// </remarks> |
| public LoggingEvent(Type callerStackBoundaryDeclaringType, |
| log4net.Repository.ILoggerRepository repository, |
| LoggingEventData data) : this(callerStackBoundaryDeclaringType, repository, data, FixFlags.All) |
| { |
| } |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="LoggingEvent" /> class |
| /// using specific data. |
| /// </summary> |
| /// <param name="data">Data used to initialize the logging event.</param> |
| /// <remarks> |
| /// <para> |
| /// This constructor is provided to allow a <see cref="LoggingEvent" /> |
| /// to be created independently of the log4net framework. This can |
| /// be useful if you require a custom serialization scheme. |
| /// </para> |
| /// <para> |
| /// Use the <see cref="M:GetLoggingEventData(FixFlags)"/> method to obtain an |
| /// instance of the <see cref="LoggingEventData"/> class. |
| /// </para> |
| /// <para> |
| /// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>, |
| /// this assumes that all the data relating to this event is passed in via the <paramref name="data"/> |
| /// parameter and no other data should be captured from the environment. |
| /// </para> |
| /// </remarks> |
| public LoggingEvent(LoggingEventData data) : this(null, null, data) |
| { |
| } |
| |
| #endregion Public Instance Constructors |
| |
| #region Protected Instance Constructors |
| |
| #if !NETCF |
| |
| /// <summary> |
| /// Serialization constructor |
| /// </summary> |
| /// <param name="info">The <see cref="SerializationInfo" /> that holds the serialized object data.</param> |
| /// <param name="context">The <see cref="StreamingContext" /> that contains contextual information about the source or destination.</param> |
| /// <remarks> |
| /// <para> |
| /// Initializes a new instance of the <see cref="LoggingEvent" /> class |
| /// with serialized data. |
| /// </para> |
| /// </remarks> |
| protected LoggingEvent(SerializationInfo info, StreamingContext context) |
| { |
| m_data.LoggerName = info.GetString("LoggerName"); |
| |
| // Note we are deserializing the whole level object. That is the |
| // name and the value. This value is correct for the source |
| // hierarchy but may not be for the target hierarchy that this |
| // event may be re-logged into. If it is to be re-logged it may |
| // be necessary to re-lookup the level based only on the name. |
| m_data.Level = (Level)info.GetValue("Level", typeof(Level)); |
| |
| m_data.Message = info.GetString("Message"); |
| m_data.ThreadName = info.GetString("ThreadName"); |
| m_data.TimeStampUtc = info.GetDateTime("TimeStamp").ToUniversalTime(); |
| m_data.LocationInfo = (LocationInfo)info.GetValue("LocationInfo", typeof(LocationInfo)); |
| m_data.UserName = info.GetString("UserName"); |
| m_data.ExceptionString = info.GetString("ExceptionString"); |
| m_data.Properties = (PropertiesDictionary)info.GetValue("Properties", typeof(PropertiesDictionary)); |
| m_data.Domain = info.GetString("Domain"); |
| m_data.Identity = info.GetString("Identity"); |
| |
| // We have restored all the values of this instance, i.e. all the values are fixed |
| // Set the fix flags otherwise the data values may be overwritten from the current environment. |
| m_fixFlags = FixFlags.All; |
| } |
| |
| #endif |
| |
| #endregion Protected Instance Constructors |
| |
| #region Public Instance Properties |
| |
| /// <summary> |
| /// Gets the time when the current process started. |
| /// </summary> |
| /// <value> |
| /// This is the time when this process started. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The TimeStamp is stored internally in UTC and converted to the local time zone for this computer. |
| /// </para> |
| /// <para> |
| /// Tries to get the start time for the current process. |
| /// Failing that it returns the time of the first call to |
| /// this property. |
| /// </para> |
| /// <para> |
| /// Note that AppDomains may be loaded and unloaded within the |
| /// same process without the process terminating and therefore |
| /// without the process start time being reset. |
| /// </para> |
| /// </remarks> |
| public static DateTime StartTime |
| { |
| get { return SystemInfo.ProcessStartTimeUtc.ToLocalTime(); } |
| } |
| |
| /// <summary> |
| /// Gets the UTC time when the current process started. |
| /// </summary> |
| /// <value> |
| /// This is the UTC time when this process started. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Tries to get the start time for the current process. |
| /// Failing that it returns the time of the first call to |
| /// this property. |
| /// </para> |
| /// <para> |
| /// Note that AppDomains may be loaded and unloaded within the |
| /// same process without the process terminating and therefore |
| /// without the process start time being reset. |
| /// </para> |
| /// </remarks> |
| public static DateTime StartTimeUtc |
| { |
| get { return SystemInfo.ProcessStartTimeUtc; } |
| } |
| |
| /// <summary> |
| /// Gets the <see cref="Level" /> of the logging event. |
| /// </summary> |
| /// <value> |
| /// The <see cref="Level" /> of the logging event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets the <see cref="Level" /> of the logging event. |
| /// </para> |
| /// </remarks> |
| public Level Level |
| { |
| get { return m_data.Level; } |
| } |
| |
| /// <summary> |
| /// Gets the time of the logging event. |
| /// </summary> |
| /// <value> |
| /// The time of the logging event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The TimeStamp is stored in UTC and converted to the local time zone for this computer. |
| /// </para> |
| /// </remarks> |
| public DateTime TimeStamp |
| { |
| get { return m_data.TimeStampUtc.ToLocalTime(); } |
| } |
| |
| /// <summary> |
| /// Gets UTC the time of the logging event. |
| /// </summary> |
| /// <value> |
| /// The UTC time of the logging event. |
| /// </value> |
| public DateTime TimeStampUtc |
| { |
| get { return m_data.TimeStampUtc; } |
| } |
| |
| /// <summary> |
| /// Gets the name of the logger that logged the event. |
| /// </summary> |
| /// <value> |
| /// The name of the logger that logged the event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets the name of the logger that logged the event. |
| /// </para> |
| /// </remarks> |
| public string LoggerName |
| { |
| get { return m_data.LoggerName; } |
| } |
| |
| /// <summary> |
| /// Gets the location information for this logging event. |
| /// </summary> |
| /// <value> |
| /// The location information for this logging event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The collected information is cached for future use. |
| /// </para> |
| /// <para> |
| /// See the <see cref="LocationInfo"/> class for more information on |
| /// supported frameworks and the different behavior in Debug and |
| /// Release builds. |
| /// </para> |
| /// </remarks> |
| public LocationInfo LocationInformation |
| { |
| get |
| { |
| if (m_data.LocationInfo == null && this.m_cacheUpdatable) |
| { |
| m_data.LocationInfo = new LocationInfo(m_callerStackBoundaryDeclaringType); |
| } |
| |
| return m_data.LocationInfo; |
| } |
| } |
| |
| /// <summary> |
| /// Gets the message object used to initialize this event. |
| /// </summary> |
| /// <value> |
| /// The message object used to initialize this event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets the message object used to initialize this event. |
| /// Note that this event may not have a valid message object. |
| /// If the event is serialized the message object will not |
| /// be transferred. To get the text of the message the |
| /// <see cref="RenderedMessage"/> property must be used |
| /// not this property. |
| /// </para> |
| /// <para> |
| /// If there is no defined message object for this event then |
| /// null will be returned. |
| /// </para> |
| /// </remarks> |
| public object MessageObject |
| { |
| get { return m_message; } |
| protected set { m_message = value; } |
| } |
| |
| /// <summary> |
| /// Gets the exception object used to initialize this event. |
| /// </summary> |
| /// <value> |
| /// The exception object used to initialize this event. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets the exception object used to initialize this event. |
| /// Note that this event may not have a valid exception object. |
| /// If the event is serialized the exception object will not |
| /// be transferred. To get the text of the exception the |
| /// <see cref="GetExceptionString"/> method must be used |
| /// not this property. |
| /// </para> |
| /// <para> |
| /// If there is no defined exception object for this event then |
| /// null will be returned. |
| /// </para> |
| /// </remarks> |
| public Exception ExceptionObject |
| { |
| get { return m_thrownException; } |
| } |
| |
| /// <summary> |
| /// The <see cref="ILoggerRepository"/> that this event was created in. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The <see cref="ILoggerRepository"/> that this event was created in. |
| /// </para> |
| /// </remarks> |
| public ILoggerRepository Repository |
| { |
| get { return m_repository; } |
| } |
| |
| /// <summary> |
| /// Ensure that the repository is set. |
| /// </summary> |
| /// <param name="repository">the value for the repository</param> |
| internal void EnsureRepository(ILoggerRepository repository) |
| { |
| if (repository != null) |
| { |
| m_repository = repository; |
| } |
| } |
| |
| /// <summary> |
| /// Gets the message, rendered through the <see cref="ILoggerRepository.RendererMap" />. |
| /// </summary> |
| /// <value> |
| /// The message rendered through the <see cref="ILoggerRepository.RendererMap" />. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The collected information is cached for future use. |
| /// </para> |
| /// </remarks> |
| public virtual string RenderedMessage |
| { |
| get |
| { |
| if (m_data.Message == null && this.m_cacheUpdatable) |
| { |
| if (m_message == null) |
| { |
| m_data.Message = ""; |
| } |
| else if (m_message is string) |
| { |
| m_data.Message = (m_message as string); |
| } |
| else if (m_repository != null) |
| { |
| m_data.Message = m_repository.RendererMap.FindAndRender(m_message); |
| } |
| else |
| { |
| // Very last resort |
| m_data.Message = m_message.ToString(); |
| } |
| } |
| |
| return m_data.Message; |
| } |
| } |
| |
| /// <summary> |
| /// Write the rendered message to a TextWriter |
| /// </summary> |
| /// <param name="writer">the writer to write the message to</param> |
| /// <remarks> |
| /// <para> |
| /// Unlike the <see cref="RenderedMessage"/> property this method |
| /// does store the message data in the internal cache. Therefore |
| /// if called only once this method should be faster than the |
| /// <see cref="RenderedMessage"/> property, however if the message is |
| /// to be accessed multiple times then the property will be more efficient. |
| /// </para> |
| /// </remarks> |
| public virtual void WriteRenderedMessage(TextWriter writer) |
| { |
| if (m_data.Message != null) |
| { |
| writer.Write(m_data.Message); |
| } |
| else |
| { |
| if (m_message != null) |
| { |
| if (m_message is string) |
| { |
| writer.Write(m_message as string); |
| } |
| else if (m_repository != null) |
| { |
| m_repository.RendererMap.FindAndRender(m_message, writer); |
| } |
| else |
| { |
| // Very last resort |
| writer.Write(m_message.ToString()); |
| } |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Gets the name of the current thread. |
| /// </summary> |
| /// <value> |
| /// The name of the current thread, or the thread ID when |
| /// the name is not available. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The collected information is cached for future use. |
| /// </para> |
| /// </remarks> |
| public string ThreadName |
| { |
| get |
| { |
| if (m_data.ThreadName == null && this.m_cacheUpdatable) |
| { |
| #if NETCF |
| // Get thread ID only |
| m_data.ThreadName = |
| SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo.InvariantInfo); |
| #else |
| // '.NET ThreadPool Worker' appears as a default thread pool name in .NET 6+. |
| // Prefer the numeric thread ID instead. |
| string threadName = System.Threading.Thread.CurrentThread.Name; |
| if (!string.IsNullOrEmpty(threadName) && threadName != ".NET ThreadPool Worker") |
| { |
| m_data.ThreadName = threadName; |
| } |
| else |
| { |
| // The thread name is not available or unsuitable. Therefore we |
| // go the the AppDomain to get the ID of the |
| // current thread. (Why don't Threads know their own ID?) |
| try |
| { |
| m_data.ThreadName = |
| SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo |
| .InvariantInfo); |
| } |
| catch (SecurityException) |
| { |
| // This security exception will occur if the caller does not have |
| // some undefined set of SecurityPermission flags. |
| LogLog.Debug(declaringType, |
| "Security exception while trying to get current thread ID. Error Ignored. Empty thread name."); |
| |
| // As a last resort use the hash code of the Thread object |
| m_data.ThreadName = System.Threading.Thread.CurrentThread.GetHashCode() |
| .ToString(System.Globalization.CultureInfo.InvariantCulture); |
| } |
| } |
| #endif |
| } |
| |
| return m_data.ThreadName; |
| } |
| } |
| |
| /// <summary> |
| /// Gets the name of the current user. |
| /// </summary> |
| /// <value> |
| /// The name of the current user, or <c>NOT AVAILABLE</c> when the |
| /// underlying runtime has no support for retrieving the name of the |
| /// current user. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Calls <c>WindowsIdentity.GetCurrent().Name</c> to get the name of |
| /// the current windows user. |
| /// </para> |
| /// <para> |
| /// To improve performance, we could cache the string representation of |
| /// the name, and reuse that as long as the identity stayed constant. |
| /// Once the identity changed, we would need to re-assign and re-render |
| /// the string. |
| /// </para> |
| /// <para> |
| /// However, the <c>WindowsIdentity.GetCurrent()</c> call seems to |
| /// return different objects every time, so the current implementation |
| /// doesn't do this type of caching. |
| /// </para> |
| /// <para> |
| /// Timing for these operations: |
| /// </para> |
| /// <list type="table"> |
| /// <listheader> |
| /// <term>Method</term> |
| /// <description>Results</description> |
| /// </listheader> |
| /// <item> |
| /// <term><c>WindowsIdentity.GetCurrent()</c></term> |
| /// <description>10000 loops, 00:00:00.2031250 seconds</description> |
| /// </item> |
| /// <item> |
| /// <term><c>WindowsIdentity.GetCurrent().Name</c></term> |
| /// <description>10000 loops, 00:00:08.0468750 seconds</description> |
| /// </item> |
| /// </list> |
| /// <para> |
| /// This means we could speed things up almost 40 times by caching the |
| /// value of the <c>WindowsIdentity.GetCurrent().Name</c> property, since |
| /// this takes (8.04-0.20) = 7.84375 seconds. |
| /// </para> |
| /// </remarks> |
| public string UserName => |
| m_data.UserName ??= TryGetCurrentUserName() ?? SystemInfo.NotAvailableText; |
| |
| private string TryGetCurrentUserName() |
| { |
| #if (NETCF || SSCLI || NETSTANDARD1_3) |
| // On compact framework there's no notion of current Windows user |
| return SystemInfo.NotAvailableText; |
| #else |
| if (_platformDoesNotSupportWindowsIdentity) |
| { |
| // we've already received one PlatformNotSupportedException |
| // and it's highly unlikely that will change |
| return Environment.UserName; |
| } |
| |
| try |
| { |
| return _cachedWindowsIdentityUserName ??= |
| TryReadWindowsIdentityUserName(); |
| } |
| catch (PlatformNotSupportedException) |
| { |
| _platformDoesNotSupportWindowsIdentity = true; |
| return Environment.UserName; |
| } |
| catch (SecurityException) |
| { |
| // This security exception will occur if the caller does not have |
| // some undefined set of SecurityPermission flags. |
| LogLog.Debug( |
| declaringType, |
| "Security exception while trying to get current windows identity. Error Ignored." |
| ); |
| return Environment.UserName; |
| } |
| catch |
| { |
| return null; |
| } |
| #endif |
| } |
| |
| #if (NETCF || SSCLI || NETSTANDARD1_3) |
| #else |
| private string _cachedWindowsIdentityUserName; |
| private static string TryReadWindowsIdentityUserName() |
| { |
| using var identity = WindowsIdentity.GetCurrent(); |
| return identity?.Name ?? ""; |
| } |
| #endif |
| |
| #if (NETCF || SSCLI || NETSTANDARD1_3) |
| #else |
| private static bool _platformDoesNotSupportWindowsIdentity; |
| #endif |
| |
| /// <summary> |
| /// Gets the identity of the current thread principal. |
| /// </summary> |
| /// <value> |
| /// The string name of the identity of the current thread principal. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Calls <c>System.Threading.Thread.CurrentPrincipal.Identity.Name</c> to get |
| /// the name of the current thread principal. |
| /// </para> |
| /// </remarks> |
| public string Identity |
| { |
| get |
| { |
| if (m_data.Identity == null && this.m_cacheUpdatable) |
| { |
| #if (NETCF || SSCLI || NETSTANDARD1_3) |
| // On compact framework there's no notion of current thread principals |
| m_data.Identity = SystemInfo.NotAvailableText; |
| #else |
| try |
| { |
| if (System.Threading.Thread.CurrentPrincipal != null && |
| System.Threading.Thread.CurrentPrincipal.Identity != null && |
| System.Threading.Thread.CurrentPrincipal.Identity.Name != null) |
| { |
| m_data.Identity = System.Threading.Thread.CurrentPrincipal.Identity.Name; |
| } |
| else |
| { |
| m_data.Identity = ""; |
| } |
| } |
| catch (ObjectDisposedException) |
| { |
| // This exception will occur if System.Threading.Thread.CurrentPrincipal.Identity is not null but |
| // the getter of the property Name tries to access disposed objects. |
| // Seen to happen on IIS 7 or greater with windows authentication. |
| LogLog.Debug(declaringType, |
| "Object disposed exception while trying to get current thread principal. Error Ignored. Empty identity name."); |
| |
| m_data.Identity = ""; |
| } |
| catch (System.Security.SecurityException) |
| { |
| // This security exception will occur if the caller does not have |
| // some undefined set of SecurityPermission flags. |
| LogLog.Debug(declaringType, |
| "Security exception while trying to get current thread principal. Error Ignored. Empty identity name."); |
| |
| m_data.Identity = ""; |
| } |
| #endif |
| } |
| |
| return m_data.Identity; |
| } |
| } |
| |
| /// <summary> |
| /// Gets the AppDomain friendly name. |
| /// </summary> |
| /// <value> |
| /// The AppDomain friendly name. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Gets the AppDomain friendly name. |
| /// </para> |
| /// </remarks> |
| public string Domain |
| { |
| get |
| { |
| if (m_data.Domain == null && this.m_cacheUpdatable) |
| { |
| m_data.Domain = SystemInfo.ApplicationFriendlyName; |
| } |
| |
| return m_data.Domain; |
| } |
| } |
| |
| /// <summary> |
| /// Additional event specific properties. |
| /// </summary> |
| /// <value> |
| /// Additional event specific properties. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// A logger or an appender may attach additional |
| /// properties to specific events. These properties |
| /// have a string key and an object value. |
| /// </para> |
| /// <para> |
| /// This property is for events that have been added directly to |
| /// this event. The aggregate properties (which include these |
| /// event properties) can be retrieved using <see cref="LookupProperty"/> |
| /// and <see cref="GetProperties"/>. |
| /// </para> |
| /// <para> |
| /// Once the properties have been fixed <see cref="Fix"/> this property |
| /// returns the combined cached properties. This ensures that updates to |
| /// this property are always reflected in the underlying storage. When |
| /// returning the combined properties there may be more keys in the |
| /// Dictionary than expected. |
| /// </para> |
| /// </remarks> |
| public PropertiesDictionary Properties |
| { |
| get |
| { |
| // If we have cached properties then return that otherwise changes will be lost |
| if (m_data.Properties != null) |
| { |
| return m_data.Properties; |
| } |
| |
| if (m_eventProperties == null) |
| { |
| m_eventProperties = new PropertiesDictionary(); |
| } |
| |
| return m_eventProperties; |
| } |
| } |
| |
| /// <summary> |
| /// The fixed fields in this event |
| /// </summary> |
| /// <value> |
| /// The set of fields that are fixed in this event |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Fields will not be fixed if they have previously been fixed. |
| /// It is not possible to 'unfix' a field. |
| /// </para> |
| /// </remarks> |
| public FixFlags Fix |
| { |
| get { return m_fixFlags; } |
| set { this.FixVolatileData(value); } |
| } |
| |
| #endregion Public Instance Properties |
| |
| #region Implementation of ISerializable |
| |
| #if !NETCF |
| |
| /// <summary> |
| /// Serializes this object into the <see cref="SerializationInfo" /> provided. |
| /// </summary> |
| /// <param name="info">The <see cref="SerializationInfo" /> to populate with data.</param> |
| /// <param name="context">The destination for this serialization.</param> |
| /// <remarks> |
| /// <para> |
| /// The data in this event must be fixed before it can be serialized. |
| /// </para> |
| /// <para> |
| /// The <see cref="M:FixVolatileData()"/> method must be called during the |
| /// <see cref="log4net.Appender.IAppender.DoAppend"/> method call if this event |
| /// is to be used outside that method. |
| /// </para> |
| /// </remarks> |
| #if NET_4_0 || MONO_4_0 || NETSTANDARD |
| [System.Security.SecurityCritical] |
| #endif |
| #if !NETCF && !NETSTANDARD1_3 |
| [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, |
| SerializationFormatter = true)] |
| #endif |
| public virtual void GetObjectData(SerializationInfo info, StreamingContext context) |
| { |
| // The caller must call FixVolatileData before this object |
| // can be serialized. |
| |
| info.AddValue("LoggerName", m_data.LoggerName); |
| info.AddValue("Level", m_data.Level); |
| info.AddValue("Message", m_data.Message); |
| info.AddValue("ThreadName", m_data.ThreadName); |
| // TODO: consider serializing UTC rather than local time. Not implemented here because it |
| // would give an unexpected result if client and server have different versions of this class. |
| // info.AddValue("TimeStamp", m_data.TimeStampUtc); |
| #pragma warning disable 618 |
| info.AddValue("TimeStamp", m_data.TimeStamp); |
| #pragma warning restore 618 |
| info.AddValue("LocationInfo", m_data.LocationInfo); |
| info.AddValue("UserName", m_data.UserName); |
| info.AddValue("ExceptionString", m_data.ExceptionString); |
| info.AddValue("Properties", m_data.Properties); |
| info.AddValue("Domain", m_data.Domain); |
| info.AddValue("Identity", m_data.Identity); |
| } |
| |
| #endif |
| |
| #endregion Implementation of ISerializable |
| |
| #region Public Instance Methods |
| |
| /// <summary> |
| /// Gets the portable data for this <see cref="LoggingEvent" />. |
| /// </summary> |
| /// <returns>The <see cref="LoggingEventData"/> for this event.</returns> |
| /// <remarks> |
| /// <para> |
| /// A new <see cref="LoggingEvent"/> can be constructed using a |
| /// <see cref="LoggingEventData"/> instance. |
| /// </para> |
| /// <para> |
| /// Does a <see cref="FixFlags.Partial"/> fix of the data |
| /// in the logging event before returning the event data. |
| /// </para> |
| /// </remarks> |
| public LoggingEventData GetLoggingEventData() |
| { |
| return GetLoggingEventData(FixFlags.Partial); |
| } |
| |
| /// <summary> |
| /// Gets the portable data for this <see cref="LoggingEvent" />. |
| /// </summary> |
| /// <param name="fixFlags">The set of data to ensure is fixed in the LoggingEventData</param> |
| /// <returns>The <see cref="LoggingEventData"/> for this event.</returns> |
| /// <remarks> |
| /// <para> |
| /// A new <see cref="LoggingEvent"/> can be constructed using a |
| /// <see cref="LoggingEventData"/> instance. |
| /// </para> |
| /// </remarks> |
| public LoggingEventData GetLoggingEventData(FixFlags fixFlags) |
| { |
| Fix = fixFlags; |
| return m_data; |
| } |
| |
| /// <summary> |
| /// Returns this event's exception's rendered using the |
| /// <see cref="ILoggerRepository.RendererMap" />. |
| /// </summary> |
| /// <returns> |
| /// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />. |
| /// </returns> |
| /// <remarks> |
| /// <para> |
| /// <b>Obsolete. Use <see cref="GetExceptionString"/> instead.</b> |
| /// </para> |
| /// </remarks> |
| [Obsolete("Use GetExceptionString instead")] |
| public string GetExceptionStrRep() |
| { |
| return GetExceptionString(); |
| } |
| |
| /// <summary> |
| /// Returns this event's exception's rendered using the |
| /// <see cref="ILoggerRepository.RendererMap" />. |
| /// </summary> |
| /// <returns> |
| /// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />. |
| /// </returns> |
| /// <remarks> |
| /// <para> |
| /// Returns this event's exception's rendered using the |
| /// <see cref="ILoggerRepository.RendererMap" />. |
| /// </para> |
| /// </remarks> |
| public string GetExceptionString() |
| { |
| if (m_data.ExceptionString == null && this.m_cacheUpdatable) |
| { |
| if (m_thrownException != null) |
| { |
| if (m_repository != null) |
| { |
| // Render exception using the repositories renderer map |
| m_data.ExceptionString = m_repository.RendererMap.FindAndRender(m_thrownException); |
| } |
| else |
| { |
| // Very last resort |
| m_data.ExceptionString = m_thrownException.ToString(); |
| } |
| } |
| else |
| { |
| m_data.ExceptionString = ""; |
| } |
| } |
| |
| return m_data.ExceptionString; |
| } |
| |
| /// <summary> |
| /// Fix instance fields that hold volatile data. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Some of the values in instances of <see cref="LoggingEvent"/> |
| /// are considered volatile, that is the values are correct at the |
| /// time the event is delivered to appenders, but will not be consistent |
| /// at any time afterwards. If an event is to be stored and then processed |
| /// at a later time these volatile values must be fixed by calling |
| /// <see cref="M:FixVolatileData()"/>. There is a performance penalty |
| /// incurred by calling <see cref="M:FixVolatileData()"/> but it |
| /// is essential to maintaining data consistency. |
| /// </para> |
| /// <para> |
| /// Calling <see cref="M:FixVolatileData()"/> is equivalent to |
| /// calling <see cref="M:FixVolatileData(bool)"/> passing the parameter |
| /// <c>false</c>. |
| /// </para> |
| /// <para> |
| /// See <see cref="M:FixVolatileData(bool)"/> for more |
| /// information. |
| /// </para> |
| /// </remarks> |
| [Obsolete("Use Fix property")] |
| public void FixVolatileData() |
| { |
| Fix = FixFlags.All; |
| } |
| |
| /// <summary> |
| /// Fixes instance fields that hold volatile data. |
| /// </summary> |
| /// <param name="fastButLoose">Set to <c>true</c> to not fix data that takes a long time to fix.</param> |
| /// <remarks> |
| /// <para> |
| /// Some of the values in instances of <see cref="LoggingEvent"/> |
| /// are considered volatile, that is the values are correct at the |
| /// time the event is delivered to appenders, but will not be consistent |
| /// at any time afterwards. If an event is to be stored and then processed |
| /// at a later time these volatile values must be fixed by calling |
| /// <see cref="M:FixVolatileData()"/>. There is a performance penalty |
| /// for incurred by calling <see cref="M:FixVolatileData()"/> but it |
| /// is essential to maintaining data consistency. |
| /// </para> |
| /// <para> |
| /// The <paramref name="fastButLoose"/> param controls the data that |
| /// is fixed. Some of the data that can be fixed takes a long time to |
| /// generate, therefore if you do not require those settings to be fixed |
| /// they can be ignored by setting the <paramref name="fastButLoose"/> param |
| /// to <c>true</c>. This setting will ignore the <see cref="LocationInformation"/> |
| /// and <see cref="UserName"/> settings. |
| /// </para> |
| /// <para> |
| /// Set <paramref name="fastButLoose"/> to <c>false</c> to ensure that all |
| /// settings are fixed. |
| /// </para> |
| /// </remarks> |
| [Obsolete("Use Fix property")] |
| public void FixVolatileData(bool fastButLoose) |
| { |
| if (fastButLoose) |
| { |
| Fix = FixFlags.Partial; |
| } |
| else |
| { |
| Fix = FixFlags.All; |
| } |
| } |
| |
| /// <summary> |
| /// Fix the fields specified by the <see cref="FixFlags"/> parameter |
| /// </summary> |
| /// <param name="flags">the fields to fix</param> |
| /// <remarks> |
| /// <para> |
| /// Only fields specified in the <paramref name="flags"/> will be fixed. |
| /// Fields will not be fixed if they have previously been fixed. |
| /// It is not possible to 'unfix' a field. |
| /// </para> |
| /// </remarks> |
| protected virtual void FixVolatileData(FixFlags flags) |
| { |
| object forceCreation = null; |
| |
| //Unlock the cache so that new values can be stored |
| //This may not be ideal if we are no longer in the correct context |
| //and someone calls fix. |
| m_cacheUpdatable = true; |
| |
| // determine the flags that we are actually fixing |
| var updateFlags = (FixFlags)((flags ^ m_fixFlags) & flags); |
| |
| if (updateFlags > 0) |
| { |
| if ((updateFlags & FixFlags.Message) != 0) |
| { |
| // Force the message to be rendered |
| forceCreation = this.RenderedMessage; |
| |
| m_fixFlags |= FixFlags.Message; |
| } |
| |
| if ((updateFlags & FixFlags.ThreadName) != 0) |
| { |
| // Grab the thread name |
| forceCreation = this.ThreadName; |
| |
| m_fixFlags |= FixFlags.ThreadName; |
| } |
| |
| if ((updateFlags & FixFlags.LocationInfo) != 0) |
| { |
| // Force the location information to be loaded |
| forceCreation = this.LocationInformation; |
| |
| m_fixFlags |= FixFlags.LocationInfo; |
| } |
| |
| if ((updateFlags & FixFlags.UserName) != 0) |
| { |
| // Grab the user name |
| forceCreation = this.UserName; |
| |
| m_fixFlags |= FixFlags.UserName; |
| } |
| |
| if ((updateFlags & FixFlags.Domain) != 0) |
| { |
| // Grab the domain name |
| forceCreation = this.Domain; |
| |
| m_fixFlags |= FixFlags.Domain; |
| } |
| |
| if ((updateFlags & FixFlags.Identity) != 0) |
| { |
| // Grab the identity |
| forceCreation = this.Identity; |
| |
| m_fixFlags |= FixFlags.Identity; |
| } |
| |
| if ((updateFlags & FixFlags.Exception) != 0) |
| { |
| // Force the exception text to be loaded |
| forceCreation = GetExceptionString(); |
| |
| m_fixFlags |= FixFlags.Exception; |
| } |
| |
| if ((updateFlags & FixFlags.Properties) != 0) |
| { |
| CacheProperties(); |
| |
| m_fixFlags |= FixFlags.Properties; |
| } |
| } |
| |
| // avoid warning CS0219 |
| if (forceCreation != null) |
| { |
| } |
| |
| //Finaly lock everything we've cached. |
| m_cacheUpdatable = false; |
| } |
| |
| #endregion Public Instance Methods |
| |
| #region Protected Instance Methods |
| |
| private void CreateCompositeProperties() |
| { |
| var compositeProperties = new CompositeProperties(); |
| |
| if (m_eventProperties != null) |
| { |
| compositeProperties.Add(m_eventProperties); |
| } |
| #if !NETCF |
| var logicalThreadProperties = LogicalThreadContext.Properties.GetProperties(false); |
| if (logicalThreadProperties != null) |
| { |
| compositeProperties.Add(logicalThreadProperties); |
| } |
| #endif |
| var threadProperties = ThreadContext.Properties.GetProperties(false); |
| if (threadProperties != null) |
| { |
| compositeProperties.Add(threadProperties); |
| } |
| |
| // TODO: Add Repository Properties |
| |
| // event properties |
| var shouldFixUserName = (m_fixFlags & FixFlags.UserName) != 0; |
| var shouldFixIdentity = (m_fixFlags & FixFlags.Identity) != 0; |
| if (shouldFixIdentity || shouldFixUserName) |
| { |
| var eventProperties = new PropertiesDictionary(); |
| if (shouldFixUserName) |
| { |
| eventProperties[UserNameProperty] = UserName; |
| } |
| |
| if (shouldFixIdentity) |
| { |
| eventProperties[IdentityProperty] = Identity; |
| } |
| |
| compositeProperties.Add(eventProperties); |
| } |
| |
| compositeProperties.Add(GlobalContext.Properties.GetReadOnlyProperties()); |
| m_compositeProperties = compositeProperties; |
| } |
| |
| private void CacheProperties() |
| { |
| if (m_data.Properties == null && this.m_cacheUpdatable) |
| { |
| if (m_compositeProperties == null) |
| { |
| CreateCompositeProperties(); |
| } |
| |
| var flattenedProperties = m_compositeProperties.Flatten(); |
| |
| var fixedProperties = new PropertiesDictionary(); |
| |
| // Validate properties |
| foreach (DictionaryEntry entry in flattenedProperties) |
| { |
| var key = entry.Key as string; |
| |
| if (key != null) |
| { |
| var val = entry.Value; |
| |
| // Fix any IFixingRequired objects |
| var fixingRequired = val as IFixingRequired; |
| if (fixingRequired != null) |
| { |
| val = fixingRequired.GetFixedObject(); |
| } |
| |
| // Strip keys with null values |
| if (val != null) |
| { |
| fixedProperties[key] = val; |
| } |
| } |
| } |
| |
| m_data.Properties = fixedProperties; |
| } |
| } |
| |
| /// <summary> |
| /// Lookup a composite property in this event |
| /// </summary> |
| /// <param name="key">the key for the property to lookup</param> |
| /// <returns>the value for the property</returns> |
| /// <remarks> |
| /// <para> |
| /// This event has composite properties that combine together properties from |
| /// several different contexts in the following order: |
| /// <list type="definition"> |
| /// <item> |
| /// <term>this events properties</term> |
| /// <description> |
| /// This event has <see cref="Properties"/> that can be set. These |
| /// properties are specific to this event only. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>the thread properties</term> |
| /// <description> |
| /// The <see cref="ThreadContext.Properties"/> that are set on the current |
| /// thread. These properties are shared by all events logged on this thread. |
| /// </description> |
| /// </item> |
| /// <item> |
| /// <term>the global properties</term> |
| /// <description> |
| /// The <see cref="GlobalContext.Properties"/> that are set globally. These |
| /// properties are shared by all the threads in the AppDomain. |
| /// </description> |
| /// </item> |
| /// </list> |
| /// </para> |
| /// </remarks> |
| public object LookupProperty(string key) |
| { |
| if (m_data.Properties != null) |
| { |
| return m_data.Properties[key]; |
| } |
| |
| if (m_compositeProperties == null) |
| { |
| CreateCompositeProperties(); |
| } |
| |
| return m_compositeProperties[key]; |
| } |
| |
| /// <summary> |
| /// Get all the composite properties in this event |
| /// </summary> |
| /// <returns>the <see cref="PropertiesDictionary"/> containing all the properties</returns> |
| /// <remarks> |
| /// <para> |
| /// See <see cref="LookupProperty"/> for details of the composite properties |
| /// stored by the event. |
| /// </para> |
| /// <para> |
| /// This method returns a single <see cref="PropertiesDictionary"/> containing all the |
| /// properties defined for this event. |
| /// </para> |
| /// </remarks> |
| public PropertiesDictionary GetProperties() |
| { |
| if (m_data.Properties != null) |
| { |
| return m_data.Properties; |
| } |
| |
| if (m_compositeProperties == null) |
| { |
| CreateCompositeProperties(); |
| } |
| |
| return m_compositeProperties.Flatten(); |
| } |
| |
| #endregion Public Instance Methods |
| |
| #region Private Instance Fields |
| |
| /// <summary> |
| /// The internal logging event data. |
| /// </summary> |
| private LoggingEventData m_data; |
| |
| /// <summary> |
| /// The internal logging event data. |
| /// </summary> |
| private CompositeProperties m_compositeProperties; |
| |
| /// <summary> |
| /// The internal logging event data. |
| /// </summary> |
| private PropertiesDictionary m_eventProperties; |
| |
| /// <summary> |
| /// The fully qualified Type of the calling |
| /// logger class in the stack frame (i.e. the declaring type of the method). |
| /// </summary> |
| private readonly Type m_callerStackBoundaryDeclaringType; |
| |
| /// <summary> |
| /// The application supplied message of logging event. |
| /// </summary> |
| private object m_message; |
| |
| /// <summary> |
| /// The exception that was thrown. |
| /// </summary> |
| /// <remarks> |
| /// This is not serialized. The string representation |
| /// is serialized instead. |
| /// </remarks> |
| private readonly Exception m_thrownException; |
| |
| /// <summary> |
| /// The repository that generated the logging event |
| /// </summary> |
| /// <remarks> |
| /// This is not serialized. |
| /// </remarks> |
| private ILoggerRepository m_repository = null; |
| |
| /// <summary> |
| /// The fix state for this event |
| /// </summary> |
| /// <remarks> |
| /// These flags indicate which fields have been fixed. |
| /// Not serialized. |
| /// </remarks> |
| private FixFlags m_fixFlags = FixFlags.None; |
| |
| /// <summary> |
| /// Indicated that the internal cache is updateable (ie not fixed) |
| /// </summary> |
| /// <remarks> |
| /// This is a seperate flag to m_fixFlags as it allows incrementel fixing and simpler |
| /// changes in the caching strategy. |
| /// </remarks> |
| private bool m_cacheUpdatable = true; |
| |
| #endregion Private Instance Fields |
| |
| #region Constants |
| |
| /// <summary> |
| /// The key into the Properties map for the host name value. |
| /// </summary> |
| public const string HostNameProperty = "log4net:HostName"; |
| |
| /// <summary> |
| /// The key into the Properties map for the thread identity value. |
| /// </summary> |
| public const string IdentityProperty = "log4net:Identity"; |
| |
| /// <summary> |
| /// The key into the Properties map for the user name value. |
| /// </summary> |
| public const string UserNameProperty = "log4net:UserName"; |
| |
| #endregion |
| } |
| } |