#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.Configuration; using System.Reflection; using log4net.Util; using log4net.Repository; namespace log4net.Core { /// /// Static manager that controls the creation of repositories /// /// /// /// Static manager that controls the creation of repositories /// /// /// This class is used by the wrapper managers (e.g. ) /// to provide access to the objects. /// /// /// This manager also holds the that is used to /// lookup and create repositories. The selector can be set either programmatically using /// the property, or by setting the log4net.RepositorySelector /// AppSetting in the applications config file to the fully qualified type name of the /// selector to use. /// /// /// Nicko Cadell /// Gert Driesen public sealed class LoggerManager { #region Private Instance Constructors /// /// Private constructor to prevent instances. Only static methods should be used. /// /// /// /// Private constructor to prevent instances. Only static methods should be used. /// /// private LoggerManager() { } #endregion Private Instance Constructors #region Static Constructor /// /// Hook the shutdown event /// /// /// /// On the full .NET runtime, the static constructor hooks up the /// AppDomain.ProcessExit and AppDomain.DomainUnload> events. /// These are used to shutdown the log4net system as the application exits. /// /// static LoggerManager() { try { // Register the AppDomain events, note we have to do this with a // method call rather than directly here because the AppDomain // makes a LinkDemand which throws the exception during the JIT phase. RegisterAppDomainEvents(); } catch(System.Security.SecurityException) { LogLog.Debug(declaringType, "Security Exception (ControlAppDomain LinkDemand) while trying "+ "to register Shutdown handler with the AppDomain. LoggerManager.Shutdown() "+ "will not be called automatically when the AppDomain exits. It must be called "+ "programmatically."); } // Dump out our assembly version into the log if debug is enabled LogLog.Debug(declaringType, GetVersionInfo()); // Set the default repository selector #if NETCF s_repositorySelector = new CompactRepositorySelector(typeof(log4net.Repository.Hierarchy.Hierarchy)); #else // Look for the RepositorySelector type specified in the AppSettings 'log4net.RepositorySelector' string appRepositorySelectorTypeName = SystemInfo.GetAppSetting("log4net.RepositorySelector"); if (appRepositorySelectorTypeName != null && appRepositorySelectorTypeName.Length > 0) { // Resolve the config string into a Type Type appRepositorySelectorType = null; try { appRepositorySelectorType = SystemInfo.GetTypeFromString(appRepositorySelectorTypeName, false, true); } catch(Exception ex) { LogLog.Error(declaringType, "Exception while resolving RepositorySelector Type ["+appRepositorySelectorTypeName+"]", ex); } if (appRepositorySelectorType != null) { // Create an instance of the RepositorySelectorType object appRepositorySelectorObj = null; try { appRepositorySelectorObj = Activator.CreateInstance(appRepositorySelectorType); } catch(Exception ex) { LogLog.Error(declaringType, "Exception while creating RepositorySelector ["+appRepositorySelectorType.FullName+"]", ex); } if (appRepositorySelectorObj != null && appRepositorySelectorObj is IRepositorySelector) { s_repositorySelector = (IRepositorySelector)appRepositorySelectorObj; } else { LogLog.Error(declaringType, "RepositorySelector Type ["+appRepositorySelectorType.FullName+"] is not an IRepositorySelector"); } } } // Create the DefaultRepositorySelector if not configured above if (s_repositorySelector == null) { s_repositorySelector = new DefaultRepositorySelector(typeof(log4net.Repository.Hierarchy.Hierarchy)); } #endif } /// /// Register for ProcessExit and DomainUnload events on the AppDomain /// /// /// /// This needs to be in a separate method because the events make /// a LinkDemand for the ControlAppDomain SecurityPermission. Because /// this is a LinkDemand it is demanded at JIT time. Therefore we cannot /// catch the exception in the method itself, we have to catch it in the /// caller. /// /// private static void RegisterAppDomainEvents() { #if !NETCF // ProcessExit seems to be fired if we are part of the default domain AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit); // Otherwise DomainUnload is fired AppDomain.CurrentDomain.DomainUnload += new EventHandler(OnDomainUnload); #endif } #endregion Static Constructor #region Public Static Methods /// /// Return the default instance. /// /// the repository to lookup in /// Return the default instance /// /// /// Gets the for the repository specified /// by the argument. /// /// [Obsolete("Use GetRepository instead of GetLoggerRepository")] public static ILoggerRepository GetLoggerRepository(string repository) { return GetRepository(repository); } /// /// Returns the default instance. /// /// The assembly to use to lookup the repository. /// The default instance. [Obsolete("Use GetRepository instead of GetLoggerRepository")] public static ILoggerRepository GetLoggerRepository(Assembly repositoryAssembly) { return GetRepository(repositoryAssembly); } /// /// Return the default instance. /// /// the repository to lookup in /// Return the default instance /// /// /// Gets the for the repository specified /// by the argument. /// /// public static ILoggerRepository GetRepository(string repository) { if (repository == null) { throw new ArgumentNullException("repository"); } return RepositorySelector.GetRepository(repository); } /// /// Returns the default instance. /// /// The assembly to use to lookup the repository. /// The default instance. /// /// /// Returns the default instance. /// /// public static ILoggerRepository GetRepository(Assembly repositoryAssembly) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } return RepositorySelector.GetRepository(repositoryAssembly); } /// /// Returns the named logger if it exists. /// /// The repository to lookup in. /// The fully qualified logger name to look for. /// /// The logger found, or null if the named logger does not exist in the /// specified repository. /// /// /// /// If the named logger exists (in the specified repository) then it /// returns a reference to the logger, otherwise it returns /// null. /// /// public static ILogger Exists(string repository, string name) { if (repository == null) { throw new ArgumentNullException("repository"); } if (name == null) { throw new ArgumentNullException("name"); } return RepositorySelector.GetRepository(repository).Exists(name); } /// /// Returns the named logger if it exists. /// /// The assembly to use to lookup the repository. /// The fully qualified logger name to look for. /// /// The logger found, or null if the named logger does not exist in the /// specified assembly's repository. /// /// /// /// If the named logger exists (in the specified assembly's repository) then it /// returns a reference to the logger, otherwise it returns /// null. /// /// public static ILogger Exists(Assembly repositoryAssembly, string name) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } if (name == null) { throw new ArgumentNullException("name"); } return RepositorySelector.GetRepository(repositoryAssembly).Exists(name); } /// /// Returns all the currently defined loggers in the specified repository. /// /// The repository to lookup in. /// All the defined loggers. /// /// /// The root logger is not included in the returned array. /// /// public static ILogger[] GetCurrentLoggers(string repository) { if (repository == null) { throw new ArgumentNullException("repository"); } return RepositorySelector.GetRepository(repository).GetCurrentLoggers(); } /// /// Returns all the currently defined loggers in the specified assembly's repository. /// /// The assembly to use to lookup the repository. /// All the defined loggers. /// /// /// The root logger is not included in the returned array. /// /// public static ILogger[] GetCurrentLoggers(Assembly repositoryAssembly) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } return RepositorySelector.GetRepository(repositoryAssembly).GetCurrentLoggers(); } /// /// Retrieves or creates a named logger. /// /// The repository to lookup in. /// The name of the logger to retrieve. /// The logger with the name specified. /// /// /// Retrieves a logger named as the /// parameter. If the named logger already exists, then the /// existing instance will be returned. Otherwise, a new instance is /// created. /// /// /// By default, loggers do not have a set level but inherit /// it from the hierarchy. This is one of the central features of /// log4net. /// /// public static ILogger GetLogger(string repository, string name) { if (repository == null) { throw new ArgumentNullException("repository"); } if (name == null) { throw new ArgumentNullException("name"); } return RepositorySelector.GetRepository(repository).GetLogger(name); } /// /// Retrieves or creates a named logger. /// /// The assembly to use to lookup the repository. /// The name of the logger to retrieve. /// The logger with the name specified. /// /// /// Retrieves a logger named as the /// parameter. If the named logger already exists, then the /// existing instance will be returned. Otherwise, a new instance is /// created. /// /// /// By default, loggers do not have a set level but inherit /// it from the hierarchy. This is one of the central features of /// log4net. /// /// public static ILogger GetLogger(Assembly repositoryAssembly, string name) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } if (name == null) { throw new ArgumentNullException("name"); } return RepositorySelector.GetRepository(repositoryAssembly).GetLogger(name); } /// /// Shorthand for . /// /// The repository to lookup in. /// The of which the fullname will be used as the name of the logger to retrieve. /// The logger with the name specified. /// /// /// Gets the logger for the fully qualified name of the type specified. /// /// public static ILogger GetLogger(string repository, Type type) { if (repository == null) { throw new ArgumentNullException("repository"); } if (type == null) { throw new ArgumentNullException("type"); } return RepositorySelector.GetRepository(repository).GetLogger(type.FullName); } /// /// Shorthand for . /// /// the assembly to use to lookup the repository /// The of which the fullname will be used as the name of the logger to retrieve. /// The logger with the name specified. /// /// /// Gets the logger for the fully qualified name of the type specified. /// /// public static ILogger GetLogger(Assembly repositoryAssembly, Type type) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } if (type == null) { throw new ArgumentNullException("type"); } return RepositorySelector.GetRepository(repositoryAssembly).GetLogger(type.FullName); } /// /// Shuts down the log4net system. /// /// /// /// Calling this method will safely close and remove all /// appenders in all the loggers including root contained in all the /// default repositories. /// /// /// Some appenders need to be closed before the application exists. /// Otherwise, pending logging events might be lost. /// /// /// The shutdown method is careful to close nested /// appenders before closing regular appenders. This is allows /// configurations where a regular appender is attached to a logger /// and again to a nested appender. /// /// public static void Shutdown() { foreach(ILoggerRepository repository in GetAllRepositories()) { repository.Shutdown(); } } /// /// Shuts down the repository for the repository specified. /// /// The repository to shutdown. /// /// /// Calling this method will safely close and remove all /// appenders in all the loggers including root contained in the /// repository for the specified. /// /// /// Some appenders need to be closed before the application exists. /// Otherwise, pending logging events might be lost. /// /// /// The shutdown method is careful to close nested /// appenders before closing regular appenders. This is allows /// configurations where a regular appender is attached to a logger /// and again to a nested appender. /// /// public static void ShutdownRepository(string repository) { if (repository == null) { throw new ArgumentNullException("repository"); } RepositorySelector.GetRepository(repository).Shutdown(); } /// /// Shuts down the repository for the repository specified. /// /// The assembly to use to lookup the repository. /// /// /// Calling this method will safely close and remove all /// appenders in all the loggers including root contained in the /// repository for the repository. The repository is looked up using /// the specified. /// /// /// Some appenders need to be closed before the application exists. /// Otherwise, pending logging events might be lost. /// /// /// The shutdown method is careful to close nested /// appenders before closing regular appenders. This is allows /// configurations where a regular appender is attached to a logger /// and again to a nested appender. /// /// public static void ShutdownRepository(Assembly repositoryAssembly) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } RepositorySelector.GetRepository(repositoryAssembly).Shutdown(); } /// /// Resets all values contained in this repository instance to their defaults. /// /// The repository to reset. /// /// /// Resets all values contained in the repository instance to their /// defaults. This removes all appenders from all loggers, sets /// the level of all non-root loggers to null, /// sets their additivity flag to true and sets the level /// of the root logger to . Moreover, /// message disabling is set its default "off" value. /// /// public static void ResetConfiguration(string repository) { if (repository == null) { throw new ArgumentNullException("repository"); } RepositorySelector.GetRepository(repository).ResetConfiguration(); } /// /// Resets all values contained in this repository instance to their defaults. /// /// The assembly to use to lookup the repository to reset. /// /// /// Resets all values contained in the repository instance to their /// defaults. This removes all appenders from all loggers, sets /// the level of all non-root loggers to null, /// sets their additivity flag to true and sets the level /// of the root logger to . Moreover, /// message disabling is set its default "off" value. /// /// public static void ResetConfiguration(Assembly repositoryAssembly) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } RepositorySelector.GetRepository(repositoryAssembly).ResetConfiguration(); } /// /// Creates a repository with the specified name. /// /// The name of the repository, this must be unique amongst repositories. /// The created for the repository. /// /// /// CreateDomain is obsolete. Use CreateRepository instead of CreateDomain. /// /// /// Creates the default type of which is a /// object. /// /// /// The name must be unique. Repositories cannot be redefined. /// An will be thrown if the repository already exists. /// /// /// The specified repository already exists. [Obsolete("Use CreateRepository instead of CreateDomain")] public static ILoggerRepository CreateDomain(string repository) { return CreateRepository(repository); } /// /// Creates a repository with the specified name. /// /// The name of the repository, this must be unique amongst repositories. /// The created for the repository. /// /// /// Creates the default type of which is a /// object. /// /// /// The name must be unique. Repositories cannot be redefined. /// An will be thrown if the repository already exists. /// /// /// The specified repository already exists. public static ILoggerRepository CreateRepository(string repository) { if (repository == null) { throw new ArgumentNullException("repository"); } return RepositorySelector.CreateRepository(repository, null); } /// /// Creates a repository with the specified name and repository type. /// /// The name of the repository, this must be unique to the repository. /// A that implements /// and has a no arg constructor. An instance of this type will be created to act /// as the for the repository specified. /// The created for the repository. /// /// /// CreateDomain is obsolete. Use CreateRepository instead of CreateDomain. /// /// /// The name must be unique. Repositories cannot be redefined. /// An Exception will be thrown if the repository already exists. /// /// /// The specified repository already exists. [Obsolete("Use CreateRepository instead of CreateDomain")] public static ILoggerRepository CreateDomain(string repository, Type repositoryType) { return CreateRepository(repository, repositoryType); } /// /// Creates a repository with the specified name and repository type. /// /// The name of the repository, this must be unique to the repository. /// A that implements /// and has a no arg constructor. An instance of this type will be created to act /// as the for the repository specified. /// The created for the repository. /// /// /// The name must be unique. Repositories cannot be redefined. /// An Exception will be thrown if the repository already exists. /// /// /// The specified repository already exists. public static ILoggerRepository CreateRepository(string repository, Type repositoryType) { if (repository == null) { throw new ArgumentNullException("repository"); } if (repositoryType == null) { throw new ArgumentNullException("repositoryType"); } return RepositorySelector.CreateRepository(repository, repositoryType); } /// /// Creates a repository for the specified assembly and repository type. /// /// The assembly to use to get the name of the repository. /// A that implements /// and has a no arg constructor. An instance of this type will be created to act /// as the for the repository specified. /// The created for the repository. /// /// /// CreateDomain is obsolete. Use CreateRepository instead of CreateDomain. /// /// /// The created will be associated with the repository /// specified such that a call to with the /// same assembly specified will return the same repository instance. /// /// [Obsolete("Use CreateRepository instead of CreateDomain")] public static ILoggerRepository CreateDomain(Assembly repositoryAssembly, Type repositoryType) { return CreateRepository(repositoryAssembly, repositoryType); } /// /// Creates a repository for the specified assembly and repository type. /// /// The assembly to use to get the name of the repository. /// A that implements /// and has a no arg constructor. An instance of this type will be created to act /// as the for the repository specified. /// The created for the repository. /// /// /// The created will be associated with the repository /// specified such that a call to with the /// same assembly specified will return the same repository instance. /// /// public static ILoggerRepository CreateRepository(Assembly repositoryAssembly, Type repositoryType) { if (repositoryAssembly == null) { throw new ArgumentNullException("repositoryAssembly"); } if (repositoryType == null) { throw new ArgumentNullException("repositoryType"); } return RepositorySelector.CreateRepository(repositoryAssembly, repositoryType); } /// /// Gets an array of all currently defined repositories. /// /// An array of all the known objects. /// /// /// Gets an array of all currently defined repositories. /// /// public static ILoggerRepository[] GetAllRepositories() { return RepositorySelector.GetAllRepositories(); } /// /// Gets or sets the repository selector used by the . /// /// /// The repository selector used by the . /// /// /// /// The repository selector () is used by /// the to create and select repositories /// (). /// /// /// The caller to supplies either a string name /// or an assembly (if not supplied the assembly is inferred using /// ). /// /// /// This context is used by the selector to lookup a specific repository. /// /// /// For the full .NET Framework, the default repository is DefaultRepositorySelector; /// for the .NET Compact Framework CompactRepositorySelector is the default /// repository. /// /// public static IRepositorySelector RepositorySelector { get { return s_repositorySelector; } set { s_repositorySelector = value; } } #endregion Public Static Methods #region Private Static Methods /// /// Internal method to get pertinent version info. /// /// A string of version info. private static string GetVersionInfo() { System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Grab the currently executing assembly Assembly myAssembly = Assembly.GetExecutingAssembly(); // Build Up message sb.Append("log4net assembly [").Append(myAssembly.FullName).Append("]. "); sb.Append("Loaded from [").Append(SystemInfo.AssemblyLocationInfo(myAssembly)).Append("]. "); sb.Append("(.NET Runtime [").Append(Environment.Version.ToString()).Append("]"); #if (!SSCLI) sb.Append(" on ").Append(Environment.OSVersion.ToString()); #endif sb.Append(")"); return sb.ToString(); } #if (!NETCF) /// /// Called when the event fires /// /// the that is exiting /// null /// /// /// Called when the event fires. /// /// /// When the event is triggered the log4net system is . /// /// private static void OnDomainUnload(object sender, EventArgs e) { Shutdown(); } /// /// Called when the event fires /// /// the that is exiting /// null /// /// /// Called when the event fires. /// /// /// When the event is triggered the log4net system is . /// /// private static void OnProcessExit(object sender, EventArgs e) { Shutdown(); } #endif #endregion Private Static Methods #region Private Static Fields /// /// The fully qualified type of the LoggerManager class. /// /// /// Used by the internal logger to record the Type of the /// log message. /// private readonly static Type declaringType = typeof(LoggerManager); /// /// Initialize the default repository selector /// private static IRepositorySelector s_repositorySelector; #endregion Private Static Fields } }