123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- #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;
- }
- }
- }
|