.NET Core集成Exceptionless分布式日志功能

点击上方“程序员大咖”,选择“置顶公众号”

关键时刻,第一时间送达!640?640?wx_fmt=gif















































































































































































































































































































    先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明明只是灵武七重,而在这两个月不到的时间,连跳两重修为,又跳过一个大境界,踏入了元武一重,这般进步速度,简直堪称变态啊。


    “这楚枫不简单,原来是一位天才,若是让他继续成长下去,绝对能成为一号人物,不过可惜,他太狂妄了,竟与龚师兄定下生死约战,一年时间,他再厉害也无法战胜龚师兄。”有人认识到楚枫的潜力后,为楚枫感到惋惜。


    “哼,何须一年,此子今日就必败,巫九与龚师兄关系甚好,早就看他不顺眼了,如今他竟敢登上生死台挑战巫九,巫九岂会放过他?”但也有人认为,楚枫今日就已是在劫难逃。


    “何人挑战老子?”就在这时,又是一声爆喝响起,而后一道身影自人群之中掠出,最后稳稳的落在了比斗台上。


    这位身材瘦弱,身高平平,长得那叫一个猥琐,金钩鼻子蛤蟆眼,嘴巴一张牙带色儿,说话臭气能传三十米,他若是当面对谁哈口气,都能让那人跪在地上狂呕不止。


    不过别看这位长得不咋地,他在核心地带可是鼎鼎有名,剑道盟创建者,青龙榜第九名,正是巫九是也。


    “你就是巫九?”楚枫眼前一亮,第一次发现,世间还有长得如此奇葩的人。


    巫九鼻孔一张,大嘴一咧,拍着那干瘪的肚子,得意洋洋的道:“老子就是巫九,你挑战老子?”


    “不是挑战你,是要宰了你。”楚枫冷声笑道。


    “好,老子满足你这个心愿,长老,拿张生死状来,老子今日在这里了解了这小子。”巫九扯开嗓子,对着下方吼了一声。


    如果他对内门长老这么说话,也就算了,但是敢这么跟核心长老说话的,他可真是算作胆肥的,就连许多核心弟子,都是倒吸了一口凉气,心想这楚枫够狂,想不到这巫九更狂。


    不过最让人无言的就是,巫九话音落下不久,真有一位核心长老自人群走出,缓缓得来到了比斗台上,左手端着笔墨,右手拿着生死状,来到了巫九的身前。


    “我去,这巫九什么身份,竟能这般使唤核心长老?”有人吃惊不已,那长老修为不低,乃是元武七重,比巫九还要高两个层次,但却这般听巫九的话,着实让人吃惊不已。


    “这你就不知道了吧,巫九在前些时日,拜了钟离长老为师尊,已正式得到钟离长老的亲传。”有人解释道。


    “钟离长老?可是那位性情古怪的钟离一护?”


    “没错,就是他。”


    “天哪,巫九竟然拜入了他的门下?”


    人们再次大吃一惊,那钟离一护在青龙宗可是赫赫有名,若要是论其个人实力,在青龙宗内绝对能够排入前三,连护宗六老单打独斗都不会是他的对手。


    只不过那钟离一护,如同诸葛青云一样,也是一位客卿长老,所以在青龙宗内只是挂个头衔,什么事都不管,更别说传授宗内弟子技艺了,如今巫九竟然能拜入他老人家门下,着实让人羡慕不已。


    “恩怨生死台,的确可以决斗生死,但必须要有所恩怨,你们两个人,可有恩怨?”那位长老开口询问道。































































































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


这篇文章有一部分内容翻译自官方文档https://github.com/exceptionless/Exceptionless.Net/wiki/Sending-Events]

英语好的可以自行阅读 。


当然中间很多代码我都进行了重构,还有参考周旭龙的代码,进行了简单地封装,同时加入了为webapi加入异常全局过滤器进行异常日志的记录。希望对大家有所帮助。


手动发送错误


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


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);

}


2、既然有了接口,那么当然得实现它了


/// <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);

        }

    }

}


3、当然实现好了,可别忘了依赖注入哦


 //注入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;

    }

}


全局过滤器写好了,怎么让它生效呢,客观别急啊,上正菜


//添加验证

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里面,因为我全局过滤器代码里面已经写明了,不明白的回去看代码,然后看接口调用的实现方法。下面上结果:


640?wx_fmt=png


点进去,看看详细信息:


640?wx_fmt=png


再测试下使用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里面看看不活的异常吧。打字很累直接上图吧


640?wx_fmt=png


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


640?wx_fmt=png


最后,源码就不上了,因为上面代码很清楚了


总结


本文没有对Exceptionless进行过多地介绍,因为博主的上篇文章《ASP.NET Core免费开源分布式异常日志收集框架Exceptionless》https://mp.weixin.qq.com/s/IuSrcFt_VkyvSQwkGE5VpQ已经进行了详细的介绍。


直接切入正题,先对官方高级用法进行了简单地翻译。然后对Exceptionless Log这个eventtype进行了简单地封装,让你可以像使用NLog一样很爽的使用Exceptionless。


最后通过一个asp.net core web api的项目进行了演示,在全局过滤器中利用封装的Log方法进行全局异常的捕获。希望对大家使用Exceptionless有所帮助。


640.jpeg

  • 来源:依乐祝

  • cnblogs.com/yilezhu/p/9339017.html

  • 程序员大咖整理发布,转载请联系作者获得授权

640?wx_fmt=gif640?【点击成为源码大神】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言在互联网时代,分布式应用、系统变得越来越多,我们在使用 .Net 技术构建分布式系统的时候,需要使用到一些组件或者是助手库来帮助我们提高生产力以及应用程序解耦,但是纵观.Net圈,能够符合要求的这样的组件并不是 很多,并且没有一个通用的抽象组件能够将这些接口集成起来,今天就为大家介绍一款开源的组件库 Foundatio,他们同样出自于Exceptionless团队之手,下面就来看看吧。目录Foundatio 介绍Getting Started缓存队列锁消息工作任务文件存储度量日志示例程序源码总结Foundatio 介绍GitHub : https://github.com/exceptionless/FoundatioFoundatio 是一个插件式的,松耦合的一套构建分布式应用的程序库,出自于Exceptionless团队。Foundatio 同时支持 .NET Framework 4.6 和 .NET Core。通过 Foundatio 我可以获得哪些帮助呢?如果你是面对接口(抽象)构建的程序,你可以很容易的对接口实现进行切换。具有友好的依赖注入,还在使用 .Net Framework的朋友可以体验一下,它具有比Autofac,Unity等更简易的操作和更友好的接口。可以更加方便的使用缓存了,Foundatio帮助我们封装了很多缓存的客户端实现,比如RedisCache、InMemoryCache、ScopedCache等等。消息总线,你不必自己构建或者使用复杂且昂贵的NServiceBus了,很多时候我们仅仅需要的是一个可以在本地或者云上运行的简单的消息总线。存储,现在你可以很方便的通过一致的接口来使用分布式存储了,包括内存文件存储、文件夹文件存储,Azure文件存储,AWS S3文件存储。Foundatio 主要包含以下模块:缓存(Caching)队列(Queues)锁(Locks)消息(Messaging)工作任务(Jobs)文件存储(File Storage)度量(Metrics)日志(Logging)这些组件都以NuGet包的形式提供出来供我们很方便的使用,下面依次来看看每一个组件的用途和使用方法吧。Getting Started缓存缓存是一种空间换时间的技术,你可以通过缓存来快速的获取一些数据。Foundatio Cache 提供了一致的接口ICacheClient 来很容易的存储或者读取缓存数据,并且提供了4中不同的缓存客户端的实现。他们分别是:1、InMemoryCacheClient:内存缓存的实现,这种缓存的生命周期为当前进程, 有一个MaxItems属性,可以设置最多缓存多少条数据。2、HybridCacheClient:InMemoryCacheClient 具有相同的实现,但是此接口提供、IMessageBus 可以用来跨线程之间的同步。3、RedisCacheClient:一个 Redis 客户端的实现。4、RedisHybridCacheClient:一个RedisCacheClient 、InMemoryCacheClient 的混合实现,通过RedisMessageBus来保持内存缓存跨线程之间的同步。注意:如果本地缓存的项已经存在,在调用Redis进行序列化保存的时候可能会有性能问题。5、ScopedCacheClient:传入ICacheClient和scope,scope 可以设置一个字符串,来制定一个缓存键前缀,这样可以很方便的进行批量存储和删除。例子:using Foundatio.Caching; ICacheClient cache = new InMemoryCacheClient(); await cache.SetAsync("test", 1); var value = await cache.GetAsync("test");队列提供了一个先进,先出的消息管道,Foundatio 提供了一个IQueue接口,并且拥有 4 种不同的队列实现。1、InMemoryQueue:一个内存队列实现,队列的生命周期为当前进程。2、RedisQueue:一个 Redis 队列实现。3、AzureServiceBusQueue:一个基于Azure的服务消息队列实现。4、AzureStorageQueue:一个基于Azure的存储队列实现。例子:using Foundatio.Queues; IQueue queue = new InMemoryQueue();await queue.EnqueueAsync(new SimpleWorkItem {     Data = "Hello"});var

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值