| #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 log4net.ObjectRenderer; |
| using log4net.Core; |
| using log4net.Util; |
| using log4net.Plugin; |
| using System.Threading; |
| |
| namespace log4net.Repository |
| { |
| /// <summary> |
| /// Base implementation of <see cref="ILoggerRepository"/> |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Default abstract implementation of the <see cref="ILoggerRepository"/> interface. |
| /// </para> |
| /// <para> |
| /// Skeleton implementation of the <see cref="ILoggerRepository"/> interface. |
| /// All <see cref="ILoggerRepository"/> types can extend this type. |
| /// </para> |
| /// </remarks> |
| /// <author>Nicko Cadell</author> |
| /// <author>Gert Driesen</author> |
| public abstract class LoggerRepositorySkeleton : ILoggerRepository, Appender.IFlushable |
| { |
| #region Member Variables |
| |
| private string m_name; |
| private RendererMap m_rendererMap; |
| private PluginMap m_pluginMap; |
| private LevelMap m_levelMap; |
| private Level m_threshold; |
| private bool m_configured; |
| private ICollection m_configurationMessages; |
| private event LoggerRepositoryShutdownEventHandler m_shutdownEvent; |
| private event LoggerRepositoryConfigurationResetEventHandler m_configurationResetEvent; |
| private event LoggerRepositoryConfigurationChangedEventHandler m_configurationChangedEvent; |
| private PropertiesDictionary m_properties; |
| |
| #endregion |
| |
| #region Constructors |
| |
| /// <summary> |
| /// Default Constructor |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Initializes the repository with default (empty) properties. |
| /// </para> |
| /// </remarks> |
| protected LoggerRepositorySkeleton() : this(new PropertiesDictionary()) |
| { |
| } |
| |
| /// <summary> |
| /// Construct the repository using specific properties |
| /// </summary> |
| /// <param name="properties">the properties to set for this repository</param> |
| /// <remarks> |
| /// <para> |
| /// Initializes the repository with specified properties. |
| /// </para> |
| /// </remarks> |
| protected LoggerRepositorySkeleton(PropertiesDictionary properties) |
| { |
| m_properties = properties; |
| m_rendererMap = new RendererMap(); |
| m_pluginMap = new PluginMap(this); |
| m_levelMap = new LevelMap(); |
| m_configurationMessages = EmptyCollection.Instance; |
| m_configured = false; |
| |
| AddBuiltinLevels(); |
| |
| // Don't disable any levels by default. |
| m_threshold = Level.All; |
| } |
| |
| #endregion |
| |
| #region Implementation of ILoggerRepository |
| |
| /// <summary> |
| /// The name of the repository |
| /// </summary> |
| /// <value> |
| /// The string name of the repository |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The name of this repository. The name is |
| /// used to store and lookup the repositories |
| /// stored by the <see cref="IRepositorySelector"/>. |
| /// </para> |
| /// </remarks> |
| virtual public string Name |
| { |
| get { return m_name; } |
| set { m_name = value; } |
| } |
| |
| /// <summary> |
| /// The threshold for all events in this repository |
| /// </summary> |
| /// <value> |
| /// The threshold for all events in this repository |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The threshold for all events in this repository |
| /// </para> |
| /// </remarks> |
| virtual public Level Threshold |
| { |
| get { return m_threshold; } |
| set |
| { |
| if (value != null) |
| { |
| m_threshold = value; |
| } |
| else |
| { |
| // Must not set threshold to null |
| LogLog.Warn(declaringType, "LoggerRepositorySkeleton: Threshold cannot be set to null. Setting to ALL"); |
| m_threshold = Level.All; |
| } |
| } |
| } |
| |
| /// <summary> |
| /// RendererMap accesses the object renderer map for this repository. |
| /// </summary> |
| /// <value> |
| /// RendererMap accesses the object renderer map for this repository. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// RendererMap accesses the object renderer map for this repository. |
| /// </para> |
| /// <para> |
| /// The RendererMap holds a mapping between types and |
| /// <see cref="IObjectRenderer"/> objects. |
| /// </para> |
| /// </remarks> |
| virtual public RendererMap RendererMap |
| { |
| get { return m_rendererMap; } |
| } |
| |
| /// <summary> |
| /// The plugin map for this repository. |
| /// </summary> |
| /// <value> |
| /// The plugin map for this repository. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// The plugin map holds the <see cref="IPlugin"/> instances |
| /// that have been attached to this repository. |
| /// </para> |
| /// </remarks> |
| virtual public PluginMap PluginMap |
| { |
| get { return m_pluginMap; } |
| } |
| |
| /// <summary> |
| /// Get the level map for the Repository. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Get the level map for the Repository. |
| /// </para> |
| /// <para> |
| /// The level map defines the mappings between |
| /// level names and <see cref="Level"/> objects in |
| /// this repository. |
| /// </para> |
| /// </remarks> |
| virtual public LevelMap LevelMap |
| { |
| get { return m_levelMap; } |
| } |
| |
| /// <summary> |
| /// Test if logger exists |
| /// </summary> |
| /// <param name="name">The name of the logger to lookup</param> |
| /// <returns>The Logger object with the name specified</returns> |
| /// <remarks> |
| /// <para> |
| /// Check if the named logger exists in the repository. If so return |
| /// its reference, otherwise returns <c>null</c>. |
| /// </para> |
| /// </remarks> |
| abstract public ILogger Exists(string name); |
| |
| /// <summary> |
| /// Returns all the currently defined loggers in the repository |
| /// </summary> |
| /// <returns>All the defined loggers</returns> |
| /// <remarks> |
| /// <para> |
| /// Returns all the currently defined loggers in the repository as an Array. |
| /// </para> |
| /// </remarks> |
| abstract public ILogger[] GetCurrentLoggers(); |
| |
| /// <summary> |
| /// Return a new logger instance |
| /// </summary> |
| /// <param name="name">The name of the logger to retrieve</param> |
| /// <returns>The logger object with the name specified</returns> |
| /// <remarks> |
| /// <para> |
| /// Return a new logger instance. |
| /// </para> |
| /// <para> |
| /// If a logger of that name already exists, then it will be |
| /// returned. Otherwise, a new logger will be instantiated and |
| /// then linked with its existing ancestors as well as children. |
| /// </para> |
| /// </remarks> |
| abstract public ILogger GetLogger(string name); |
| |
| /// <summary> |
| /// Shutdown the repository |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Shutdown the repository. Can be overridden in a subclass. |
| /// This base class implementation notifies the <see cref="ShutdownEvent"/> |
| /// listeners and all attached plugins of the shutdown event. |
| /// </para> |
| /// </remarks> |
| virtual public void Shutdown() |
| { |
| // Shutdown attached plugins |
| foreach(IPlugin plugin in PluginMap.AllPlugins) |
| { |
| plugin.Shutdown(); |
| } |
| |
| // Notify listeners |
| OnShutdown(null); |
| } |
| |
| /// <summary> |
| /// Reset the repositories configuration to a default state |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Reset all values contained in this instance to their |
| /// default state. |
| /// </para> |
| /// <para> |
| /// Existing loggers are not removed. They are just reset. |
| /// </para> |
| /// <para> |
| /// This method should be used sparingly and with care as it will |
| /// block all logging until it is completed. |
| /// </para> |
| /// </remarks> |
| virtual public void ResetConfiguration() |
| { |
| // Clear internal data structures |
| m_rendererMap.Clear(); |
| m_levelMap.Clear(); |
| m_configurationMessages = EmptyCollection.Instance; |
| |
| // Add the predefined levels to the map |
| AddBuiltinLevels(); |
| |
| Configured = false; |
| |
| // Notify listeners |
| OnConfigurationReset(null); |
| } |
| |
| /// <summary> |
| /// Log the logEvent through this repository. |
| /// </summary> |
| /// <param name="logEvent">the event to log</param> |
| /// <remarks> |
| /// <para> |
| /// This method should not normally be used to log. |
| /// The <see cref="ILog"/> interface should be used |
| /// for routine logging. This interface can be obtained |
| /// using the <see cref="M:log4net.LogManager.GetLogger(string)"/> method. |
| /// </para> |
| /// <para> |
| /// The <c>logEvent</c> is delivered to the appropriate logger and |
| /// that logger is then responsible for logging the event. |
| /// </para> |
| /// </remarks> |
| abstract public void Log(LoggingEvent logEvent); |
| |
| /// <summary> |
| /// Flag indicates if this repository has been configured. |
| /// </summary> |
| /// <value> |
| /// Flag indicates if this repository has been configured. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Flag indicates if this repository has been configured. |
| /// </para> |
| /// </remarks> |
| virtual public bool Configured |
| { |
| get { return m_configured; } |
| set { m_configured = value; } |
| } |
| |
| /// <summary> |
| /// Contains a list of internal messages captures during the |
| /// last configuration. |
| /// </summary> |
| virtual public ICollection ConfigurationMessages |
| { |
| get { return m_configurationMessages; } |
| set { m_configurationMessages = value; } |
| } |
| |
| /// <summary> |
| /// Event to notify that the repository has been shutdown. |
| /// </summary> |
| /// <value> |
| /// Event to notify that the repository has been shutdown. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Event raised when the repository has been shutdown. |
| /// </para> |
| /// </remarks> |
| public event LoggerRepositoryShutdownEventHandler ShutdownEvent |
| { |
| add { m_shutdownEvent += value; } |
| remove { m_shutdownEvent -= value; } |
| } |
| |
| /// <summary> |
| /// Event to notify that the repository has had its configuration reset. |
| /// </summary> |
| /// <value> |
| /// Event to notify that the repository has had its configuration reset. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Event raised when the repository's configuration has been |
| /// reset to default. |
| /// </para> |
| /// </remarks> |
| public event LoggerRepositoryConfigurationResetEventHandler ConfigurationReset |
| { |
| add { m_configurationResetEvent += value; } |
| remove { m_configurationResetEvent -= value; } |
| } |
| |
| /// <summary> |
| /// Event to notify that the repository has had its configuration changed. |
| /// </summary> |
| /// <value> |
| /// Event to notify that the repository has had its configuration changed. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Event raised when the repository's configuration has been changed. |
| /// </para> |
| /// </remarks> |
| public event LoggerRepositoryConfigurationChangedEventHandler ConfigurationChanged |
| { |
| add { m_configurationChangedEvent += value; } |
| remove { m_configurationChangedEvent -= value; } |
| } |
| |
| /// <summary> |
| /// Repository specific properties |
| /// </summary> |
| /// <value> |
| /// Repository specific properties |
| /// </value> |
| /// <remarks> |
| /// These properties can be specified on a repository specific basis |
| /// </remarks> |
| public PropertiesDictionary Properties |
| { |
| get { return m_properties; } |
| } |
| |
| /// <summary> |
| /// Returns all the Appenders that are configured as an Array. |
| /// </summary> |
| /// <returns>All the Appenders</returns> |
| /// <remarks> |
| /// <para> |
| /// Returns all the Appenders that are configured as an Array. |
| /// </para> |
| /// </remarks> |
| abstract public log4net.Appender.IAppender[] GetAppenders(); |
| |
| #endregion |
| |
| #region Private Static Fields |
| |
| /// <summary> |
| /// The fully qualified type of the LoggerRepositorySkeleton class. |
| /// </summary> |
| /// <remarks> |
| /// Used by the internal logger to record the Type of the |
| /// log message. |
| /// </remarks> |
| private readonly static Type declaringType = typeof(LoggerRepositorySkeleton); |
| |
| #endregion Private Static Fields |
| |
| private void AddBuiltinLevels() |
| { |
| // Add the predefined levels to the map |
| m_levelMap.Add(Level.Off); |
| |
| // Unrecoverable errors |
| m_levelMap.Add(Level.Emergency); |
| m_levelMap.Add(Level.Fatal); |
| m_levelMap.Add(Level.Alert); |
| |
| // Recoverable errors |
| m_levelMap.Add(Level.Critical); |
| m_levelMap.Add(Level.Severe); |
| m_levelMap.Add(Level.Error); |
| m_levelMap.Add(Level.Warn); |
| |
| // Information |
| m_levelMap.Add(Level.Notice); |
| m_levelMap.Add(Level.Info); |
| |
| // Debug |
| m_levelMap.Add(Level.Debug); |
| m_levelMap.Add(Level.Fine); |
| m_levelMap.Add(Level.Trace); |
| m_levelMap.Add(Level.Finer); |
| m_levelMap.Add(Level.Verbose); |
| m_levelMap.Add(Level.Finest); |
| |
| m_levelMap.Add(Level.All); |
| } |
| |
| /// <summary> |
| /// Adds an object renderer for a specific class. |
| /// </summary> |
| /// <param name="typeToRender">The type that will be rendered by the renderer supplied.</param> |
| /// <param name="rendererInstance">The object renderer used to render the object.</param> |
| /// <remarks> |
| /// <para> |
| /// Adds an object renderer for a specific class. |
| /// </para> |
| /// </remarks> |
| virtual public void AddRenderer(Type typeToRender, IObjectRenderer rendererInstance) |
| { |
| if (typeToRender == null) |
| { |
| throw new ArgumentNullException("typeToRender"); |
| } |
| if (rendererInstance == null) |
| { |
| throw new ArgumentNullException("rendererInstance"); |
| } |
| |
| m_rendererMap.Put(typeToRender, rendererInstance); |
| } |
| |
| /// <summary> |
| /// Notify the registered listeners that the repository is shutting down |
| /// </summary> |
| /// <param name="e">Empty EventArgs</param> |
| /// <remarks> |
| /// <para> |
| /// Notify any listeners that this repository is shutting down. |
| /// </para> |
| /// </remarks> |
| protected virtual void OnShutdown(EventArgs e) |
| { |
| if (e == null) |
| { |
| e = EventArgs.Empty; |
| } |
| |
| LoggerRepositoryShutdownEventHandler handler = m_shutdownEvent; |
| if (handler != null) |
| { |
| handler(this, e); |
| } |
| } |
| |
| /// <summary> |
| /// Notify the registered listeners that the repository has had its configuration reset |
| /// </summary> |
| /// <param name="e">Empty EventArgs</param> |
| /// <remarks> |
| /// <para> |
| /// Notify any listeners that this repository's configuration has been reset. |
| /// </para> |
| /// </remarks> |
| protected virtual void OnConfigurationReset(EventArgs e) |
| { |
| if (e == null) |
| { |
| e = EventArgs.Empty; |
| } |
| |
| LoggerRepositoryConfigurationResetEventHandler handler = m_configurationResetEvent; |
| if (handler != null) |
| { |
| handler(this, e); |
| } |
| } |
| |
| /// <summary> |
| /// Notify the registered listeners that the repository has had its configuration changed |
| /// </summary> |
| /// <param name="e">Empty EventArgs</param> |
| /// <remarks> |
| /// <para> |
| /// Notify any listeners that this repository's configuration has changed. |
| /// </para> |
| /// </remarks> |
| protected virtual void OnConfigurationChanged(EventArgs e) |
| { |
| if (e == null) |
| { |
| e = EventArgs.Empty; |
| } |
| |
| LoggerRepositoryConfigurationChangedEventHandler handler = m_configurationChangedEvent; |
| if (handler != null) |
| { |
| handler(this, e); |
| } |
| } |
| |
| /// <summary> |
| /// Raise a configuration changed event on this repository |
| /// </summary> |
| /// <param name="e">EventArgs.Empty</param> |
| /// <remarks> |
| /// <para> |
| /// Applications that programmatically change the configuration of the repository should |
| /// raise this event notification to notify listeners. |
| /// </para> |
| /// </remarks> |
| public void RaiseConfigurationChanged(EventArgs e) |
| { |
| OnConfigurationChanged(e); |
| } |
| |
| private static int GetWaitTime(DateTime startTimeUtc, int millisecondsTimeout) |
| { |
| if (millisecondsTimeout == Timeout.Infinite) return Timeout.Infinite; |
| if (millisecondsTimeout == 0) return 0; |
| |
| int elapsedMilliseconds = (int)(DateTime.UtcNow - startTimeUtc).TotalMilliseconds; |
| int timeout = millisecondsTimeout - elapsedMilliseconds; |
| if (timeout < 0) timeout = 0; |
| return timeout; |
| } |
| |
| /// <summary> |
| /// Flushes all configured Appenders that implement <see cref="log4net.Appender.IFlushable"/>. |
| /// </summary> |
| /// <param name="millisecondsTimeout">The maximum time in milliseconds to wait for logging events from asycnhronous appenders to be flushed, |
| /// or <see cref="Timeout.Infinite"/> to wait indefinitely.</param> |
| /// <returns><c>True</c> if all logging events were flushed successfully, else <c>false</c>.</returns> |
| public bool Flush(int millisecondsTimeout) |
| { |
| if (millisecondsTimeout < -1) throw new ArgumentOutOfRangeException("millisecondsTimeout", "Timeout must be -1 (Timeout.Infinite) or non-negative"); |
| |
| // Assume success until one of the appenders fails |
| bool result = true; |
| |
| // Use DateTime.UtcNow rather than a System.Diagnostics.Stopwatch for compatibility with .NET 1.x |
| DateTime startTimeUtc = DateTime.UtcNow; |
| |
| // Do buffering appenders first. These may be forwarding to other appenders |
| foreach(log4net.Appender.IAppender appender in GetAppenders()) |
| { |
| log4net.Appender.IFlushable flushable = appender as log4net.Appender.IFlushable; |
| if (flushable == null) continue; |
| if (appender is Appender.BufferingAppenderSkeleton) |
| { |
| int timeout = GetWaitTime(startTimeUtc, millisecondsTimeout); |
| if (!flushable.Flush(timeout)) result = false; |
| } |
| } |
| |
| // Do non-buffering appenders. |
| foreach (log4net.Appender.IAppender appender in GetAppenders()) |
| { |
| log4net.Appender.IFlushable flushable = appender as log4net.Appender.IFlushable; |
| if (flushable == null) continue; |
| if (!(appender is Appender.BufferingAppenderSkeleton)) |
| { |
| int timeout = GetWaitTime(startTimeUtc, millisecondsTimeout); |
| if (!flushable.Flush(timeout)) result = false; |
| } |
| } |
| |
| return result; |
| } |
| } |
| } |