专栏首页依乐祝Net Core集成Exceptionless分布式日志功能以及全局异常过滤

Net Core集成Exceptionless分布式日志功能以及全局异常过滤

Net Core集成Exceptionless分布式日志功能以及全局异常过滤

相信很多朋友都看过我的上篇关于Exceptionless的简单入门教程[asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程][https://www.cnblogs.com/yilezhu/p/9193723.html] 上篇文章只是简单的介绍了Exceptionless是什么?能做什么呢?以及怎么进行本地部署和异常提交的简单用法,而这篇文章将带你探讨一下Exceptionless的异常收集高级用法以及你熟悉的类似NLog的日志用法。

这篇文章有一部分内容翻译自官方文档,[点我阅读][https://github.com/exceptionless/Exceptionless.Net/wiki/Sending-Events] 英语好的可以自行阅读 。当然中间很多代码我都进行了重构,还有参考周旭龙的代码,进行了简单地封装,同时加入了为webapi加入异常全局过滤器进行异常日志的记录。希望对大家有所帮助。

本文地址:https://www.cnblogs.com/yilezhu/p/9339017.html 作者:依乐祝

手动发送错误

上篇文章介绍了,导入命名空间后,并使用如下代码就可以简单地提交异常日志:

try {
    throw new ApplicationException(Guid.NewGuid().ToString());
} catch (Exception ex) {
    ex.ToExceptionless().Submit();
}

发送附加信息

当然你还可以为发送的事件添加额外的标记信息,比如坐标,标签,以及其他的用户相关的信息等等

try {
    throw new ApplicationException("Unable to create order from quote.");
} catch (Exception ex) {
    ex.ToExceptionless()
        // 设置一个ReferenceId方便查找
        .SetReferenceId(Guid.NewGuid().ToString("N"))
        // 添加一个不包含CreditCardNumber属性的对象信息
        .AddObject(order, "Order", excludedPropertyNames: new [] { "CreditCardNumber" }, maxDepth: 2)
        // 设置一个名为"Quote"的编号
        .SetProperty("Quote", 123)
        // 添加一个名为“Order”的标签
        .AddTags("Order")
        //  标记为关键异常
        .MarkAsCritical()
        // 设置一个位置坐标
        .SetGeo(43.595089, -88.444602)
        // 在你的系统中设置userid并提供一个有好的名字,俗称昵称
        .SetUserIdentity(user.Id, user.FullName)
        // 为异常信息添加一些用户描述信息.
        .SetUserDescription(user.EmailAddress, "I tried creating an order from my saved quote.")
        // 提交.
        .Submit();
}

统一修改未处理的异常报告

你可以在通过SubmittingEvent 事件设置全局的忽略异常信息添加一些自定义信息等等

 #region Exceptionless配置
            ExceptionlessClient.Default.Configuration.ApiKey = exceptionlessOptions.Value.ApiKey;
            ExceptionlessClient.Default.Configuration.ServerUrl = exceptionlessOptions.Value.ServerUrl;
            ExceptionlessClient.Default.SubmittingEvent += OnSubmittingEvent;
            app.UseExceptionless();
#endregion

 /// <summary>
        /// 全局配置Exceptionless
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSubmittingEvent(object sender, EventSubmittingEventArgs e)
        {
            // 只处理未处理的异常
            if (!e.IsUnhandledError)
                return;

            // 忽略404错误
            if (e.Event.IsNotFound())
            {
                e.Cancel = true;
                return;
            }

            // 忽略没有错误体的错误
            var error = e.Event.GetError();
            if (error == null)
                return;
            // 忽略 401 (Unauthorized) 和 请求验证的错误.
            if (error.Code == "401" || error.Type == "System.Web.HttpRequestValidationException")
            {
                e.Cancel = true;
                return;
            }
            // Ignore any exceptions that were not thrown by our code.
            var handledNamespaces = new List<string> { "Exceptionless" };
            if (!error.StackTrace.Select(s => s.DeclaringNamespace).Distinct().Any(ns => handledNamespaces.Any(ns.Contains)))
            {
                e.Cancel = true;
                return;
            }
            // 添加附加信息.
            //e.Event.AddObject(order, "Order", excludedPropertyNames: new[] { "CreditCardNumber" }, maxDepth: 2);
            e.Event.Tags.Add("MunicipalPublicCenter.BusinessApi");
            e.Event.MarkAsCritical();
            //e.Event.SetUserIdentity();
        }

配合使用 NLog 或 Log4Net

有时候,程序中需要对日志信息做非常详细的记录,比如在开发阶段。这个时候可以配合 log4net 或者 nlog 来联合使用 exceptionless,详细可以查看这个官方的 [示例][https://github.com/exceptionless/Exceptionless.Net/tree/master/samples/Exceptionless.SampleConsole]。

如果你的程序中有在短时间内生成大量日志的情况,比如一分钟产生上千的日志。这个时候你需要使用内存存储(in-memory store)事件,这样客户端就不会将事件系列化的磁盘,所以会快很多。这样就可以使用Log4net 或者 Nlog来将一些事件存储到磁盘,另外 Exceptionless 事件存储到内存当中。

Exceptionless 日志记录的封装

  1. 首先简单地封装一个ILoggerHelper接口
/// <summary>
    /// lzhu
    /// 2018.7.19
    /// 日志接口
    /// </summary>
    public interface ILoggerHelper
    {
        /// <summary>
        /// 记录trace日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        void Trace(string source, string message, params string[] args);
        /// <summary>
        /// 记录debug信息
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        void Debug(string source, string message, params string[] args);
        /// <summary>
        /// 记录信息
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        void Info(string source, string message, params string[] args);
        /// <summary>
        /// 记录警告日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        void Warn(string source, string message, params string[] args);
        /// <summary>
        /// 记录错误日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        void Error(string source, string message, params string[] args);
    }
  1. 既然有了接口,那么当然得实现它了
/// <summary>
    /// lzhu
    /// 2018.7.19
    /// Exceptionless日志实现
    /// </summary>
    public class ExceptionlessLogger : ILoggerHelper
    {
        /// <summary>
        /// 记录trace日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">添加标记</param>
        public void Trace(string source,string message, params string[] args)
        {
            if (args != null && args.Length > 0)
            {
                ExceptionlessClient.Default.CreateLog(source, message, LogLevel.Trace).AddTags(args).Submit();

            }
            else
            {
                ExceptionlessClient.Default.SubmitLog(source, message, LogLevel.Trace);
            }
        }
        /// <summary>
        /// 记录debug信息
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        public void Debug(string source, string message, params string[] args)
        {
            if (args != null && args.Length > 0)
            {
                ExceptionlessClient.Default.CreateLog(source, message, LogLevel.Debug).AddTags(args).Submit();
            }
            else
            {
                ExceptionlessClient.Default.SubmitLog(source, message, LogLevel.Debug);
            }
        }
        /// <summary>
        /// 记录信息
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        public void Info(string source, string message, params string[] args)
        {
            if (args != null && args.Length > 0)
            {
                ExceptionlessClient.Default.CreateLog(source, message, LogLevel.Info).AddTags(args).Submit();
            }
            else
            {
                ExceptionlessClient.Default.SubmitLog(source, message, LogLevel.Info);
            }
        }
        /// <summary>
        /// 记录警告日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        public void Warn(string source, string message, params string[] args)
        {
            if (args != null && args.Length > 0)
            {
                ExceptionlessClient.Default.CreateLog(source, message, LogLevel.Warn).AddTags(args).Submit();
            }
            else
            {
                ExceptionlessClient.Default.SubmitLog(source, message, LogLevel.Warn);
            }
        }
        /// <summary>
        /// 记录错误日志
        /// </summary>
        /// <param name="source">信息来源</param>
        /// <param name="message">日志内容</param>
        /// <param name="args">标记</param>
        public void Error(string source, string message, params string[] args)
        {
            if (args != null && args.Length > 0)
            {
                ExceptionlessClient.Default.CreateLog(source, message, LogLevel.Error).AddTags(args).Submit();
            }
            else
            {
                ExceptionlessClient.Default.SubmitLog(source, message, LogLevel.Error);
            }
        }
    }
  1. 当然实现好了,可别忘了依赖注入哦
 //注入ExceptionlessLogger服务
            services.AddSingleton<ILoggerHelper, ExceptionlessLogger>();

这时候该写一个全局异常过滤器了

/// <summary>
    /// lzhu
    /// 2018.7.19
    /// 定义全局过滤器
    /// </summary>
    public class GlobalExceptionFilter : IExceptionFilter
    {

        private readonly ILoggerHelper _loggerHelper;
        //构造函数注入ILoggerHelper
        public GlobalExceptionFilter(ILoggerHelper loggerHelper)
        {
            _loggerHelper = loggerHelper;
        }

        public void OnException(ExceptionContext filterContext)
        {
            _loggerHelper.Error(filterContext.Exception.TargetSite.GetType().FullName, filterContext.Exception.ToString(), MpcKeys.GlobalExceptionCommonTags, filterContext.Exception.GetType().FullName);
            var result = new BaseResult()
            {
                errcode = ResultCodeAddMsgKeys.CommonExceptionCode,//系统异常代码
                errmsg= ResultCodeAddMsgKeys.CommonExceptionMsg,//系统异常信息
            };
            filterContext.Result = new ObjectResult(result);
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            filterContext.ExceptionHandled = true;
        }
    }
  1. 全局过滤器写好了,怎么让它生效呢,客观别急啊,上正菜
//添加验证
            services.AddMvc(options=> {
                options.Filters.Add<GlobalExceptionFilter>();
            }).AddFluentValidation();

哈哈,没什么说的了,代码都已经写好了,剩下的就是上代码测试结果了。我这里只是简单地api测试下,万能的ValuesController登场:

// GET api/values/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            //try
            //{
            throw new Exception($"测试抛出的异常{id}");
            //}
            //catch (Exception ex)
            //{
            //    ex.ToExceptionless().Submit();
            //}
            //return "Unknown Error!";

        }

这里是直接抛出异常,不进行trycatch,这时候异常会被全局过滤器捕获,然后放到Exceptionless的Log里面,别问我为什么会在log里面,因为我全局过滤器代码里面已经写明了,不明白的回去看代码,然后看接口调用的实现方法。下面上结果:

点进去,看看详细信息:

  1. 再测试下使用try catch捕获的异常处理,这时候异常信息会被提交到Exception这个里面。直接上代码吧 // GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { try { throw new Exception($"测试抛出的异常{id}"); } catch (Exception ex) { ex.ToExceptionless().Submit(); } return "Unknown Error!"; } 到exceptionless里面看看不活的异常吧。打字很累直接上图吧

点进去看看详细信息,有三个tab,下面之粘贴一个图片了:

最后,源码就不上了,因为上面代码很清楚了 总结 本文没有对Exceptionless进行过多地介绍,因为博主的[上篇文章][https://www.cnblogs.com/yilezhu/p/9193723.html] 已经进行了详细的介绍。直接切入正题,先对官方高级用法进行了简单地翻译。然后对Exceptionless Log这个eventtype进行了简单地封装,让你可以像使用NLog一样很爽的使用Exceptionless。最后通过一个asp.net core web api的项目进行了演示,在全局过滤器中利用封装的Log方法进行全局异常的捕获。希望对大家使用Exceptionless有所帮助。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现

    本篇我将带着大家一起来对Dapper进行下封装并实现基本的增删改查、分页操作的同步异步方法的实现(已实现MSSQL,MySql,PgSQL)。同时我们再实现一下...

    依乐祝
  • 一个.NET Core开发者的Linux入门学习笔记

    用.NET Core开发也有一段时间了,但是由于工作原因一直都是在Windows系统上进行的开发,一直想学习Linux然后把.NET Core开发的程序跑在Li...

    依乐祝
  • Ocelot简易教程(六)之重写配置文件存储方式并优化响应数据

    本来这篇文章在昨天晚上就能发布的,悲剧的是写了两三千字的文章居然没保存,结果我懵逼了。今天重新来写这篇文章。今天我们就一起来探讨下如何重写Ocelot配置文件的...

    依乐祝
  • 从零开始深度学习(五):导数

    这一次主要是想对微积分和导数直观理解一下。很多人在想或许自从大学毕以后,再也没有接触微积分。不要担心,为了高效应用神经网络和深度学习,其实 并不需要非常深入理解...

    我是管小亮
  • 想做流程审批的开发?带你玩转Activity工作流(一)

    现在的很多传统企业转型互联网,最多的“转型”工作之一,就是公司的流程审批模块,如何进行线上操作。最常见的场景,比如请假审批、报表审批、财务审批、人员招聘等等。

    23号杂货铺
  • 基于物品的协调过滤算法

    基于物品的协同过滤(item-based collaborative filtering)算法是目前业界应用最多的算法。无论是亚马逊网,还是Netflix、 ...

    机器学习AI算法工程
  • 关于Oracle降序索引的定意及回溯

    降序索引本质上是FBI,其具体定义可以通过 user_ind_expressions 或dba_ind_expressions 查询。 那么同样的,降序索引只有...

    数据和云01
  • 解密如何让客户下单的六要素|腾讯SaaS加速器·学堂

    ? 来源:六要素营销咨询创始人陈勇 ---- 相对于消费者市场,企业级市场是难做的。对于很多To B 企业,除了打磨自身商业模式、产品技术外,更关键的是如何摆...

    腾讯SaaS加速器
  • SpringMVC自学笔记

    1.<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-clas...

    阮键
  • 大数据快速入门(05):MapReduce 编程模型赏析

    Cutting 的第一份工作是在 Xerox 做实习生,为激光扫描仪上的操作系统开发屏幕保护程序,这也是他最早的“平台”级的作品。

    kk大数据

作者介绍

依乐祝

安徽容知日新科技股份有限公司高级软件开发工程师

安徽容知日新科技股份有限公司 · 高级软件开发工程师 (已认证)

精选专题

活动推荐

扫码关注云+社区

领取腾讯云代金券