Web APi之异常处理(Exception)以及日志记录(NLog)(十六)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

前言

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

NLog

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

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

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

复制代码
 <targets>
    <target name="logfile" xsi:type="File" fileName="${basedir}/WebAPiNLog/${date:format=yyyyMMdd}.log" /> //在根目录下的WebAPiNlog文件下生成日志
  </targets>
  <rules>
    <logger name="*" minlevel="Trace" writeTo="logfile" />
  </rules>
复制代码

第二步

既然是利用.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<TraceRecord> traceAction);
复制代码

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

using System.Web.Http.Tracing;

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

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

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

复制代码
  private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>>
            (() => new Dictionary<TraceLevel, Action<string>> 
            {{ TraceLevel.Info, NlogLogger.Info }, 
            { TraceLevel.Debug, NlogLogger.Debug },
            { TraceLevel.Error, NlogLogger.Error }, 
            { TraceLevel.Fatal, NlogLogger.Fatal }, 
            { TraceLevel.Warn, NlogLogger.Warn } 
            });
复制代码

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

 private Dictionary<TraceLevel, Action<string>> Logger
 {
       get { return LoggingMap.Value; }
 }

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

复制代码
 public void Trace(System.Net.Http.HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> 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所以就单独拿来讲讲,其强大也是不可言喻的。






本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/4999217.html,如需转载请自行联系原作者

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
6月前
|
人工智能 搜索推荐 IDE
突破网页数据集获取难题:Web Unlocker API 助力 AI 训练与微调数据集全方位解决方案
本文介绍了Web Unlocker API、Web-Scraper和SERP API三大工具,助力解决AI训练与微调数据集获取难题。Web Unlocker API通过智能代理和CAPTCHA绕过技术,高效解锁高防护网站数据;Web-Scraper支持动态内容加载,精准抓取复杂网页信息;SERP API专注搜索引擎结果页数据抓取,适用于SEO分析与市场研究。这些工具大幅降低数据获取成本,提供合规保障,特别适合中小企业使用。粉丝专属体验入口提供2刀额度,助您轻松上手!
304 2
|
6月前
|
人工智能 运维 安全
网络安全公司推荐:F5荣膺IDC全球Web应用与API防护领导者
网络安全公司推荐:F5荣膺IDC全球Web应用与API防护领导者
129 4
|
9月前
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
475 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
7月前
|
XML JSON API
Understanding RESTful API and Web Services: Key Differences and Use Cases
在现代软件开发中,RESTful API和Web服务均用于实现系统间通信,但各有特点。RESTful API遵循REST原则,主要使用HTTP/HTTPS协议,数据格式多为JSON或XML,适用于无状态通信;而Web服务包括SOAP和REST,常用于基于网络的API,采用标准化方法如WSDL或OpenAPI。理解两者区别有助于选择适合应用需求的解决方案,构建高效、可扩展的应用程序。
|
7月前
|
机器学习/深度学习 开发框架 API
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
10月前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
258 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
11月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
223 1
|
11月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
605 2
|
5月前
|
监控 容灾 算法
阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
本文探讨了如何高效、经济且可靠地将海外应用与基础设施日志统一采集至阿里云日志服务(SLS),解决全球化业务扩展中的关键挑战。重点介绍了高性能日志采集Agent(iLogtail/LoongCollector)在海外场景的应用,推荐使用LoongCollector以获得更优的稳定性和网络容错能力。同时分析了多种网络接入方案,包括公网直连、全球加速优化、阿里云内网及专线/CEN/VPN接入等,并提供了成本优化策略和多目标发送配置指导,帮助企业构建稳定、低成本、高可用的全球日志系统。
629 54