>让Shell项目执行所有的实际日志记录.它获得对Log4Net的引用,其他项目会启动复合事件,让Shell知道它需要记录某些东西.这些项目仅在Shell的app.config文件(DEBUG,ERROR等)中打开日志记录的级别引发事件,以免降低性能.
>给每个项目,包括模块,一个Log4Net引用,并让项目自己的日志记录到一个通用的日志文件,而不是发送消息到Shell进行日志记录.
解决方法
我发现以下内容在日志记录方面工作得很好(我正在使用Enterprise Libary Logging块,但应用类似于Log4Net的应该是直接的):
在你的Shell中创建一个Boostrapper:
-My Project -Shell Module (add a reference to the Infrastructure project) -Bootstrapper.cs
在基础架构项目中创建日志记录适配器,即:
-My Project -Infrastructure Module -Adapters -Logging -MyCustomLoggerAdapter.cs -MyCustomLoggerAdapterExtendedAdapter.cs -IFormalLogger.cs
MyCustomLoggerAdapter类将用于覆盖Bootstrapper中的“LoggerFacade”属性.它应该有一个默认的构造函数来消息一切.
注意:通过覆盖Bootstrapper中的LoggerFacade属性,您正在为Prism提供一种日志记录机制,用于记录其自己的内部消息.您可以在整个应用程序中使用此记录器,也可以扩展记录器以获取更全面的记录器. (请参阅MyCustomLoggerAdapterExtendedAdapter / IFormalLogger)
public class MyCustomLoggerAdapter : ILoggerFacade { #region ILoggerFacade Members /// <summary> /// Logs an entry using the Enterprise Library logging. /// For logging a Category.Exception type,it is preferred to use /// the EnterpriseLibraryLoggerAdapter.Exception methods." /// </summary> public void Log( string message,Category category,Priority priority ) { if( category == Category.Exception ) { Exception( new Exception( message ),ExceptionPolicies.Default ); return; } Logger.Write( message,category.ToString(),( int )priority ); } #endregion /// <summary> /// Logs an entry using the Enterprise Library Logging. /// </summary> /// <param name="entry">the LogEntry object used to log the /// entry with Enterprise Library.</param> public void Log( LogEntry entry ) { Logger.Write( entry ); } // Other methods if needed,i.e.,a default Exception logger. public void Exception ( Exception ex ) { // do stuff } }
MyCustomLoggerAdapterExtendedAdapter是从MyCustomLoggerAdapter导出的,可以为更加完整的记录器提供其他构造函数.
public class MyCustomLoggerAdapterExtendedAdapter : MyCustomLoggerAdapter,IFormalLogger { private readonly ILoggingPolicySection _config; private LogEntry _infoPolicy; private LogEntry _debugPolicy; private LogEntry _warnPolicy; private LogEntry _errorPolicy; private LogEntry InfoLog { get { if( _infoPolicy == null ) { LogEntry log = GetLogEntryByPolicyName( LogPolicies.Info ); _infoPolicy = log; } return _infoPolicy; } } // removed backing code for brevity private LogEntry DebugLog... WarnLog... ErrorLog // ILoggingPolicySection is passed via constructor injection in the bootstrapper // and is used to configure varIoUs logging policies. public MyCustomLoggerAdapterExtendedAdapter ( ILoggingPolicySection loggingPolicySection ) { _config = loggingPolicySection; } #region IFormalLogger Members /// <summary> /// Info: informational statements concerning program state,/// representing program events or behavior tracking. /// </summary> /// <param name="message"></param> public void Info( string message ) { InfoLog.Message = message; InfoLog.ExtendedProperties.Clear(); base.Log( InfoLog ); } /// <summary> /// Debug: fine-grained statements concerning program state,/// typically used for debugging. /// </summary> /// <param name="message"></param> public void Debug( string message ) { DebugLog.Message = message; DebugLog.ExtendedProperties.Clear(); base.Log( DebugLog ); } /// <summary> /// Warn: statements that describe potentially harmful /// events or states in the program. /// </summary> /// <param name="message"></param> public void Warn( string message ) { WarnLog.Message = message; WarnLog.ExtendedProperties.Clear(); base.Log( WarnLog ); } /// <summary> /// Error: statements that describe non-fatal errors in the application; /// sometimes used for handled exceptions. For more defined Exception /// logging,use the Exception method in this class. /// </summary> /// <param name="message"></param> public void Error( string message ) { ErrorLog.Message = message; ErrorLog.ExtendedProperties.Clear(); base.Log( ErrorLog ); } /// <summary> /// Logs an Exception using the Default EntLib Exception policy /// as defined in the Exceptions.config file. /// </summary> /// <param name="ex"></param> public void Exception( Exception ex ) { base.Exception( ex,ExceptionPolicies.Default ); } #endregion /// <summary> /// Creates a LogEntry object based on the policy name as /// defined in the logging config file. /// </summary> /// <param name="policyName">name of the policy to get.</param> /// <returns>a new LogEntry object.</returns> private LogEntry GetLogEntryByPolicyName( string policyName ) { if( !_config.Policies.Contains( policyName ) ) { throw new ArgumentException( string.Format( "The policy '{0}' does not exist in the LoggingPoliciesCollection",policyName ) ); } ILoggingPolicyElement policy = _config.Policies[policyName]; var log = new LogEntry(); log.Categories.Add( policy.Category ); log.Title = policy.Title; log.EventId = policy.EventId; log.Severity = policy.Severity; log.Priority = ( int )policy.Priority; log.ExtendedProperties.Clear(); return log; } } public interface IFormalLogger { void Info( string message ); void Debug( string message ); void Warn( string message ); void Error( string message ); void Exception( Exception ex ); }
在Bootstrapper中:
public class MyProjectBootstrapper : UnityBootstrapper { protected override void ConfigureContainer() { // ... arbitrary stuff // create constructor injection for the MyCustomLoggerAdapterExtendedAdapter var logPolicyConfigSection = ConfigurationManager.GetSection( LogPolicies.CorporateLoggingConfiguration ); var injectedLogPolicy = new InjectionConstructor( logPolicyConfigSection as LoggingPolicySection ); // register the MyCustomLoggerAdapterExtendedAdapter Container.RegisterType<IFormalLogger,MyCustomLoggerAdapterExtendedAdapter>( new ContainerControlledLifetimeManager(),injectedLogPolicy ); } private readonly MyCustomLoggerAdapter _logger = new MyCustomLoggerAdapter(); protected override ILoggerFacade LoggerFacade { get { return _logger; } } }
最后,要使用任何一个记录器,您需要做的就是将适当的接口添加到类的构造函数中,并且UnityContainer将为您注入记录器:
public partial class Shell : Window,IShellView { private readonly IFormalLogger _logger; private readonly ILoggerFacade _loggerFacade; public Shell( IFormalLogger logger,ILoggerFacade loggerFacade ) { _logger = logger; _loggerFacade = loggerFacade _logger.Debug( "Shell: Instantiating the .ctor." ); _loggerFacade.Log( "My Message",Category.Debug,Priority.None ); InitializeComponent(); } #region IShellView Members public void ShowView() { _logger.Debug( "Shell: Showing the Shell (ShowView)." ); _loggerFacade.Log( "Shell: Showing the Shell (ShowView).",Priority.None ); this.Show(); } #endregion }
我不认为你需要一个单独的模块用于日志策略.通过将日志记录策略添加到基础架构模块,所有其他模块将获得所需的引用(假设您将基础架构模块添加为其他模块的参考).通过将Logger添加到Boostrapper,您可以让UnityContainer根据需要注入日志记录策略.
CodePlex上的CompositeWPF contrib项目还有一个simple example of uisng Log4Net.
HTH的