博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Web APi之异常处理(Exception)以及日志记录(NLog)(十六)
阅读量:7070 次
发布时间:2019-06-28

本文共 7639 字,大约阅读时间需要 25 分钟。

前言

上一篇文章我们介绍了关于日志记录用的是Log4net,确实也很挺强大,但是别忘了我们.NET有专属于我们的日志框架,那就是NLog,相对于Log4net而言,NLog可以说也是一个很好的记录日志的框架,并且其中的异步日志等都有非常大的改善,本文借此用了最新的NLog来在Web APi中进行记录日志。

NLog

第一步则是下载我们需要的程序包,包括程序集以及配置文件

利用NLog记录日志同样可以实现如我们上篇文章利用Log4net来实现的那样,所以在这里就不多说,下面我们来讲另外一种方式,那就是利用.NET内置的跟踪级别类来进行记录日志。从而达到我们所需。

在NLog.config配置文件中,我们添加如下进行日志的记录【注意:只是简单的利用了NLog,它还是比较强大,更多的详细内容请到官网或通过其他途径进行学习】

//在根目录下的WebAPiNlog文件下生成日志

第二步

既然是利用.NET内置的跟踪级别类来实现,那么我们就需要实现其接口 ITraceWriter ,该接口需要实现如下方法

// 摘要:         //     当且仅当在给定 category 和 level 允许跟踪时,调用指定的 traceAction 以允许在新的 System.Web.Http.Tracing.TraceRecord        //     中设置值。        //        // 参数:         //   request:        //     当前 System.Net.Http.HttpRequestMessage。它可以为 null,但这样做将阻止后续跟踪分析将跟踪与特定请求关联。        //        //   category:        //     跟踪的逻辑类别。用户可以定义自己的跟踪。        //        //   level:        //     写入此跟踪时所在的 System.Web.Http.Tracing.TraceLevel。        //        //   traceAction:        //     启用了跟踪时要调用的操作。在此操作中,调用方应填充给定 System.Web.Http.Tracing.TraceRecord 的各个字段。        void Trace(HttpRequestMessage request, string category, TraceLevel level, Action
traceAction);

【注意】利用内置的跟踪级别则需要引用如下命名空间

using System.Web.Http.Tracing;

首先创建一个NLogger类并实现如上接口,当然我们也得创建NLog实例并利用其实例进行级别处理,如下:

private static readonly Logger NlogLogger = LogManager.GetCurrentClassLogger();

接着我们该如何做呢?我们需要利用 TraceLevel 跟踪级别,同时结合NLog得到相应的级别信息,可能创建对象实例的过程比较长,我们可以利用Lazy<>来实现延迟加载,代码如下:

private static readonly Lazy
>> LoggingMap = new Lazy
>> (() => new Dictionary
> {
{ TraceLevel.Info, NlogLogger.Info }, { TraceLevel.Debug, NlogLogger.Debug }, { TraceLevel.Error, NlogLogger.Error }, { TraceLevel.Fatal, NlogLogger.Fatal }, { TraceLevel.Warn, NlogLogger.Warn } });

然后,我们定义一个属性来返回其实例的值,如下

private Dictionary
> Logger { get { return LoggingMap.Value; } }

紧接着我们就是实现上述ITraceWriter接口

public void Trace(System.Net.Http.HttpRequestMessage request, string category, TraceLevel level, Action
traceAction) { if (level != TraceLevel.Off) //如果没用禁用日志跟踪 { if (traceAction != null && traceAction.Target != null) { category = category + Environment.NewLine + "Action Parameters : " + JsonConvert.SerializeObject(traceAction.Target); } var record = new TraceRecord(request, category, level); if (traceAction != null) traceAction(record); Log(record); } }

我们记录请求的参数,URL,以及Token、返回的JSON等等,上述Log方法则如下

private void Log(TraceRecord record) {            var message = new StringBuilder();            if (!string.IsNullOrWhiteSpace(record.Message))                message.Append("").Append(record.Message + Environment.NewLine);            if (record.Request != null)            {                if (record.Request.Method != null)                    message.Append("Method: " + record.Request.Method + Environment.NewLine);                if (record.Request.RequestUri != null)                    message.Append("").Append("URL: " + record.Request.RequestUri + Environment.NewLine);                if (record.Request.Headers != null && record.Request.Headers.Contains("Token") && record.Request.Headers.GetValues("Token") != null && record.Request.Headers.GetValues("Token").FirstOrDefault() != null)                    message.Append("").Append("Token: " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);            }            if (!string.IsNullOrWhiteSpace(record.Category))                message.Append("").Append(record.Category);            if (!string.IsNullOrWhiteSpace(record.Operator))                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);}

第三步 

我们自定义日志特性取名为 NLogFilterAttribute ,我们在访问Action时来进行记载日志也就是需要继承于 ActionFilterAttribute ,简单来说代码如下:

public class NLogFilterAttribute : ActionFilterAttribute {        public override void OnActionExecuting(HttpActionContext filterContext)        {......} }

那么问题来了,.NET默认确确实实是走得内置的跟踪级别,我们如何让其实现我们上述实现的接口的级别呢?

此时我们之前所学就派上了一点用场,我们将其服务容器的关于ITraceWriter接口实现进行替换我们自定义实现的接口即可,用如下一句即可

GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper());

接下来就是从服务容器中获取我们自定义实现的跟踪级别

var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();

然后调用比如说隔离级别中的Info,获取其访问的控制器名、Action名称以及JSON等数据,如下:

trace.Info(filterContext.Request,                 "Controller : " + filterContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine +                 "Action : " + filterContext.ActionDescriptor.ActionName,                 "JSON", filterContext.ActionArguments);

我们简单个给出所请求的控制器以及需要返回的数据,如下:

public class AboutController : ApiController    {        [POST("about")]        public string about()        {            var test = new            {                name = "xpy0928",                gender = "男",                age = 12            };            return Newtonsoft.Json.JsonConvert.SerializeObject(test);        }    }

接下来我们利用WebAPiTestOnHelpPage进行测试,看结果是否如我们所期望

结果如我们所期待的那样

但是我们的重点是是否生成了相应的日志,我们一起来看下:

到此,关于利用.NET内置的跟踪级别结合NLog来实现日志的记录也就告一段落,接下来我们来看看异常处理

Exception

既然异常处理,那么我们当然就得利用自定义异常特性实现 ExceptionFilterAttribute ,其基本实现如下:

public class CustomExceptionAttribute:ExceptionFilterAttribute {        public override void OnException(HttpActionExecutedContext actionExecutedContext)        {....} }

关于其实现和上面大同小异,如下

GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new NLogHelper());            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();            trace.Error(actionExecutedContext.Request, "Controller : " + actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + actionExecutedContext.ActionContext.ActionDescriptor.ActionName, actionExecutedContext.Exception);            var exceptionType = actionExecutedContext.Exception.GetType();            if (exceptionType == typeof(ValidationException))            {                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(actionExecutedContext.Exception.Message), ReasonPhrase = "ValidationException", };                throw new HttpResponseException(resp);            }            else if (exceptionType == typeof(UnauthorizedAccessException))            {                throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.Unauthorized));            }            else            {                throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError));            }

此时我们还需要在日志NLogger类中添加如下一句

//处理异常            if (record.Exception != null && !string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))            {                var exceptionType = record.Exception.GetType();                message.Append(Environment.NewLine);                message.Append("").Append("Error: " + record.Exception.GetBaseException().Message + Environment.NewLine);            }

如此就基本实现了利用NLog记录异常,当然我们可以自定义个异常类来更好的管理异常例如,如下:

public class ApiExceptions:Exception    {        int ErrorCode { get; set; }        string ErrorDescription { get; set; }        HttpStatusCode HttpStatus { get; set; }    }

总结

本节我们学习了利用NLog来实现记录异常通过集合内置的跟踪级别。NLog是属于.NET所以就单独拿来讲讲,其强大也是不可言喻的。

 

转载于:https://www.cnblogs.com/CreateMyself/p/4999217.html

你可能感兴趣的文章
巴斯卡三角形
查看>>
产品和团队
查看>>
mysql取差集、交集、并集
查看>>
三层架构—简析
查看>>
利用linux shell自己主动顶贴
查看>>
[转]MVC Razor模板引擎 @RenderBody、@RenderPage、@RenderSection及Html.RenderPartial、Html.RenderAction...
查看>>
bzoj 1860: [Zjoi2006]Mahjong麻将 题解
查看>>
第21章 RTX 低功耗之睡眠模式
查看>>
拉格朗日插值
查看>>
递归函数的写法笔记
查看>>
net 自定义泛型那点事
查看>>
免费「模拟面试」福利反馈连载(20180128期)
查看>>
交叉熵代价函数——当我们用sigmoid函数作为神经元的激活函数时,最好使用交叉熵代价函数来替代方差代价函数,以避免训练过程太慢...
查看>>
nxn随机矩阵乘以概率向量依旧是概率向量
查看>>
【转载】TCP协议要点和难点全解
查看>>
mysql修改表、字段、库的字符集
查看>>
realm vs. domain
查看>>
关闭Spring Boot的Jsckson的FAIL_ON_EMPTY_BEANS
查看>>
Oracle 切割字符查询
查看>>
结构体内存对齐具体解释
查看>>