在實際的.Net Core相關項目開發中,不少人都會把NLog做爲日誌框架的首選,主要是源於它的強大和它的擴展性。同時不少時候咱們須要集中式的採集日誌,這時候僅僅使用NLog是不夠的,NLog主要是負責代碼中日誌的落地,也就是收集程序中的日誌。相似的使用ELK(Elasticsearch+Logstash+Kibana)或EFK(Elasticsearch+Filebeat+Kibana)的集中式日誌管理平臺負責統一採集各個應用端經過日誌框架手機的日誌並統一的管理和展現。可是不管是ELK仍是EFK,操做都有必定的複雜度,並且這是重型武器,有時候可能還不須要這麼大的排場,這時候就須要一種輕量級的解決方案,而Exceptionless正式這種輕量級的分佈式日誌管理平臺。html
可能有的同窗對於Exceptionless或者是NLog還不是很瞭解,這裏我們就簡單的介紹一下。node
簡單的來講Exceptionless就是一款分佈式日誌管理框架,它能夠統一收集管理並展現出來程序的日誌,這樣的話減小了傳統開發過程當中還須要去服務器查找日誌的痛苦,大大提高對程序的運維效率。接下來咱們先亮出來自學三件套git
目前支持JavaScript, Node, .NET Core, .NET相關應用程序的異常信息採集。爲什麼僅支持.Net .Net Core和JS相關的?緣由很簡單,Exceptionless是基於.NET Core開發的。若是你有別的語言的開發需求也想使用Exceptionless,這個時候不要氣餒,由於Exceptionless本質是基於http接口的形式上報數據的,這個可在官方文檔上找到如何使用http上報日誌信息相關github
以上文檔有針對Exceptionless經過http接口對接的全部信息,經過它能夠封裝本身的sdk。web
相信不少同窗對NLog已經至關熟悉了,它是一款日誌框架,完美的支持.Net和.Net Core,它在.Net Core的流行度和使用普遍度徹底不亞於以前的Log4Net,最重要的它功能很強大,並且擴展起來很是方便,它支持將日誌輸入到多種target形式,好比txt文件、Sql Server、MySQL、Redis、Mq、MongoDb、ElasticSearch等,幾乎能想到的全部存儲相關的組件,並且還支持過期日誌打包壓縮自動刪除等高級功能,也是我我的很是推薦的一款日誌框架,並且它能夠直接對接到.Net Core Logger組件上,廢話很少說自學N件套地址redis
NLog最大的優點就是強大,強大到你能用到的它幾乎都支持,並且你想不到的它可能也支持了,並且使用起來也是很是的簡單。做爲日誌框架,我以爲它是最值得一試的一款。docker
上面咱們已經分別介紹了Exceptionless和NLog知道了他們的概念。Exceptionless支持直接採集日誌信息上報到Exceptionless,也就是原始的方式,這個官方文檔上都有相關的介紹,這裏我們就不過多介紹這種方式了,使用原始方式的的時候可能會存在許多的問題,好比上報形式單一採集格式的問題等。許多時候咱們是使用日誌框架記錄程序日誌相關的,它的優點在於target豐富,並且支持自定義日誌格式等等,偏偏NLog足夠強大,支持直接將Log數據上報到Exceptionless,接下來咱們就來看一下它們之間的整合方式。編程
官網提供了兩種使用的方式api
官方也是提供了兩種方式去基於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中添加你須要採集日誌的項目,具體操做如如下步驟
到了這一步Exceptionless搭建基本上就完成了。
新建一個名叫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程序的核心,並且基於這些內置的核心抽象操做能夠很輕鬆的擴展許多操做,使得模塊之間的耦合性變得很是低,而這種設計的思想纔是咱們真正在編程中應該學習的。