返回ABP系列javascript
ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。html
ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。java
ABP的官方网站:http://www.aspnetboilerplate.comgit
ABP官方文档:http://www.aspnetboilerplate.com/Pages/Documentsgithub
Github上的开源项目:https://github.com/aspnetboilerplateweb
ABP使用Castle日志记录工具,而且可使用不一样的日志类库,好比:Log4Net, NLog, Serilog... 等。对于全部的日志类库,Castle提供了一个通用的接口来实现,咱们能够很方便的处理各类特殊的日志库,并且当业务须要的时候,很容易替换日志组件。数据库
Castle是什么:Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架、AOP,基本包括了整个开发过程当中的全部东西。ASP.NET Boilerplate的ioc容器就是经过Castle实现的。apache
Log4Net是.Net中最流行的日志类库之一。ABP模板中自带了通过合适配置的Log4Net。可是,只存在一行log4net的依赖(看下面),所以,你能够将它改成你最喜欢的类库。浏览器
获取Logger:app
不管你选择了什么日志类库,最终要记录的日志代码都是相同的
一开始,咱们要处理一下记录日志的Logger对象。由于ABP强烈推荐使用依赖注入,因此咱们可使用属性注入模式轻松地注入一个Logger对象。以下所示:
using Castle.Core.Logging; //一、导入 Logging 命名空间 public class TaskAppService : ITaskAppService { //二、使用属性注入得到 logger public ILogger Logger { get; set; } public TaskAppService() { //三、若是没有提供Logger,就不能记录日志 Logger = NullLogger.Instance; } public void CreateTask(CreateTaskInput input) { //四、记录日志 Logger.Info("Creating a new task with description: " + input.Description); //TODO: 保存到数据库... } }
一、导入Castle的ILogger接口的命名空间。
二、定义一个公有的叫作Logger的ILogger对象。这是记录日志的对象。建立TaskAppService对象以后,依赖注入系统会自动注入这个属性。这就是所谓的属性注入模式。
三、将Logger设置为NullLogger.Instance。即便没有这行代码,系统也会工做地很好。可是这是属性注入模式的最佳实践。若是没给Logger设置任何值,那么当咱们使用它的时候会由于它是null而抛出“空指针”异常。这个保证了它不为null。所以,若是没有给Logger设置值,那么它是NullLogger。这就是所谓的null对象模式。NullLogger实际上什么都没作,也没有记录任何日志。所以,咱们的类要不要一个实际的logger都能工做。
四、最后,咱们记录了一个info等级的日志文本。存在多种不一样的等级。
经过积累使用Logger:
ASP.NET Boilerplate框架提供了MVC Controllers、Web API Controllers和Application service classes的基类。例如,Web层对应的基类是XXXControllerBase,这些基类中都声明了Logger属性。能够直接使用Logger来记录日志,无需注入。以下:
public class HomeController : SimpleTaskSystemControllerBase { public ActionResult Index() { Logger.Debug("A sample log message..."); return View(); } }
MVC Controllers:继承XXAbpController基类
Web API Controllers:继承XXAbpApiController基类
Application service classes:继承XXAppServiceBase基类
配置:
若是你在官网上经过ASP.NET Boilerplate templates 来生成了你的工程,Log4Net的全部配置都自动生成了。
默认的配置格式以下:
配置文件:log4net.config 通常都在项目的web目录下面。
<?xml version="1.0" encoding="utf-8" ?> <log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" > <file value="Logs/Logs.txt" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="10" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" /> </layout> </appender> <root> <appender-ref ref="RollingFileAppender" /> <level value="DEBUG" /> </root> <logger name="NHibernate"> <level value="WARN" /> </logger> </log4net>
Log4Net是一个很是强大和易用的日志库组件,你能够写各类日志,好比写到txt文件,写入到数据库等等。你能设置最小的日志等级,就像上面这个针对NHibernate的配置。不一样的记录器写不一样的日志。
最后,在工程的Global.asax 文件中,来定义Log4Net的配置文件:
public class MvcApplication : AbpWebApplication { protected override void Application_Start(object sender, EventArgs e) { IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig("log4net.config")); base.Application_Start(sender, e); } }
客户端:
ABP为客户端定义了一个javascript日志记录API。默认会将日志记录到浏览器的控制台。记录日志的javascript代码样例以下:
abp.log.warn('a sample log message...');
LogSeverity:枚举类型,定义了5个日志级别:Info,Debug,Warn,Error, Fatal.
namespace Abp.Logging { /// <summary> /// Indicates severity for log. /// </summary> public enum LogSeverity { /// <summary> /// Debug. /// </summary> Debug, /// <summary> /// Info. /// </summary> Info, /// <summary> /// Warn. /// </summary> Warn, /// <summary> /// Error. /// </summary> Error, /// <summary> /// Fatal. /// </summary> Fatal } }
IHasLogSeverity:封装了LogSeverity。UserFriendlyException,AbpValidationException实现了这个接口。Loghelper在对exeption作log的时候能够方便的经过实现了IHasLogSeverity的exeption的实例获取到logSeverity。而后根据logSeverity的级别log.
namespace Abp.Logging { /// <summary> /// Interface to define a <see cref="Severity"/> property (see <see cref="LogSeverity"/>). /// </summary> public interface IHasLogSeverity { /// <summary> /// Log severity. /// </summary> LogSeverity Severity { get; set; } } }
Loghelper: 静态类。调用logger实例(实现Castle的Ilogger接口)完成log操做。
using System; using System.Linq; using Abp.Collections.Extensions; using Abp.Dependency; using Abp.Runtime.Validation; using Castle.Core.Logging; namespace Abp.Logging { /// <summary> /// This class can be used to write logs from somewhere where it's a hard to get a reference to the <see cref="ILogger"/>. /// Normally, use <see cref="ILogger"/> with property injection wherever it's possible. /// </summary> public static class LogHelper { /// <summary> /// A reference to the logger. /// </summary> public static ILogger Logger { get; private set; } static LogHelper() { Logger = IocManager.Instance.IsRegistered(typeof(ILoggerFactory)) ? IocManager.Instance.Resolve<ILoggerFactory>().Create(typeof(LogHelper)) : NullLogger.Instance; } public static void LogException(Exception ex) { LogException(Logger, ex); } public static void LogException(ILogger logger, Exception ex) { var severity = (ex is IHasLogSeverity) ? (ex as IHasLogSeverity).Severity : LogSeverity.Error; logger.Log(severity, ex.Message, ex); LogValidationErrors(logger, ex); } private static void LogValidationErrors(ILogger logger, Exception exception) { //Try to find inner validation exception if (exception is AggregateException && exception.InnerException != null) { var aggException = exception as AggregateException; if (aggException.InnerException is AbpValidationException) { exception = aggException.InnerException; } } if (!(exception is AbpValidationException)) { return; } var validationException = exception as AbpValidationException; if (validationException.ValidationErrors.IsNullOrEmpty()) { return; } logger.Log(validationException.Severity, "There are " + validationException.ValidationErrors.Count + " validation errors:"); foreach (var validationResult in validationException.ValidationErrors) { var memberNames = ""; if (validationResult.MemberNames != null && validationResult.MemberNames.Any()) { memberNames = " (" + string.Join(", ", validationResult.MemberNames) + ")"; } logger.Log(validationException.Severity, validationResult.ErrorMessage + memberNames); } } } }
LoggerExtensions: 扩展了Castle的Ilogger接口的方法,封装更便捷的方法供Loghelper调用。
using System; using Castle.Core.Logging; namespace Abp.Logging { /// <summary> /// Extensions for <see cref="ILogger"/>. /// </summary> public static class LoggerExtensions { public static void Log(this ILogger logger, LogSeverity severity, string message) { switch (severity) { case LogSeverity.Fatal: logger.Fatal(message); break; case LogSeverity.Error: logger.Error(message); break; case LogSeverity.Warn: logger.Warn(message); break; case LogSeverity.Info: logger.Info(message); break; case LogSeverity.Debug: logger.Debug(message); break; default: throw new AbpException("Unknown LogSeverity value: " + severity); } } public static void Log(this ILogger logger, LogSeverity severity, string message, Exception exception) { switch (severity) { case LogSeverity.Fatal: logger.Fatal(message, exception); break; case LogSeverity.Error: logger.Error(message, exception); break; case LogSeverity.Warn: logger.Warn(message, exception); break; case LogSeverity.Info: logger.Info(message, exception); break; case LogSeverity.Debug: logger.Debug(message, exception); break; default: throw new AbpException("Unknown LogSeverity value: " + severity); } } public static void Log(this ILogger logger, LogSeverity severity, Func<string> messageFactory) { switch (severity) { case LogSeverity.Fatal: logger.Fatal(messageFactory); break; case LogSeverity.Error: logger.Error(messageFactory); break; case LogSeverity.Warn: logger.Warn(messageFactory); break; case LogSeverity.Info: logger.Info(messageFactory); break; case LogSeverity.Debug: logger.Debug(messageFactory); break; default: throw new AbpException("Unknown LogSeverity value: " + severity); } } } }
在具体的web项目的application_start方法中注入logger实例。如下是注入log4net代码
public class MvcApplication : AbpWebApplication { protected override void Application_Start(object sender, EventArgs e) { IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig("log4net.config")); base.Application_Start(sender, e); } }