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 下面