(6)Orchard 开发之 Logging and NullLogger

NullLogger 很像 NullLocalizer 其实它们都没有干什么实际的工作,orchard 通常会在构造函数中给 ILogger 赋一个 NullLogger.Instance

Logger = NullLogger.Instance;    这样一看很多人还以为是 NullLogger 打的 log ,其实不是这样的, 你删掉 Logger = NullLogger.Instance;  这条语句也没什么影响,log 一样能打出来。 我暂时还不知道 NullLogger 究竟有什么用。

相关的类都在 Orchard.Framework\Logging 下:

首先还是看 LoggingModule 类:

protected override void Load(ContainerBuilder moduleBuilder) {
            // by default, use Orchard's logger that delegates to Castle's logger factory
            moduleBuilder.RegisterType<CastleLoggerFactory>().As<ILoggerFactory>().InstancePerLifetimeScope(); // 注册工厂方法
            moduleBuilder.RegisterType<OrchardLog4netFactory>().As<Castle.Core.Logging.ILoggerFactory>().InstancePerLifetimeScope(); // 注册工厂方法

            // call CreateLogger in response to the request for an ILogger implementation
            moduleBuilder.Register(CreateLogger).As<ILogger>().InstancePerDependency();    // 当需要一个 ILogger 实例时 调 CreateLogger 方法
        }

        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
            var implementationType = registration.Activator.LimitType;

            // build an array of actions on this type to assign loggers to member properties
            var injectors = BuildLoggerInjectors(implementationType).ToArray();

            // if there are no logger properties, there's no reason to hook the activated event
            if (!injectors.Any())
                return;

            // otherwise, whan an instance of this component is activated, inject the loggers on the instance
            registration.Activated += (s, e) => {
                foreach (var injector in injectors)
                    injector(e.Context, e.Instance);  
            };
        }

        private IEnumerable<Action<IComponentContext, object>> BuildLoggerInjectors(Type componentType) {  // 查找是否定义了 ILogger 属性
            // Look for settable properties of type "ILogger" 
            var loggerProperties = componentType
                .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance)
                .Select(p => new {
                    PropertyInfo = p,
                    p.PropertyType,
                    IndexParameters = p.GetIndexParameters(),
                    Accessors = p.GetAccessors(false)
                })
                .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger
                .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer
                .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set

            // Return an array of actions that resolve a logger and assign the property
            foreach (var entry in loggerProperties) {
                var propertyInfo = entry.PropertyInfo;

                yield return (ctx, instance) => {
                    string component = componentType.ToString();
                    var logger = _loggerCache.GetOrAdd(component, key => ctx.Resolve<ILogger>(new TypedParameter(typeof(Type), componentType)));
                    propertyInfo.SetValue(instance, logger, null); // 为 ILogger 赋值
                };
            }
        }

        private static ILogger CreateLogger(IComponentContext context, IEnumerable<Parameter> parameters) {
            // return an ILogger in response to Resolve<ILogger>(componentTypeParameter)
            var loggerFactory = context.Resolve<ILoggerFactory>();   // 注入一个工厂方法 ,这里注入的是 CastleLoggerFactory 在 Load 方法中配置的
            var containingType = parameters.TypedAs<Type>();
            return loggerFactory.CreateLogger(containingType);  // 返回一个 ILogger 对象,这里返回的是 CastleLogger
        }

所以  ILogger 实际指向的是一个  CastleLogger 对象

CastleLogger 类中 有一个字段  _castleLogger

private readonly Castle.Core.Logging.ILogger _castleLogger;

由上可知这个字段实际会指向   OrchardLog4netLogger 对象

所以最后真正打 Log 的还是  OrchardLog4netLogger  。

public interface ILogger {
        bool IsEnabled(LogLevel level);
        void Log(LogLevel level, Exception exception, string format, params object[] args);
    }

ILogger 只有一个  Log 方法, 但你却可以调 Logger.Debug 等方法,这是因为在  LoggingExtensions  定义了 ILogger 扩展方法。

Log4net 的配置文件在 Orchard.Web\Config\log4net.config

默认的 log 会打到 \Orchard.Web\App_Data\Logs 下面

你可能感兴趣的:(logging)