对于docker部署Exceptionless(.netcore3.1版本)-随笔感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解docker部署.netcore,并且为您提供关于.NetC
对于docker部署Exceptionless(.net core3.1版本)-随笔感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解docker 部署.net core,并且为您提供关于.Net Core项目中NLog整合Exceptionless实例、.NetCore 中结合 ExceptionLess 的处理对 Polly 再次封装、.NetCore下 Exceptionless 分布式日志的个性化处理、.NetCore中使用ExceptionLess 添加操作日志的宝贵知识。
本文目录一览:- docker部署Exceptionless(.net core3.1版本)-随笔(docker 部署.net core)
- .Net Core项目中NLog整合Exceptionless实例
- .NetCore 中结合 ExceptionLess 的处理对 Polly 再次封装
- .NetCore下 Exceptionless 分布式日志的个性化处理
- .NetCore中使用ExceptionLess 添加操作日志
docker部署Exceptionless(.net core3.1版本)-随笔(docker 部署.net core)
前言
在实际的.Net Core相关项目开发中,很多人都会把NLog作为日志框架的首选,主要是源于它的强大和它的扩展性。同时很多时候我们需要集中式的采集日志,这时候仅仅使用NLog是不够的,NLog主要是负责代码中日志的落地,也就是收集程序中的日志。类似的使用ELK(Elasticsearch+Logstash+Kibana)或EFK(Elasticsearch+Filebeat+Kibana)的集中式日志管理平台负责统一采集各个应用端通过日志框架手机的日志并统一的管理和展示。但是无论是ELK还是EFK,操作都有一定的复杂度,而且这是重型武器,有时候可能还不需要这么大的排场,这时候就需要一种轻量级的解决方案,而Exceptionless正式这种轻量级的分布式日志管理平台。
概念
Exceptionless
简单的来说Exceptionless就是一款分布式日志管理框架,它可以统一收集管理并展示出来程序的日志,这样的话减少了传统开发过程中还需要去服务器查找日志的痛苦,大大提升对程序的运维效率。接下来我们先亮出来自学三件套
-
官网地址:https://exceptionless.com/
-
官方文档地址:https://exceptionless.com/docs/
-
官方Github地址:https://github.com/exceptionless/Exceptionless
目前支持JavaScript, Node, .NET Core, .NET相关应用程序的异常信息采集。为何仅支持.Net .Net Core和JS相关的?原因很简单,Exceptionless是基于.NET Core开发的。如果你有别的语言的开发需求也想使用Exceptionless,这个时候不要气馁,因为Exceptionless本质是基于http接口的形式上报数据的,这个可在官方文档上找到如何使用http上报日志信息相关
-
官方文档api地址:https://exceptionless.com/docs/api/api-getting-started/
-
api官方文档地址:https://api.exceptionless.io/
-
api官方swagger地址:https://api.exceptionless.io/docs/index.html
以上文档有针对Exceptionless通过http接口对接的所有信息,通过它可以封装自己的sdk。
NLog
相信很多同学对NLog已经相当熟悉了,它是一款日志框架,完美的支持.Net和.Net Core,它在.Net Core的流行度和使用广泛度完全不亚于之前的Log4Net,最重要的它功能很强大,而且扩展起来非常方便,它支持将日志输入到多种target形式,比如txt文件、sql Server、MysqL、Redis、Mq、MongoDb、ElasticSearch等,几乎能想到的所有存储相关的组件,而且还支持过时日志打包压缩自动删除等高级功能,也是我个人非常推荐的一款日志框架,而且它可以直接对接到.Net Core Logger组件上,废话不多说自学N件套地址
-
官方GitHub地址:https://github.com/NLog/NLog
-
官方文档地址:https://nlog-project.org/
-
文档地址:https://github.com/NLog/NLog/wiki
-
配置相关地址:https://nlog-project.org/config/
NLog最大的优势就是强大,强大到你能用到的它几乎都支持,而且你想不到的它可能也支持了,而且使用起来也是非常的简单。作为日志框架,我觉得它是最值得一试的一款。
步骤:
1、到github下载Exceptionless .net core版本,5.0.0及以后版本都是.net core版本,我下载的是6.0.0(windows系统)
2.下载下来解压,生成 (运行 dotnet restore,dotnet build)
3.在解压后的源码文件夹打开终端,运行 docker-compose up -d
参考文章:https://blog.csdn.net/weixin_39305029/article/details/105757909
https://mp.weixin.qq.com/s/eDhhR0WEJSQEadHWAKdqyA
.Net Core项目中NLog整合Exceptionless实例
前言
在实际的.Net Core相关项目开发中,很多人都会把NLog作为日志框架的首选,主要是源于它的强大和它的扩展性。同时很多时候我们需要集中式的采集日志,这时候仅仅使用NLog是不够的,NLog主要是负责代码中日志的落地,也就是收集程序中的日志。类似的使用ELK(Elasticsearch+Logstash+Kibana)或EFK(Elasticsearch+Filebeat+Kibana)的集中式日志管理平台负责统一采集各个应用端通过日志框架手机的日志并统一的管理和展示。但是无论是ELK还是EFK,操作都有一定的复杂度,而且这是重型武器,有时候可能还不需要这么大的排场,这时候就需要一种轻量级的解决方案,而Exceptionless正式这种轻量级的分布式日志管理平台。
概念
可能有的同学对于Exceptionless或者是NLog还不是很了解,这里咱们就简单的介绍一下。
Exceptionless
简单的来说Exceptionless就是一款分布式日志管理框架,它可以统一收集管理并展示出来程序的日志,这样的话减少了传统开发过程中还需要去服务器查找日志的痛苦,大大提升对程序的运维效率。接下来我们先亮出来自学三件套
- 官网地址:https://exceptionless.com/
- 官方文档地址:https://exceptionless.com/docs/
- 官方Github地址:https://github.com/exceptionless/Exceptionless
目前支持JavaScript, Node, .NET Core, .NET相关应用程序的异常信息采集。为何仅支持.Net .Net Core和JS相关的?原因很简单,Exceptionless是基于.NET Core开发的。如果你有别的语言的开发需求也想使用Exceptionless,这个时候不要气馁,因为Exceptionless本质是基于http接口的形式上报数据的,这个可在官方文档上找到如何使用http上报日志信息相关
- 官方文档api地址:https://exceptionless.com/docs/api/api-getting-started/
- api官方文档地址:https://api.exceptionless.io/
- api官方swagger地址:https://api.exceptionless.io/docs/index.html
以上文档有针对Exceptionless通过http接口对接的所有信息,通过它可以封装自己的sdk。
NLog
相信很多同学对NLog已经相当熟悉了,它是一款日志框架,完美的支持.Net和.Net Core,它在.Net Core的流行度和使用广泛度完全不亚于之前的Log4Net,最重要的它功能很强大,而且扩展起来非常方便,它支持将日志输入到多种target形式,比如txt文件、Sql Server、MySQL、Redis、Mq、MongoDb、ElasticSearch等,几乎能想到的所有存储相关的组件,而且还支持过时日志打包压缩自动删除等高级功能,也是我个人非常推荐的一款日志框架,而且它可以直接对接到.Net Core Logger组件上,废话不多说自学N件套地址
- 官方GitHub地址:https://github.com/NLog/NLog
- 官方文档地址:https://nlog-project.org/
- 文档地址:https://github.com/NLog/NLog/wiki
- 配置相关地址:https://nlog-project.org/config/
NLog最大的优势就是强大,强大到你能用到的它几乎都支持,而且你想不到的它可能也支持了,而且使用起来也是非常的简单。作为日志框架,我觉得它是最值得一试的一款。
环境搭建
上面我们已经分别介绍了Exceptionless和NLog知道了他们的概念。Exceptionless支持直接采集日志信息上报到Exceptionless,也就是原始的方式,这个官方文档上都有相关的介绍,这里咱们就不过多介绍这种方式了,使用原始方式的的时候可能会存在许多的问题,比如上报形式单一采集格式的问题等。许多时候我们是使用日志框架记录程序日志相关的,它的优势在于target丰富,而且支持自定义日志格式等等,恰恰NLog足够强大,支持直接将Log数据上报到Exceptionless,接下来我们就来看一下它们之间的整合方式。
Exceptionless搭建
官网提供了两种使用的方式
- 一种是在官方网站注册账号然后获取apiKey,这样的话不用自己搭建Exceptionless,而是将日志直接收集上报到Exceptionless服务器上。但是,一般基于安全和性能考虑,这种方式并不常用。
- 另一种则是自建Exceptionless服务,也是本篇我们要使用的方式。之前的低版本支持在window服务器上自建服务,但是高版本已经是基于docker的方式构建了。而使用docker的方式也是我个人日常学习中比较喜欢的方式。
官方也是提供了两种方式去基于docker构建Exceptionless,一种是基于源码自行构建,另一种则是通过官方docker镜像直接运行容器。因为Exceptionless依赖Elasticsearch存储所以官方也是也是直接提供了docker-compose的方式去运行容器。
如果使用基于源码的方式构建,首先是找到Exceptionless的官方GitHub地址https://github.com/exceptionless/Exceptionless去clone源代码,或者直接下载源码的Release包https://github.com/exceptionless/Exceptionless/releases。下载完成之后进入项目根目录找到docker-compose.dev.yml文件,文件内容如下
version: ''3.7'' services: #通过源码自行构建镜像 app: #依赖elasticsearch和redis depends_on: - elasticsearch - redis build: context: . target: app image: exceptionless/app:latest environment: EX_AppMode: Production EX_ConnectionStrings__Cache: provider=redis EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200 #redis的作用是消息总线、消息队列和缓存 EX_ConnectionStrings__MessageBus: provider=redis EX_ConnectionStrings__Queue: provider=redis EX_ConnectionStrings__Redis: server=redis,abortConnect=false EX_RunJobsInProcess: ''false'' #暴露访问端口 ports: - 5000:80 - 5001:443 volumes: - appdata:/app/storage - ssldata:/https jobs: depends_on: - app image: exceptionless/job:latest build: context: . target: job environment: EX_AppMode: Production EX_BaseURL: http://localhost:5000 EX_ConnectionStrings__Cache: provider=redis EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200 EX_ConnectionStrings__MessageBus: provider=redis EX_ConnectionStrings__Queue: provider=redis EX_ConnectionStrings__Redis: server=redis,abortConnect=false EX_ConnectionStrings__Storage: provider=folder;path=/app/storage volumes: - appdata:/app/storage elasticsearch: image: exceptionless/elasticsearch:7.10.0 environment: discovery.type: single-node xpack.security.enabled: ''false'' ES_JAVA_OPTS: -Xms1g -Xmx1g ports: - 9200:9200 - 9300:9300 volumes: - esdata7:/usr/share/elasticsearch/data kibana: depends_on: - elasticsearch image: docker.elastic.co/kibana/kibana:7.10.0 ports: - 5601:5601 redis: image: redis:6.0-alpine ports: - 6379:6379 volumes: esdata7: driver: local appdata: driver: local ssldata: driver: local
通过上面的docker-compose文件我们可以看出目前Exceptionless依赖elasticsearch和redis,大致可以看出Exceptionless存储是依赖elasticsearch,而提升性能的则是redis,比如消息总线防止并发的缓冲队列都是依赖redis的,具体实现细节我们这里就不做过多套路了。因为使用dev的方式构建镜像的方式依赖Exceptionless源码,所以不建议移动该docker-compose文件位置,使用docker-compose的指令直接运行该文件
docker-compose -f docker-compose.dev.yml up
上面的方式虽然可以直接依靠源码去构建,但是其实大可不必这么复杂比如kibana这种完全就是多余的,而且他的这种方式是依赖源码的,生产环境我们不可能把代码直接copy过去,所以我们需要精简一下,如下所示
version: ''3.7'' services: app: depends_on: - elasticsearch - redis image: exceptionless/exceptionless:latest environment: EX_AppMode: Production EX_ConnectionStrings__Cache: provider=redis EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200 EX_ConnectionStrings__MessageBus: provider=redis EX_ConnectionStrings__Queue: provider=redis EX_ConnectionStrings__Redis: server=redis:6379,abortConnect=false EX_RunJobsInProcess: ''false'' ports: - 5000:80 volumes: - appdata:/app/storage jobs: depends_on: - app image: exceptionless/job:latest environment: EX_AppMode: Production EX_BaseURL: http://localhost:5000 EX_ConnectionStrings__Cache: provider=redis EX_ConnectionStrings__Elasticsearch: server=http://elasticsearch:9200 EX_ConnectionStrings__MessageBus: provider=redis EX_ConnectionStrings__Queue: provider=redis EX_ConnectionStrings__Redis: server=redis:6379,abortConnect=false EX_ConnectionStrings__Storage: provider=folder;path=/app/storage volumes: - appdata:/app/storage elasticsearch: image: exceptionless/elasticsearch:7.10.0 environment: discovery.type: single-node xpack.security.enabled: ''false'' xpack.ml.enabled: ''false'' ES_JAVA_OPTS: -Xms1g -Xmx1g ports: - 9200:9200 - 9300:9300 volumes: - esdata7:/usr/share/elasticsearch/data redis: image: redis:6.0-alpine ports: - 6379:6379 volumes: esdata7: driver: local appdata: driver: local
将上面的yml内容直接复制到一个新建的docker-compose.yml的空文件中就可以直运行了,无任何额外的依赖,在yml文件所在路径直接运行以下命令
docker-compose up -d
如果你的服务器已经拥有了elasticsearch和redis服务,也就是不需要使用以上docker-compose的方式进行构建,那么可以直接使用官方docker镜像的方式直接启动Exceptionless容器,可以使用docker原生的方式直接运行
sudo docker run -d -e EX_AppMode=Production -e EX_ConnectionStrings__Cache="provider=redis" -e EX_ConnectionStrings__Elasticsearch="server=http://10.255.198.168:9200" -e EX_ConnectionStrings__MessageBus="provider=redis" -e EX_ConnectionStrings__Queue="provider=redis" -e EX_ConnectionStrings__Redis="server=10.255.198.168:6379,abortConnect=false" -e EX_RunJobsInProcess=false -e EX_Html5Mode=true -p 5000:80 exceptionless/exceptionless:latest
这里注意修改下相关服务的ip地址,因为我粘贴的是我本机的地址,而且注意elasticsearch的版本必须是7.x版本的,否则的话会报错。程序启动完成后再浏览器输输入http://ip:5000后会自动跳转到登录界面
如果没有登录账户需要注册一个新的用户后,登录到首页如图所示
因为Exceptionless每个项目的日志信息是根据apiKey去区分的,所以要在Exceptionless中添加你需要采集日志的项目,具体操作如以下步骤
- 首先,点击所有项目--->创建项目
- 然后,输入组织名称和项目名称
- 然后,选择项目类型,这里以Asp.Net Core程序为例
- 完成之后,点击项目管理,这里的API秘钥正是我们上传到Exceptionless服务所需要的凭证
到了这一步Exceptionless搭建基本上就完成了。
集成NLog
新建一个名叫ProductApi的Asp.Net Core的项目,项目名称任意。然后添加Exceptionless.NLog包,这个包就是将NLog数据上报到Exceptionless的包
<PackageReference Include="Exceptionless.NLog" Version="4.6.2" /> <PackageReference Include="NLog.Web.AspNetCore" Version="4.10.0" />
Exceptionless.NLog的Github项目地址位于https://github.com/exceptionless/Exceptionless.Net/tree/master/src/Platforms/Exceptionless.NLog这个地址相当隐蔽不太容易被发现,而且说明文档也是很低调几乎没啥内容,可能是觉得NLog的文档写的太完善了,不用多说大家就能知道怎么用。添加完nuget包引用之后,修改Program.cs程序添加NLog的Logging扩展。仅仅添加UseNLog即可,因为我们使用了NLog.Web.AspNetCore扩展包,所以NLog会集成到Asp.Net Core自带的Microsoft.Extensions.Logging中去,不得不说.Net Core的整体扩展性还是非常强的,这样的话我们可以设置默认的Logging的配置即可,几乎感知不到NLog的存在
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }).UseNLog();
接下来需要在项目根目录中新建nlog.config用来配置nlog相关信息,新建完成之后添加以下配置
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true" internalLogFile="internal-nlog.log" internalLogLevel="Debug" > <extensions> <!--添加扩展Exceptionless程序集--> <add assembly="Exceptionless.NLog"/> </extensions> <targets async="true"> <!--写入本地文件--> <target name="File" xsi:type="File" fileName="${basedir}/logs/${shortdate}.log" layout=" ${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}| ${newline}" > </target> <!--上报Exceptionless--> <!--xsi:type:固定是Exceptionless--> <!--apiKey:即我们在Exceptionless中添加完项目后得到的apiKey--> <!--serverUrl:Exceptionless的地址--> <target xsi:type="Exceptionless" name="Exceptionless" apiKey="d66B6fXD6sz3kAuqdc5Fe04td7iIygunkDa5GoUt" serverUrl="http://10.255.52.93:5000/"> <!--堆栈信息--> <field name="StackTrace" layout="${stacktrace}"/> <!--Message信息--> <field name="Message" layout="${message}"/> <field name="LogLevel" layout="${level}"/> <field name="CreateDate" layout="${date}"/> <!--物理名称--> <field name="MachineName" layout="${machinename}" /> <!--线程ID--> <field name="ThreadId" layout="${threadid}"/> <!--发生源--> <field name="CallSite" layout="${callsite}"/> <field name="AppdomainVersion" layout="${assembly-version}"/> <field name="Appdomain" layout="${appdomain}"/> </target> </targets> <rules> <!--本地文件--> <logger name="*" writeTo="File"/> <!--上报Exceptionless--> <logger name=''*'' writeTo=''Exceptionless''/> </rules> </nlog>
新建完nlog.config之后不要忘了将右击该文件 属性--->复制到输出路径--->始终复制,或修改该项目的csproj文件添加
<ItemGroup> <Content Update="nlog.config"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup>
到这里为止关于NLog整合Exceptionless的环境搭建就已经完成了,是不是非常的简单,抛开环境搭建工作量其实并不大,这一切都是源于.Net Core的强大和它那灵活的可扩展性。
简单测试一下
通过上面的操作我们已经把NLog整合Exceptionless的环境搭建起来了,接下来我们随便写点代码测试一波随便建个类,就是为了演示异常,代码无任何实质意义,不喜勿喷。。。,这里我是模拟了一个ApiController抛出异常,然后用Logger记录了信息
[Route("productapi/[controller]")] public class ProductController : ControllerBase { private readonly ILogger _logger; public ProductController(ILogger<ProductController> logger) { _logger = logger; } [HttpGet("exceptiontest")] public string ExceptionTest() { try { throw new Exception("发生了未知的异常"); } catch (Exception ex) { _logger.LogError(ex,$"{HttpContext.Connection.RemoteIpAddress}调用了productapi/product/exceptiontest接口返回了失败"); } return "调用失败"; } }
运行起来项目调用一下这段代码之后,查看Exceptionless,如果环境配置啥的都是正确的话,会展示出一下效果,点击All菜单展示出来的信息会比较全
可以点击查看详情,详情信息记录的非常详细,不得不说Exceptionless还是非常强大非常人性非常实用的
还能查看更详细的信息
到这里为止,关于NLog整合Exceptionless的操作就全部完成了,感叹一句就是不仅简单而且强大。
总结
通过本次整合NLog和Exceptionless,我们既感受到Exceptionless的简单和强大,也感受到了NLog的扩展性之强,希望更多地人能够尝试一下NLog。这一切还是得益于.Net Core自身的扩展性,特别是它内置的一些抽象,完全成为了构建.Net Core程序的核心,而且基于这些内置的核心抽象操作可以很轻松的扩展许多操作,使得模块之间的耦合性变得非常低,而这种设计的思想才是我们真正在编程中应该学习的。
到此这篇关于.Net Core项目中NLog整合Exceptionless实例的文章就介绍到这了,更多相关NLog整合Exceptionless内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
- .NET日志框架Nlog使用介绍
- 关于.Net 6 添加NLog的方法
- .Net Core 使用NLog记录日志到文件和数据库的操作方法
- Asp.Net Core用NLog记录日志操作方法
- .Net项目中NLog的配置和使用实例详解
- 详解.Net core2.0日志组件Log4net、Nlog简单性能测试
- ASP.NET Core与NLog集成的完整步骤
- ASP.NET Core开发教程之Logging利用NLog写日志文件
- 使用NLog给Asp.Net Core做请求监控的方法
- ASP.NET Core使用NLog输出日志记录
.NetCore 中结合 ExceptionLess 的处理对 Polly 再次封装
/// <summary>
/// Polly封装 liyouming
/// </summary>
public class PollyServicesFactory
{
private IELLog eLLog;
public PollyServicesFactory(IELLog ellog)
{
eLLog = ellog;
}
#region 重试
/// <summary>
/// 组合使用Warp
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="num"></param>
/// <returns></returns>
public ISyncPolicy RetryWarp<TException>(int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.Retry(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetry")
.AddSubmitWarn();
});
return policy;
}
public IAsyncPolicy RetryWarpAsync<TException>(int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.RetryAsync(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetry")
.AddSubmitWarn();
});
return policy;
}
/// <summary>
/// 服务重试 及重试次数
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="num"></param>
public void PollyRetry<TException>(Action action, int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.Retry(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetry")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
policy.Execute(action);
}
public TResult PollyResultRetry<TException, TResult>(Func<TResult> action, int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.Retry(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetry")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
return policy.Execute(action);
}
/// <summary>
/// 服务重试 及重试次数
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="num"></param>
public async Task PollyRetryAsync<TException>(Func<Task> action, int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.RetryAsync(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetryAsync")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
await policy.ExecuteAsync(action);
}
public async Task<TResult> PollyResultRetryAsync<TException, TResult>(Func<Task<TResult>> action, int num) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.RetryAsync(num, (ex, count) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"执行失败!重试次数 {count}\r\n异常来自 {ex.GetType().Name}")
.AddTag("PollyRetryAsync")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
return await policy.ExecuteAsync(action);
}
#endregion
#region 重试 TimeSpan
/// <summary>
/// 重试 Warp
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="timeSpans"></param>
/// <returns></returns>
public ISyncPolicy WaitAndRetryWarp<TException>(params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]")
.AddMessage($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetry")
.AddSubmitWarn();
});
return policy;
}
public IAsyncPolicy WaitAndRetryWarpAsync<TException>(params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]")
.AddMessage($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetry")
.AddSubmitWarn();
});
return policy;
}
/// <summary>
/// 按需要的周期重试
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="timeSpans"></param>
/// <returns></returns>
public void PollyWaitAndRetry<TException>(Action action, params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetry")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
policy.Execute(action);
}
public TResult PollyResultWaitAndRetry<TException, TResult>(Func<TResult> action, params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetry(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetry")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
return policy.Execute(action);
}
/// <summary>
/// 按需要的周期重试
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="timeSpans"></param>
/// <returns></returns>
public async Task PollyWaitAndRetryAsync<TException>(Func<Task> action, params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetryAsync")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
await policy.ExecuteAsync(action);
}
public async Task<TResult> PollyResultWaitAndRetryAsync<TException, TResult>(Func<Task<TResult>> action, params TimeSpan[] timeSpans) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.WaitAndRetryAsync(timeSpans, (e, tiempo, intento, contexto) =>
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常:{e.Message} {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}")
.AddTag("WaitAndRetryAsync")
.AddTag(action.Method.Name)
.AddSubmitWarn();
});
return await policy.ExecuteAsync(action);
}
#endregion
#region 指定特定返回值
public ISyncPolicy<OperatorResult> FallBackWarp<TException>() where TException : Exception
{
var pollyfallback = Policy<OperatorResult>.Handle<TException>()
.Fallback(new OperatorResult
{
Result = ResultType.Fail,
Message = "执行失败"
});
return pollyfallback;
}
public IAsyncPolicy<OperatorResult> FallBackWarpAsync<TException>() where TException : Exception
{
var pollyfallback = Policy<OperatorResult>.Handle<TException>()
.FallbackAsync(new OperatorResult
{
Result = ResultType.Fail,
Message = "执行失败"
});
return pollyfallback;
}
/// <summary>
/// 监控特定错误指定返回值
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public OperatorResult PollyFallBack<TException>(Func<OperatorResult> action) where TException : Exception
{
var pollyfallback = Policy<OperatorResult>.Handle<TException>()
.Fallback(() =>
{
return new OperatorResult
{
Result = ResultType.Fail,
Message = action.Method.Name + "执行失败"
};
});
return pollyfallback.Execute(action);
}
/// <summary>
/// 监控特定错误指定返回值
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <returns></returns>
public async Task<OperatorResult> PollyFallBackAsync<TException>(Func<Task<OperatorResult>> action) where TException : Exception
{
var pollyfallback = Policy<OperatorResult>.Handle<TException>()
.FallbackAsync(new OperatorResult
{
Result = ResultType.Fail,
Message = action.Method.Name + "执行失败"
}
);
return await pollyfallback.ExecuteAsync(action);
}
#endregion
#region 熔断
public ISyncPolicy CircuitBreakerWarp<TException>(int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreaker(num, timeSpan);
return policy;
}
public IAsyncPolicy CircuitBreakerWarpAsync<TException>(int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreakerAsync(num, timeSpan);
return policy;
}
/// <summary>
/// 熔断 仓壁隔离
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="num"></param>
/// <param name="timeSpan"></param>
public void PollyCircuitBreaker<TException>(Action action, int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreaker(num, timeSpan);
while (true)
{
try
{
policy.Execute(action);
}
catch (Exception ex)
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {ex.Message} \t执行时间: {DateTime.Now}")
.AddTag("PollyCircuitBreaker")
.AddTag(action.Method.Name)
.AddSubmitWarn();
}
Thread.Sleep(100);
}
}
public Task<TResult> PollyResultCircuitBreaker<TException, TResult>(Func<Task<TResult>> action, int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreaker(num, timeSpan);
while (true)
{
try
{
return policy.Execute(action);
}
catch (Exception ex)
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {ex.Message} \t执行时间: {DateTime.Now}")
.AddTag("PollyCircuitBreaker")
.AddTag(action.Method.Name)
.AddSubmitWarn();
}
Thread.Sleep(100);
}
}
/// <summary>
/// 熔断 仓壁隔离
/// </summary>
/// <typeparam name="TException"></typeparam>
/// <param name="action"></param>
/// <param name="num"></param>
/// <param name="timeSpan"></param>
public async Task PollyCircuitBreakerAsync<TException>(Func<Task> action, int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreakerAsync(num, timeSpan);
while (true)
{
try
{
await policy.ExecuteAsync(action);
}
catch (Exception ex)
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {ex.Message} \t执行时间: {DateTime.Now}")
.AddTag("PollyCircuitBreaker")
.AddTag(action.Method.Name)
.AddSubmitWarn();
}
Thread.Sleep(100);
}
}
public async Task<TResult> PollyResultCircuitBreakerAsync<TException, TResult>(Func<Task<TResult>> action, int num, TimeSpan timeSpan) where TException : Exception
{
var policy = Policy
.Handle<TException>()
.CircuitBreakerAsync(num, timeSpan);
while (true)
{
try
{
return await policy.ExecuteAsync(action);
}
catch (Exception ex)
{
eLLog.AddSource($"[Polly]{action.Method.Name}")
.AddMessage($"异常: {ex.Message} \t执行时间: {DateTime.Now}")
.AddTag("PollyCircuitBreaker")
.AddTag(action.Method.Name)
.AddSubmitWarn();
}
Thread.Sleep(100);
}
}
#endregion
#region 组合各种场景
public void PollyWarp(Action action, params ISyncPolicy[] syncPolicies)
{
var mixedPolicy = Policy.Wrap(syncPolicies);
mixedPolicy.Execute(action);
}
public async Task PollyWarpAsync(Func<Task> action, params IAsyncPolicy[] syncPolicies)
{
var mixedPolicy = Policy.WrapAsync(syncPolicies);
await mixedPolicy.ExecuteAsync(action);
}
#endregion
}
感觉封装了下也没什么太大的卵用~浪费了时间,但是还是贴出来
.NetCore下 Exceptionless 分布式日志的个性化处理
Event Type
在Exceptionless中有 Exception 、LogMessage、Broken Links 、Feature Usages
接下来就这几种类型分别添加日志记录
Exception
Exceptionless组件对系统的异常日志都有捕获,所有Exception异常都会添加
当然也可以对异常添加标签
ex.ToExceptionless().AddTags("tags").Submit();
在Exceptionless站点上可以看到
通过详细我们看到tags message
通过这个tags可以查询出对应的日志,方便快速查找
LogMessage
日志信息记录,对于业务需要记录操作日志信息地方可以用如下方式
ExceptionlessClient.Default.CreateLog("LogMessage", ex.Message, LogLevel.Info).AddTags("LogMessage").Submit();
可以设置日志信息 Summary 以及 日志的LogLevel 根据业务需求设置
Broken Links
记录404找不到请求的日志
如在地址栏里输入http://localhost:20011/api/check/xxxxx 不存在的地址
可以看到这个日志已经被记录
Feature Usages
ExceptionlessClient.Default.CreateFeatureUsage("custom").SetSource("customsource").SetMessage("这是FeatureUsage日志").SetType("customType").Submit();
同样添加添加日志的信息、来源、类型、标签等设置,可能不同的exceptionless在语法上有不同
.NetCore中使用ExceptionLess 添加操作日志
上一篇文章已经扩展了日志,下面我们在结合下处理操作日志
通常我们想到操作日志 可能想到的参数可能有 模块 方法 参数内容 操作人 操作时间 操作 Ip 下面我们就来结合这些信息添加操作日志
如果要在代码中每个操作中添加 是非常繁琐的 代码很大部分重复,有AOP思想的应该都知道面向切面的方式处理日志,日志贯穿整个系统
所以我们会想到过滤器,在之前的文章中我用到了拦截器处理,这里我们使用 Filter 过滤器 结合Attribute属性来处理,这里我们主要依靠 IAsyncActionFilter 或者 IActionFilter 来处理
定义个属性类 LogAttribute
public class LogAttribute : Attribute, IAsyncActionFilter
{
}
实现 IAsyncActionFilter 接口 ,定义好属性需要的构造函数 具体代码如下 结合 ExceptionLess添加操作日志
public class LogAttribute : Attribute, IAsyncActionFilter
{
private string MoudleName { get; set; }
private string MethodName { get; set; }
/// <summary>
/// 构造日志类型
/// </summary>
/// <param name="Moudle">模块名称</param>
/// <param name="Method">方法名称</param>
public LogAttribute(string Moudle, string Method)
{
this.MoudleName = Moudle;
this.MethodName = Method;
}
/// <summary>
/// 添加操作日志 liyouming
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var actiondescriptor = ((ControllerActionDescriptor)context.ActionDescriptor);
var identity = ((ApiBase)context.Controller).userIdentity;
var _eLLog = context.HttpContext.RequestServices.GetService(typeof(IELLog)) as IELLog;
var model = JsonConvert.SerializeObject(context.ActionArguments);
_eLLog.AddSource($"[{MoudleName}]{MethodName}{string.Format("{0:yyyy年MM月dd日 HH:mm:ss}", DateTime.Now)}")
.AddMessage("参数内容:" + model ?? "")
.AddTag(identity.UserId ?? "")
.AddTag(identity.UserName ?? "")
.AddTag(actiondescriptor.ControllerName)
.AddTag(actiondescriptor.ActionName)
.AddTag(MoudleName)
.AddTag(MethodName)
.AddTag(string.Format("{0:yyyy-MM-dd}", DateTime.Now))
.AddSubmitInfo();
await next.Invoke();
}
}
接下来添加好接口代码
/// <summary>
/// Demo 添加数据 调用MediatR DDD 实现领域事件
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("createdata")]
[ProducesResponseType(typeof(OperatorResult),(int) HttpStatusCode.OK)]
[Permission(PermissionCode.DemoCreate)]
[Log("测试模块","添加测试方法")]
public async Task<IActionResult> CreateData([FromBody]SchoolDto model)
{
var validationResult = _validator.Validate(model);
if (!validationResult.IsValid)
{
return Ok(new OperatorResult
{
Result = ResultType.Fail,
Message = string.Join(";", validationResult.Errors)
});
}
//这里用Mapper做映射
var school = _mapper.Map<SchoolDto, School>(model);
school.Id = Guid.NewGuid();
school.AddClassesDomain(new Classes { CName="Demo", Id=Guid.NewGuid() }); var command = new DemoCreateCommand { com_school = school };
var result = await _mediator.Send(command);
return Ok(result);
}
下面我们通过API来测试下
下面看下ExceptionLess中的日志
今天关于docker部署Exceptionless(.net core3.1版本)-随笔和docker 部署.net core的分享就到这里,希望大家有所收获,若想了解更多关于.Net Core项目中NLog整合Exceptionless实例、.NetCore 中结合 ExceptionLess 的处理对 Polly 再次封装、.NetCore下 Exceptionless 分布式日志的个性化处理、.NetCore中使用ExceptionLess 添加操作日志等相关知识,可以在本站进行查询。
本文标签: