前言

在实际的.Net Core相关项目开发中,很多人都会把NLog作为日志框架的首选,主要是源于它的强大和它的扩展性。同时很多时候我们需要集中式的采集日志,这时候仅仅使用NLog是不够的,NLog主要是负责代码中日志的落地,也就是收集程序中的日志。类似的使用ELK(Elasticsearch+Logstash+Kibana)或EFK(Elasticsearch+Filebeat+Kibana)的集中式日志管理平台负责统一采集各个应用端通过日志框架手机的日志并统一的管理和展示。但是无论是ELK还是EFK,操作都有一定的复杂度,而且这是重型武器,有时候可能还不需要这么大的排场,这时候就需要一种轻量级的解决方案,而Exceptionless正式这种轻量级的分布式日志管理平台。

概念

可能有的同学对于Exceptionless或者是NLog还不是很了解,这里咱们就简单的介绍一下。

Exceptionless

简单的来说Exceptionless就是一款分布式日志管理框架,它可以统一收集管理并展示出来程序的日志,这样的话减少了传统开发过程中还需要去服务器查找日志的痛苦,大大提升对程序的运维效率。接下来我们先亮出来自学三件套

目前支持JavaScript, Node, .NET Core, .NET相关应用程序的异常信息采集。为何仅支持.Net .Net Core和JS相关的?原因很简单,Exceptionless是基于.NET Core开发的。如果你有别的语言的开发需求也想使用Exceptionless,这个时候不要气馁,因为Exceptionless本质是基于http接口的形式上报数据的,这个可在官方文档上找到如何使用http上报日志信息相关

以上文档有针对Exceptionless通过http接口对接的所有信息,通过它可以封装自己的sdk。

NLog

相信很多同学对NLog已经相当熟悉了,它是一款日志框架,完美的支持.Net和.Net Core,它在.Net Core的流行度和使用广泛度完全不亚于之前的Log4Net,最重要的它功能很强大,而且扩展起来非常方便,它支持将日志输入到多种target形式,比如txt文件、Sql Server、MySQL、Redis、Mq、MongoDb、ElasticSearch等,几乎能想到的所有存储相关的组件,而且还支持过时日志打包压缩自动删除等高级功能,也是我个人非常推荐的一款日志框架,而且它可以直接对接到.Net Core Logger组件上,废话不多说自学N件套地址

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程序的核心,而且基于这些内置的核心抽象操作可以很轻松的扩展许多操作,使得模块之间的耦合性变得非常低,而这种设计的思想才是我们真正在编程中应该学习的。

欢迎扫码关注我的公众号

NLog整合Exceptionless的更多相关文章

  1. (七)React Ant Design Pro + .Net5 WebApi:后端环境搭建-日志、异常处理

    一.日志 日志具有帮助开发者快速的定位问题,记录各种信息,配合其他分析框架使用等等功能,收集日志的各类框架如:Log4net.NLog.Exceptionless.Serilog等等,百度或园子里介绍 ...

  2. asp.net core系列 73 Exceptionless+Nlog以及Apollo介绍

    一. 介绍 在一上篇中介绍了Exceptionless的基本使用,这篇主要讲Exceptionless结合Nlog的实现双重日志记录,包括Exceptionles的UI可视化日志以及Nlog的txt文 ...

  3. 第七节:Asp.Net Core内置日志和整合NLog(未完)

    一. Asp.Net Core内置日志 1. 默认支持三种输出方式:控制台.调试(底部输出窗口).EventSource,当然也可以在Program类中通过logging.ClearProviders ...

  4. NET Core微服务之路:实战SkyWalking+Exceptionless体验生产环境下的追踪系统

    前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的问题: 从APM上说,知道某个节点出现异常,或延迟过过高,却不能及时知道日志反馈情况,总不可能去相应的节点 ...

  5. NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统

    原文:NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统 前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的 ...

  6. ElasticSearch+NLog+Elmah实现Asp.Net分布式日志管理

    本文将介绍使用NLOG.Elmah结合ElasticSearch实现分布式日志管理. 一.ElasticSearch简介 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布 ...

  7. Topshelf + ServiceModelEx + Nlog 从头构建WCF

    前言 Topshelf可以很方便的构建windows service,而且在本地开发时也可以构建Console宿主,因此很方便WCF的开发. ServiceModelEx则提供了很多便利的方法来配置w ...

  8. ExceptionLess新玩法 — 记日志

    ExceptionLess 之前也有介绍过这个框架,其实网上也有很多的资料,无论是部署还是一些详细的高级玩法都讲的很清楚也很棒,博主也学习了一些他们的博文,因为很多的东西比如本地部署别人已经写了,我再 ...

  9. ExceptionLess异常日志收集框架-1

    哈哈,中秋和代码更配哦,不知不觉一年过半了,祝园友们中秋快乐 前一阵子在博客园看到了一篇博文 http://www.cnblogs.com/savorboard/p/exceptionless.htm ...

随机推荐

  1. 六:SpringBoot-引入JdbcTemplate,和多数据源配置

    SpringBoot-引入JdbcTemplate,和多数据源配置 1.JdbcTemplate对象 1.1 JdbcTemplate核心方法 2.SpringBoot中使用JDBCTemplate ...

  2. Java IO--字节流与字符流OutputStream/InputStream/Writer/Reader

    流的概念 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 内容操作就四个类:OutputStream.InputStream.Writer.Reader 字节流 ...

  3. Java中的异常处理机制《》

    异常机制已经成为判断一门编程语言是否成熟的标准,异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性. Java异常机制主要依赖于try.catch.finall ...

  4. PHP-mysql存储照片的两种方式

    PHP-mysql存储照片的两种方式 方式一:把图片数据存储在数据库中(二进制) 数据库代码: CREATE TABLE `photo` (    `id` int(10) unsigned NOT ...

  5. SpringBoot整合spring-security-oauth2完整实现例子

    SpringBoot整合spring-security-oauth2完整实现例子 技术栈 : springboot + spring-security + spring-oauth2 + mybati ...

  6. Codeforces Round #651 (Div. 2) C. Number Game(数论)

    题目链接:https://codeforces.com/contest/1370/problem/C 题意 给出一个正整数 $n$,Ashishgup 和 FastestFinger 依次选择执行以下 ...

  7. Educational Codeforces Round 85 (Rated for Div. 2)

    \(Educational\ Codeforces\ Round\ 85\ (Rated\ for\ Div.2)\) \(A. Level Statistics\) 每天都可能会有人玩游戏,同时一部 ...

  8. Who Gets the Most Candies?

    Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 11303   Accepted: 3520 Case Time Limit ...

  9. AtCoder Beginner Contest 184 E - Third Avenue (BFS)

    题意:给你一张图,\(S\)表示起点,\(G\)表示终点,\(.\)表示可以走,#表示不能走,小写字母可以传送到任意一个相同的字母的位置,问从\(S\)走到\(G\)的最小步数. 题解:假如不考虑字母 ...

  10. hdu517 Triple

    Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submissio ...