基于DDD的.NET开发框架 - ABP日志Logger集成
ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。
ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。
ABP的官方网站:http://www.aspnetboilerplate.com
ABP官方文档:http://www.aspnetboilerplate.com/Pages/Documents
Github上的开源项目:https://github.com/aspnetboilerplate
一、基本概念
ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等。对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方便的处理各种特殊的日志库,而且当业务需要的时候,很容易替换日志组件。
Castle是什么:Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架、AOP,基本包括了整个开发过程中的所有东西。ASP.NET Boilerplate的ioc容器就是通过Castle实现的。
Log4Net是.Net中最流行的日志类库之一。ABP模板中自带了经过合适配置的Log4Net。但是,只存在一行log4net的依赖(看下面),因此,你可以将它改为你最喜欢的类库。
获取Logger:
无论你选择了什么日志类库,最终要记录的日志代码都是相同的
一开始,我们要处理一下记录日志的Logger对象。因为ABP强烈推荐使用依赖注入,所以我们可以使用属性注入模式轻松地注入一个Logger对象。如下所示:
using Castle.Core.Logging; //1、导入 Logging 命名空间
public class TaskAppService : ITaskAppService
{
//2、使用属性注入获得 logger
public ILogger Logger { get; set; }
public TaskAppService()
{
//3、如果没有提供Logger,就不能记录日志
Logger = NullLogger.Instance;
} public void CreateTask(CreateTaskInput input)
{
//4、记录日志
Logger.Info("Creating a new task with description: " + input.Description); //TODO: 保存到数据库...
}
}
1、导入Castle的ILogger接口的命名空间。
2、定义一个公有的叫做Logger的ILogger对象。这是记录日志的对象。创建TaskAppService对象之后,依赖注入系统会自动注入这个属性。这就是所谓的属性注入模式。
3、将Logger设置为NullLogger.Instance。即使没有这行代码,系统也会工作地很好。但是这是属性注入模式的最佳实践。如果没给Logger设置任何值,那么当我们使用它的时候会因为它是null而抛出“空指针”异常。这个保证了它不为null。因此,如果没有给Logger设置值,那么它是NullLogger。这就是所谓的null对象模式。NullLogger实际上什么都没做,也没有记录任何日志。因此,我们的类要不要一个实际的logger都能工作。
4、最后,我们记录了一个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的所有配置都自动生成了。
默认的配置格式如下:
- Log level: 日志记录等级,有DEBUG, INFO, WARN, ERROR or FATAL5个。
- Date and time: 日志记录时间。
- Thread number: 每行日志写时候的线程号。
- Logger name: 日志记录器的名字,通常情况就是类名称。
- Log text: 你写入的日志内容。
配置文件: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="" />
<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...');
二、ABP底层代码分析


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);
}
}
基于DDD的.NET开发框架 - ABP日志Logger集成的更多相关文章
- 线上分享-- 基于DDD的.NET开发框架-ABP介绍
前言 为了能够帮助.Net开发者开拓视野,更好的把最新的技术应用到工作中,我在3月底受邀到如鹏网.net训练营直播间为各位学弟学妹们进行ABP框架的直播分享.同时为了让更多的.NET开发者了解ABP框 ...
- 基于DDD的.NET开发框架 - ABP模块设计
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP领域服务
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP初探
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP分层设计
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP的Entity设计思想
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP Session实现
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架 - ABP依赖注入
返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- 基于DDD的.NET开发框架ABP实例,多租户 (Sass)应用程序,采用.NET MVC, Angularjs, EntityFramework-介绍
介绍 基于ABPZERO的多租户 (Sass)应用程序,采用ASP.NET MVC, Angularjs-介绍 ASP.NET Boilerplate作为应用程序框架. ASP.NET MVC和ASP ...
随机推荐
- 利用 druid 解析器解析SQL
最近参与一个开源项目,一个功能的实现,用到了 druid 解析器来解析SQL,记录下如果使用 druid 来解析SQL,实现对SQL的拦截改写. 1. 对 insert 语句进行解析: private ...
- vue相关的 helloword示例
<!DOCTYPE html><html> <head> <title></title> <script src="http ...
- 解决SQL死循环问题
解决SQL死循环问题 当我们在执行在使用for循环的时候,往往会遇到死循环的问题,我们可以通过SSH来连接数据库,并结束其进程:代码如下: Su - db2inst1 Db2 connect to s ...
- C# 计算文件MD5
因工作需要对文件进行是否被修改判断,整理的一段生成文件MD5码的代码: 1: public class FileHelper 2: { 3: /// <summary> 4: /// 对文 ...
- 《Remus: High Availability via Asychronous Virtual Machine Replication》翻译
Abstract 想要让应用能够躲过硬件故障是一项非常昂贵的任务,因为这通常意味着对软件进行重构,使它包含复杂的恢复逻辑的同时需要部署专用的硬件,而这些对于提升大型的或者遗留的应用的可靠性是巨大的障碍 ...
- 我的Github之旅(一)
第一站:本地环境中的Github配置 1.参考链接 作为初学者,需要了解的有[本地环境中的github配置(基于mac)][1],以及git知识,这里推荐一个网站[猴子都能懂的Git入门][2],最后 ...
- docker-image container 基本操作 -常用命令
基本概念: container 容器.可以把每个 container 看做是一个独立的主机. container 的创建通常有一个 image 作为其模板.类比成虚拟机的话可以理解为 image 就是 ...
- VS 代码Diff 之Beyone Compare
前提条件 机器已安装 beyone compared软件和 visual svn for vs 插件. 在VS中集成SVN,我推荐使用 visual svn扩展. visual svn 官网:http ...
- nginx 入门
1.nginx 如何处理一个请求 IP,域名的处理 server { listen 80 default_server; //添加 default_server就是一个默认的server ...
- hdu 1166
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...