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

来源:依乐祝

cnblogs.com/yilezhu/p/9339017.html

相信很多朋友都看过我的上篇关于Exceptionless的简单入门教程

《ASP.NET Core免费开源分布式异常日志收集框架Exceptionless》

安装配置以及简单使用图文教程上篇文章只是简单的介绍了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

///

/// 全局配置Exceptionless

///

///

///

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 { "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接口

///

/// lzhu

/// 2018.7.19

/// 日志接口

///

public interface ILoggerHelper

{

///

/// 记录trace日志

///

///

信息来源

///

日志内容

///

标记

void Trace(string source, string message, params string[] args);

///

/// 记录debug信息

///

///

信息来源

///

日志内容

///

标记

void Debug(string source, string message, params string[] args);

///

/// 记录信息

///

///

信息来源

///

日志内容

///

标记

void Info(string source, string message, params string[] args);

///

/// 记录警告日志

///

///

信息来源

///

日志内容

///

标记

void Warn(string source, string message, params string[] args);

///

/// 记录错误日志

///

///

信息来源

///

日志内容

///

标记

void Error(string source, string message, params string[] args);

}

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

///

/// lzhu

/// 2018.7.19

/// Exceptionless日志实现

///

public class ExceptionlessLogger : ILoggerHelper

{

///

/// 记录trace日志

///

///

信息来源

///

日志内容

///

添加标记

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

}

}

///

/// 记录debug信息

///

///

信息来源

///

日志内容

///

标记

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

}

}

///

/// 记录信息

///

///

信息来源

///

日志内容

///

标记

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

}

}

///

/// 记录警告日志

///

///

信息来源

///

日志内容

///

标记

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

}

}

///

/// 记录错误日志

///

///

信息来源

///

日志内容

///

标记

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

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

///

/// lzhu

/// 2018.7.19

/// 定义全局过滤器

///

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

}).AddFluentValidation();

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

// GET api/values/5

[HttpGet("")]

public ActionResult Get(int id)

{

//try

//{

throw new Exception($"测试抛出的异常");

//}

//catch (Exception ex)

//{

// ex.ToExceptionless().Submit();

//}

//return "Unknown Error!";

}

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

点进去,看看详细信息:

再测试下使用try catch捕获的异常处理,这时候异常信息会被提交到Exception这个里面。直接上代码吧

// GET api/values/5

[HttpGet("")]

public ActionResult Get(int id)

{

try

{

throw new Exception($"测试抛出的异常");

}

catch (Exception ex)

{

ex.ToExceptionless().Submit();

}

return "Unknown Error!";

}

到exceptionless里面看看不活的异常吧。打字很累直接上图吧

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

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

总结

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

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

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

看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180723B0NS0R00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券