欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

使用ElasticSearch,Kibana,ASP.NETCore和Docker可視化數(shù)據(jù)

想要輕松地通過(guò)許多不同的方式查詢(xún)數(shù)據(jù),甚至是從未預(yù)料到的方式?想要以多種方式可視化日志?同時(shí)支持基于時(shí)間、文本和其他類(lèi)型的即時(shí)過(guò)濾器?

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、墾利ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢(xún)和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的墾利網(wǎng)站制作公司

借助于 Elastic stack 的卓越性能和可擴(kuò)展方式的優(yōu)點(diǎn),我們將通過(guò)兩個(gè)示例輕松實(shí)現(xiàn)。

本文由 DNC Magazine for Developers and Architects 發(fā)布。 從這里下載此雜志[PDF] 或 免費(fèi)訂閱本雜志 下載所有以前和當(dāng)前的版本版本。

在這篇文章中,我將介紹流行的搜索引擎 Elasticsearch,其配套的可視化應(yīng)用 Kibana,并展示如何對(duì).NET核心可以輕松地與 Elastic stack 整合在一塊。

Elasticsearch和.Net Core


我們將開(kāi)始探索 Elasticsearch 的 REST API ,通過(guò)索引和查詢(xún)某些數(shù)據(jù)。接著,我們將使用Elasticsearch官方的 .Net API 完成類(lèi)似的練習(xí)。一旦熟悉 Elasticsearch 及其 API 后,我們將使用 .Net Core 創(chuàng)建一個(gè)日志模塊,并將數(shù)據(jù)發(fā)送到 Elasticsearch 。Kibana緊隨其中,以有趣的方式可視化 Elasticsearch 的索引數(shù)據(jù)。
我迫切希望你會(huì)認(rèn)為這篇文章十分有趣,并且想要了解更多關(guān)于Elastic的強(qiáng)大之處。

本文假設(shè)您已經(jīng)了解 C#和 REST API 的基本知識(shí)。使用 Visual Studio,Postman 和 Docker 等工具,但您可以輕松使用 VS Code 和 Fiddler 等替代方案。

Elasticsearch - 簡(jiǎn)介

Elasticsearch 作為核心的部分,是一個(gè)具有強(qiáng)大索引功能的文檔存儲(chǔ)庫(kù),并且可以通過(guò) REST API 來(lái)搜索數(shù)據(jù)。它使用 Java 編寫(xiě),基于 Apache Lucene,盡管這些細(xì)節(jié)隱藏在 API 中。
通過(guò)被索引的字段,可以用許多不同的聚合方式找到任何被存儲(chǔ)(索引)的文檔。
但是,ElasticSearch不僅僅只提供對(duì)這些被索引文檔的強(qiáng)大搜索功能。
快速、分布式、水平擴(kuò)展,支持實(shí)時(shí)文檔存儲(chǔ)和分析,支持?jǐn)?shù)百臺(tái)服務(wù)器和 PB 級(jí)索引數(shù)據(jù)。同時(shí)作為 Elastic stack (aka ELK) 的核心,提供了諸如 LogStash、Kibana 和更多的強(qiáng)大應(yīng)用。
Kibana 是 Elasticsearch 中專(zhuān)門(mén)提供強(qiáng)有力的可視化查詢(xún)Web應(yīng)用程序。使用Kibana,能非常簡(jiǎn)單地為 Elasticsearch 中索引的數(shù)據(jù)創(chuàng)建查詢(xún)、圖表和儀表盤(pán)。
Elasticsearch開(kāi)放了一個(gè) REST API,你會(huì)發(fā)現(xiàn)許多文檔示例是 HTTP 調(diào)用,你可以嘗試使用 curl 或 postman 等工具。當(dāng)然,這個(gè) API 的客戶端已經(jīng)用許多不同的語(yǔ)言編寫(xiě),包括.Net、Java、Python、Ruby和JavaScript等。
如果你想閱讀更多,Elasticsearch 官方網(wǎng)站 可能是最好的地方。

Docker是在本地運(yùn)行的最簡(jiǎn)方式

在這篇文章中,我們需要先連接到一個(gè) Elasticsearch (和后面的Kibana)的服務(wù)器。如果您已經(jīng)有一個(gè)在本地運(yùn)行或可以使用的服務(wù)器,那很好。否則需要先搭建一個(gè)服務(wù)器。
您可以選擇在您的本地機(jī)器或可以使用的 VM 或服務(wù)器中下載和安裝 Elasticsearch 和 Kibana 。不過(guò),建議您使用最簡(jiǎn)單最純粹的方式,使用Docker 搭建 Elasticsearch 和 Kibana 。
您可以直接運(yùn)行以下命令,獲取包含Elasticsearch和Kibana的容器。

docker run -it --rm -p 9200:9200 -p 5601:5601 --name esk nshou/elasticsearch-kibana
  • -it 表示以交互模式啟動(dòng)容器,并附加到終端。

  • --rm 表示從終端退出后,容器將被移除。

  • -p 將容器中的端口映射到主機(jī)中的端口

  • --name 給容器一個(gè)名稱(chēng),當(dāng)您不使用的情況下可以用 --rm 手動(dòng)停止/刪除

  • nshou/elasticsearch-kibana 是 Docker Hub中的一個(gè)鏡像的名稱(chēng),已經(jīng)有人幫你準(zhǔn)備好了Elasticsearch和Kibana

  • 如果你喜歡在后臺(tái)運(yùn)行的話,你可以使用參數(shù)-d 代替 --it --rm,并且手動(dòng)停止/刪除容器。

在同一個(gè)容器中運(yùn)行多個(gè)應(yīng)用程序,就像我們現(xiàn)在這種做法,非常適用本文,但不是推薦用于生產(chǎn)容器!

您應(yīng)該意識(shí)到,一旦你刪除容器,你的數(shù)據(jù)就會(huì)消失(一旦你使用-rm選項(xiàng)就刪除它了)。雖然有利于本地實(shí)驗(yàn),但在實(shí)際環(huán)境中,如果您不想丟失數(shù)據(jù),請(qǐng)參照 "data container" 模式。

Docker是一個(gè)很棒的工具,我鼓勵(lì)你更多地了解它,特別是如果你想做更重要的事情,而不僅僅是跟隨本文,在本地快速搭建 Elasticsearch 服務(wù)器。在之前的文章 Building DockNetFiddle using Docker and .NET Core 中已經(jīng)對(duì) .NET Core 搭配 Docker 有很好的介紹。

只需打開(kāi) http://localhost:9200 和 http://localhost:5600 ,檢查Elasticsearch 和 Kibana 是否都可以使用。(如果您使用docker toolbox,請(qǐng)使用托管Docker的虛擬機(jī)ip替換localhost,您可以在命令行中運(yùn)行 docker-machine env default )。

在docker中運(yùn)行 Elasticsearch

kibana也準(zhǔn)備好了

在 Elasticsearch 中索引和查詢(xún)

在我們開(kāi)始編寫(xiě)任何 .Net 代碼之前,我們先了解一下一些基本知識(shí)。先在 Elasticsearch 索引一些文檔(類(lèi)似于存到數(shù)據(jù)庫(kù)),以便我們對(duì)它們運(yùn)行不同的查詢(xún)。

在這里,我將使用Postman向我們的 Elasticsearch 服務(wù)器發(fā)送 HTTP 請(qǐng)求,但您可以使用任何其他類(lèi)似的工具,如 Fiddler或 curl 。

我們要做的第一件事是請(qǐng)求 Elasticsearch 創(chuàng)建一個(gè)新的索引 (譯者語(yǔ):類(lèi)似創(chuàng)建一個(gè)表) 并索引一些文檔 (譯者語(yǔ):類(lèi)似于在數(shù)據(jù)中插入數(shù)據(jù)) 。這類(lèi)似于將數(shù)據(jù)存儲(chǔ)在表/集合中,主要區(qū)別(和目的)是讓 Elasticsearch 集群 (這里只是一個(gè)節(jié)點(diǎn)) 可以分析和搜索文檔數(shù)據(jù)。
被索引的文檔在 Elasticsearch 中以索引和類(lèi)型進(jìn)行組織。以往,被拿來(lái)和數(shù)據(jù)庫(kù)表做對(duì)比,往往會(huì)令人困惑。如這篇文章所述,索引由Lucene處理,在分布式跨 分片 中,與類(lèi)型緊密地聯(lián)系在一起。
發(fā)送以下兩個(gè)請(qǐng)求以創(chuàng)建索引,并在該索引中插入文檔 (請(qǐng)記住 toolbox,如果使用docker ,請(qǐng)使用托管Docker的虛擬機(jī)ip而不是localhost) :

  • 創(chuàng)建一個(gè)名為 "default" 的新索引。

PUT localhost:9200/default
  • 在 "default" 索引中索引文檔。請(qǐng)注意,我們需要知道我們存儲(chǔ)哪種類(lèi)型的文檔("product")和該文檔的ID (如 1,盡管您可以使用任何值,只要它是唯一的)

PUT localhost:9200/default/product/1
{ 
    "name": "Apple MacBook Pro",
    "description": "Latest MacBook Pro 13",
    "tags": ["laptops", "mac"]
}

創(chuàng)建一個(gè)新索引

索引新文檔


在我們驗(yàn)證搜索功能和查詢(xún)數(shù)據(jù)之前,再索引幾個(gè) "product"。嘗試使用不同的 "tags",如 "laptops"和 "laptops",并記得使用不同的ids!
完成后,讓我們按名稱(chēng)排序的搜索所有被索引的文檔。您可以使用查詢(xún)字符串或 GET/POST 同樣的內(nèi)容,下面兩個(gè)請(qǐng)求是等效的:

GET http://localhost:9200/default/_search?q=*&sort=name.keyword:asc
POST http://localhost:9200/default/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "name.keyword": "asc" }
  ]
}

讓我們嘗試一些更有趣的東西,例如搜索 "description" 字段中含有 "latest" ,同時(shí) "tags" 字段中含有 "laptops" 的所有文檔:

POST http://localhost:9200/default/_search
{
  "query": { 
      "bool": {
      "must": [
        { "match": {"description": "latest"} },
        { "match": { "tags": "laptops" } }
      ]
    }
  },
  "sort": [
    { "name.keyword": "asc" }
  ]
}

搜索結(jié)果

Kibana 可視化數(shù)據(jù)

作為介紹的最后部分,我們將對(duì) Kibana 的相關(guān)知識(shí)蜻蜓點(diǎn)水。
假設(shè)您在上一步已經(jīng)索引了幾個(gè)文檔,通過(guò)訪問(wèn) http://localhost:5601 中打開(kāi)在 Docker 的 Kibana 服務(wù)器。你會(huì)注意到,Kibana 要求你提供默認(rèn)的索引模式,所以必須告訴它使用的 Elasticsearch 索引:

  • 我們?cè)谏弦还?jié)中創(chuàng)建了一個(gè)名為 "default" 的索引,因此可以使用 "default" 作為索引模式。

  • 您還需要取消 "索引包含基于時(shí)間的事件 (Index contains time-based events ) " 選項(xiàng),因?yàn)槲覀兊奈臋n不包含任何時(shí)間字段。

在 Kibana 中添加索引模式


完成后,使用左側(cè)菜單打開(kāi) " 發(fā)現(xiàn) (Discover) " 頁(yè)面,您應(yīng)該會(huì)看到上一節(jié)中插入的所有最新文檔。嘗試選擇不同的字段,在搜索欄中輸入相關(guān)的字段或某個(gè)過(guò)濾器:

在 kibana 中可視化數(shù)據(jù)


最后,我們創(chuàng)建一個(gè)餅圖,顯示 "laptops" 或 "desktops" 的銷(xiāo)量百分比。利用之前索引的數(shù)據(jù),在左側(cè)菜單新建一個(gè) "餅圖 (Pie Chart)" 。
您可以在 餅圖 (Pie Chart)的頁(yè)面上配置。將 " Count " 作為切片的大小,并在 " buckets " 部分中選擇 " split slices " 。將 " filters " 作為聚合類(lèi)型,添加兩個(gè)過(guò)濾器:tags ="laptop" 和 tags ="desktoptops" 。單擊運(yùn)行,您將看到類(lèi)似于下圖:

在Kibana中創(chuàng)建餅圖


確保在搜索欄中輸入包含已過(guò)濾的項(xiàng)目的搜索關(guān)鍵詞,并注意到可視化圖形如何變化。

Elasticsearch .Net API

在簡(jiǎn)要介紹Elasticsearch和Kibana之后,我們來(lái)看看我們?nèi)绾斡?.Net 應(yīng)用程序索引和查詢(xún)我們的文檔。
您可能想知道為什么要這樣做,而不是直接使用 HTTP API 。我可以提供幾個(gè)理由,我相信你可以自己找?guī)讉€(gè):

  • 你不想直接暴露 Elasticsearch 集群

  • Elasticsearch 可能不是您的主數(shù)據(jù)庫(kù),您可能需要結(jié)合來(lái)自主數(shù)據(jù)庫(kù)的結(jié)果。

  • 你希望包含來(lái)自存儲(chǔ)/生產(chǎn)服務(wù)器中的被索引文檔

首先需要注意的是打開(kāi) 這個(gè)文檔 ,有兩個(gè)官方提供的 APIs : Elasticsearch.Net 和 NEST ,都支持 .Net Core 項(xiàng)目。

  • Elasticsearch.Net 提供了一個(gè)用于與 Elasticsearch連接的低級(jí)API,提供構(gòu)建/處理請(qǐng)求和響應(yīng)的功能。它是 .Net 瘦客戶端。

  • NEST 在 Elasticsearch.Net 之上,提供了更高級(jí)別的 API 。它可以將對(duì)象映射到請(qǐng)求/響應(yīng)中,提供強(qiáng)大查詢(xún)功能,將索引名稱(chēng)、文檔類(lèi)型、字段類(lèi)型用于構(gòu)建與 HTTP REST API 的匹配查詢(xún)。

    Elasticsearch .Net API

由于我使用的是 NEST,所以第一步是創(chuàng)建一個(gè)新的 ASP .Net Core 應(yīng)用程序,并使用 Package Manager 安裝NEST。

使用Nest開(kāi)始索引數(shù)據(jù)

我們將在新的 ASP.Net Core 應(yīng)用程序中完成之前手動(dòng)發(fā)送 HTTP 請(qǐng)求的一些步驟。如果需要,請(qǐng)重新啟Docker 容器,從而清理數(shù)據(jù);或通過(guò) HTTP API 和 Postman 手動(dòng)刪除文檔/索引。
我們首先為產(chǎn)品創(chuàng)建一個(gè)POCO模型:

public class Product
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string[] Tags { get; set; }        
}

接下來(lái),我們創(chuàng)建一個(gè)新的控制器 ProductController,它具有添加新的 "Product" 的方法和基于單個(gè)關(guān)鍵詞查找 "Product" 的方法:

[Route("api/[controller]")]
public class ProductController : Controller
{

    [HttpPost]
    public async Task< IActionResult > Create([FromBody]Product product)
    {
    }

    [HttpGet("find")]
    public async Task< IActionResult > Find(string term)
    {
    }
}

為了實(shí)現(xiàn)這些方法,我們需要先連接到 Elasticsearch。這里有一個(gè) ElasticClient 連接的正確示范。 由于該類(lèi)是線程安全的,所以推薦的方法是在應(yīng)用程序中使用單例模式,而不是按請(qǐng)求創(chuàng)建新的連接。

為了簡(jiǎn)潔起見(jiàn),我現(xiàn)在將使用帶有硬編碼設(shè)置的私有靜態(tài)變量。在 .Net Core 中使用依賴(lài)注入配置框架,或查看 Github中 的代碼

可以想到的是,至少需要提供被連接的 Elasticsearch 集群的URL。當(dāng)然,還有其他可選參數(shù),用于與您的群集進(jìn)行身份驗(yàn)證、設(shè)置超時(shí)、連接池等。

private static readonly ConnectionSettings connSettings =
    new ConnectionSettings(new Uri("http://localhost:9200/"));        
private static readonly ElasticClient elasticClient = 
    new ElasticClient(connSettings);

建立連接后,索引文檔只是簡(jiǎn)單地使用 ElasticClient 的Index/IndexAsync 方法:

[Route("api/[controller]")]
public class ProductController : Controller
{

    [HttpPost]
    public async Task<IActionResult> Create([FromBody]Product product)
    {
    }

    [HttpGet("find")]
    public async Task<IActionResult> Find(string term)
    {
    }
}

很簡(jiǎn)單,對(duì)吧?不幸的是,如果您向Postman發(fā)送以下請(qǐng)求,您將看到失敗。

POST http://localhost:65113/api/product
{ 
    "name": "Dell XPS 13",
    "description": "Latest Dell XPS 13",
    "tags": ["laptops", "windows"]
}

這是因?yàn)镹EST無(wú)法確定在索引文檔時(shí)使用哪個(gè)索引!如果您想起手動(dòng)使用 HTTP API 的做法,那么需要在URL指出文檔的索引、文檔的類(lèi)型和ID,如 localhost:9200/default/product/1

NEST能夠推斷文檔的類(lèi)型(使用類(lèi)的名稱(chēng)),還可以默認(rèn)對(duì)字段進(jìn)行索引(基于字段的類(lèi)型),但需要一些索引名稱(chēng)的幫助。您可以指定默認(rèn)的索引名稱(chēng),以及特定類(lèi)型的特定索引名稱(chēng)。

connSettings = new ConnectionSettings(new Uri("http://192.168.99.100:9200/"))
    .DefaultIndex("default")
    //Optionally override the default index for specific types
    .MapDefaultTypeIndices(m => m
        .Add(typeof(Product), "default"));

進(jìn)行這些更改后再試一次。您將看到 NEST 創(chuàng)建索引(如果尚未存在),并將文檔編入索引。如果你切換到 Kibana,你也可以看到該文檔。需要注意的是:

  • 從類(lèi)的名稱(chēng)推斷文檔類(lèi)型,如 Product

  • 在類(lèi)中將Id屬性推斷為標(biāo)識(shí)

  • 將所有公開(kāi)的屬性發(fā)送到 Elasticsearch

使用NEST索引的文檔


在我們查詢(xún)數(shù)據(jù)之前,重新考慮創(chuàng)建索引的方式。
如何創(chuàng)建索引?
現(xiàn)在我們得到一個(gè)事實(shí),即如果這個(gè)索引不存在,也會(huì)被創(chuàng)建。然而映射字段的索引方式很重要,并直接定義了 Elasticsearch 如何索引和分析這些字段。這對(duì)于字符串字段尤其明顯,因?yàn)樵?Elasticsearch v5 中提供了兩種不同字段類(lèi)型的 "Text" 和 "Keyword":

  • Text 類(lèi)型的字段將會(huì)被分析和分解成單詞,以便用于更高級(jí)的 Elasticsearch 搜索功能

  • 另一方面,Keyword 字段將 "保持原樣" 而不進(jìn)行分析,只能通過(guò)其精確值進(jìn)行搜索。

您可以使用 NEST 索引映射屬性來(lái)生成POCO模型:

public class Product
{
    public Guid Id { get; set; }
    [Text(Name="name")]
    public string Name { get; set; }
    [Text(Name = "description")]
    public string Description { get; set; }
    [Keyword(Name = "tag")]
    public string[] Tags { get; set; }        
}

然而,我們需要先創(chuàng)建索引,必須使用 ElasticClient API 手動(dòng)創(chuàng)建和定義索引的映射。這是非常簡(jiǎn)單的,特別是如果我們只是使用屬性:

if (!elasticClient.IndexExists("default").Exists)
{
    elasticClient.CreateIndex("default", i => i
        .Mappings(m => m
            .Map<Product>(ms => ms.AutoMap())));
}

直接向Elasticsearch發(fā)送請(qǐng)求(GET localhost:92000/default),并注意與我們想要的映射是否相同。

使用NEST創(chuàng)建索引映射

使用Nest查詢(xún)數(shù)據(jù)

現(xiàn)在,我們有一個(gè)使用 NEST 對(duì) "products" 進(jìn)行索引的 ProductController 控制器。是時(shí)候,為這個(gè)控制器添加 Find action,用于使用 NEST 向 Elasticsearch 查詢(xún)文檔。
我們只是用到一個(gè)字段來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的搜索。您應(yīng)該觀察所有字段:

  • 映射為 "Text" 類(lèi)型的字段可以被分析,您可以在 "name" / "description" 字段內(nèi)搜索特定的單詞

  • 映射為 "Keywords" 的字段是保持原樣的,未進(jìn)行分析。您只能在 "tags" 字段中完全匹配。

NEST 提供了一個(gè)查詢(xún) Elasticsearch 的豐富 API,可以轉(zhuǎn)換成標(biāo)準(zhǔn)的 HTTP API 。實(shí)現(xiàn)上述查詢(xún)類(lèi)型與使用Search/SearchAsync方法一樣簡(jiǎn)單,并構(gòu)建一個(gè) SimpleQueryString 作為參數(shù)。

[HttpGet("find")]
public async Task<IActionResult> Find(string term)
{
    var res = await elasticClient.SearchAsync<Product>(x => x
        .Query( q => q.
            SimpleQueryString(qs => qs.Query(term))));
    if (!res.IsValid)
    {
        throw new InvalidOperationException(res.DebugInformation);
    }

    return Json(res.Documents);
}

使用PostMan測(cè)試您的新操作:

使用nest查詢(xún)


正如您可能已經(jīng)意識(shí)到的那樣,我們的操作行為與手動(dòng)發(fā)送請(qǐng)求到 Elasticsearch 一樣:

GET http://localhost:9200/default/_search?q=*&

在 .Net Core 中創(chuàng)建一個(gè)Elasticsearch日志提供程序

現(xiàn)在我們了解了 NEST 的一些基礎(chǔ)知識(shí),讓我們嘗試一些更有野心的事情。我們已經(jīng)創(chuàng)建了一個(gè) ASP.Net Core 的應(yīng)用程序,借助.NET Core的日志框架,實(shí)現(xiàn)我們的日志提供程序,并將信息發(fā)送到Elasticsearch。
新的日志 API 在日志 (logger) 和日志提供程序 (logger provider) 方面的區(qū)別:

  • 日志 (logger) 記錄信息和事件,如用于控制器中

  • 可以為應(yīng)用程序添加并啟用多個(gè)日志提供程序 (provider) ,并可以配置獨(dú)立的記錄級(jí)別和記錄相應(yīng)的信息/事件。

該日志框架內(nèi)置了一些對(duì)事件日志、Azure 等的日志提供程序 (provider),但正如您將看到的,創(chuàng)建自己的并不復(fù)雜。有關(guān)詳細(xì)信息,請(qǐng)查閱.NET Core 關(guān)于日志的官方文檔。
在本文的最后部分,我們將為Elasticsearch創(chuàng)建一個(gè)新的日志提供程序,在我們的應(yīng)用程序中啟用它,并使用Kibana來(lái)查看記錄的事件。

為Elasticsearch添加一個(gè)新的日志提供程序

首先要做的是定義一個(gè)新的POCO對(duì)象,我們將使用它作為使用NEST進(jìn)行索引的文檔,類(lèi)似于之前創(chuàng)建的 "Product" 類(lèi)。
這將包含有關(guān)可能發(fā)生的任何異常以及相關(guān)請(qǐng)求數(shù)據(jù)的記錄信息、可選信息。記錄請(qǐng)求數(shù)據(jù)將會(huì)派上用場(chǎng),因?yàn)槲覀兛梢愿鶕?jù)具體請(qǐng)求查詢(xún)/可視化我們記錄的事件。

public class LogEntry
{
    public DateTime DateTime { get; set; }
    public EventId EventId { get; set; }
    [Keyword]
    [JsonConverter(typeof(StringEnumConverter))]
    public Microsoft.Extensions.Logging.LogLevel Level { get; set; }
    [Keyword]
    public string Category { get; set; }
    public string Message { get; set; }

    [Keyword]
    public string TraceIdentifier { get; set; }
    [Keyword]
    public string UserName { get; set; }        
    [Keyword]
    public string ContentType { get; set; }
    [Keyword]
    public string Host { get; set; }         
    [Keyword]
    public string Method { get; set; }        
    [Keyword]
    public string Protocol { get; set; }
    [Keyword]
    public string Scheme { get; set; }
    public string Path { get; set; }
    public string PathBase { get; set; }
    public string QueryString { get; set; }
    public long? ContentLength { get; set; }
    public bool IsHttps { get; set; }
    public IRequestCookieCollection Cookies { get; set; }
    public IHeaderDictionary Headers { get; set; }

    [Keyword]
    public string ExceptionType { get; set; }        
    public string ExceptionMessage { get; set; }
    public string Exception { get; set; }
    public bool HasException { get { return Exception != null; } }
    public string StackTrace { get; set; }
}

下一步是在一個(gè)新類(lèi)上實(shí)現(xiàn)ILogger接口。如您所想,這將需要記錄的數(shù)據(jù)映射到一個(gè)新的 LogEntry 對(duì)象,并使用 ElasticClient 對(duì)其進(jìn)行索引。

  • 我們將使用IHttpContextAccessor,以便我們可以獲取當(dāng)前的HttpContext并提取相關(guān)的請(qǐng)求屬性。

在這里就不寫(xiě)連接到Elasticsearch并創(chuàng)建索引的代碼,這與之前的操作,沒(méi)有什么不同。使用不同的索引或刪除上一節(jié)中索引的 "products" 。

注意: 您可以使用依賴(lài)注入和配置文檢查 Github 中 的配套代碼。

實(shí)現(xiàn)的主要方法是Log <TState>,這是我們創(chuàng)建一個(gè)LogEntry并用NEST進(jìn)行索引:

public void Log< TState >(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func< TState, Exception, string > formatter)
{
    if (!IsEnabled(logLevel)) return;

    var message = formatter(state, exception);
    var entry = new LogEntry
    {
        EventId = eventId,
        DateTime = DateTime.UtcNow,
        Category = _categoryName,
        Message = message,
        Level = logLevel
    };

    var context = _httpContextAccessor.HttpContext;
    if (context != null)
    {                
        entry.TraceIdentifier = context.TraceIdentifier;
        entry.UserName = context.User.Identity.Name;
        var request = context.Request;
        entry.ContentLength = request.ContentLength;
        entry.ContentType = request.ContentType;
        entry.Host = request.Host.Value;
        entry.IsHttps = request.IsHttps;
        entry.Method = request.Method;
        entry.Path = request.Path;
        entry.PathBase = request.PathBase;
        entry.Protocol = request.Protocol;
        entry.QueryString = request.QueryString.Value;
        entry.Scheme = request.Scheme;

        entry.Cookies = request.Cookies;
        entry.Headers = request.Headers;
    }

    if (exception != null)
    {
        entry.Exception = exception.ToString();
        entry.ExceptionMessage = exception.Message;
        entry.ExceptionType = exception.GetType().Name;
        entry.StackTrace = exception.StackTrace;
    }

    elasticClient.Client.Index(entry);
}

您還需要額外實(shí)現(xiàn) BeginScope 和 IsEnabled 方法。

  • 為了本文的目的,忽略 BeginScope,只返回null。

  • 更新您的構(gòu)造函數(shù),以便它接收一個(gè)日志級(jí)別(LogLevel),如果接收到大于或等于構(gòu)造函數(shù)中的日志級(jí)別,則實(shí)現(xiàn) IsEnabled 并返回 true。

你可能會(huì)問(wèn)為什么需要分類(lèi)?這是一個(gè)用于標(biāo)識(shí)日志是哪種類(lèi)型的字符串。默認(rèn)情況下,每次注入ILogger <T>的實(shí)例時(shí),該類(lèi)別默認(rèn)分配為T(mén)的分類(lèi)名稱(chēng)。例如,獲取ILogger <MyController>并使用它來(lái)記錄某些事件,意味著這些事件將具有 "MyController " 名稱(chēng)。
這可能派上用場(chǎng),例如為不同的類(lèi)設(shè)置不同的日志級(jí)別,以過(guò)濾/查詢(xún)記錄的事件。我相信您可能還想到更多的用法。

這個(gè)類(lèi)的實(shí)現(xiàn)將如下所示:

public class ESLoggerProvider: ILoggerProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly FilterLoggerSettings _filter;

    public ESLoggerProvider(IServiceProvider serviceProvider, FilterLoggerSettings filter = null)
    {
        _httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
        _filter = filter ?? new FilterLoggerSettings
        {
            {"*", LogLevel.Warning}
        };
    }

    public ILogger CreateLogger(string categoryName)
    {
        return new ESLogger(_httpContextAccessor, categoryName, FindLevel(categoryName));
    }

    private LogLevel FindLevel(string categoryName)
    {
        var def = LogLevel.Warning;
        foreach (var s in _filter.Switches)
        {
            if (categoryName.Contains(s.Key))
                return s.Value;

            if (s.Key == "*")
                def = s.Value;
        }

        return def;
    }

    public void Dispose()
    {
    }
}

最后,我們創(chuàng)建一個(gè)擴(kuò)展方法,可以用于在啟動(dòng)類(lèi)中注冊(cè)我們的日志提供程序:

public static class LoggerExtensions
{
    public static ILoggerFactory AddESLogger(this ILoggerFactory factory, IServiceProvider serviceProvider, FilterLoggerSettings filter = null)
    {
        factory.AddProvider(new ESLoggerProvider(serviceProvider, filter));
        return factory;
    }
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"))
        .AddDebug()
        .AddESLogger(app.ApplicationServices, new FilterLoggerSettings
        {
            {"*", LogLevel.Information}
        });
    …
}

請(qǐng)注意我如何覆蓋默認(rèn)設(shè)置并按日志級(jí)別分類(lèi)記錄。這樣,我們可以輕松地為每個(gè)請(qǐng)求索引一些事件。

在Kibana中可視化數(shù)據(jù)

現(xiàn)在我們已經(jīng)在Kibana中記錄了事件,我們來(lái)探索數(shù)據(jù)可視化吧!
首先,在Kibana中重建索引,這次確保選擇" Index contains time-based events ( Index包含基于時(shí)間的事件 )",選擇字段dateTime作為"Time-field name (時(shí)間字段名稱(chēng))"。
接下來(lái),啟動(dòng)您的應(yīng)用程序,瀏覽一些頁(yè)面以獲取一些事件日志。還可以在某個(gè)端點(diǎn)隨意添加拋出異常的代碼,以便我們可以看到被記錄的異常數(shù)據(jù)。
在這之后,請(qǐng)轉(zhuǎn)到Kibana的 發(fā)現(xiàn) (Discover) 頁(yè)面,您可以看到由 "dateTime" 字段排序的多個(gè)事件(默認(rèn)情況下,數(shù)據(jù)被過(guò)濾為最近15分鐘,但您可以在右上角更改):

Kibana可視化中記錄的事件


試著在搜索欄中輸入 "exception",并注意任何一個(gè)被分析的文本字段中包含 "exception" 的事件。然后嘗試搜索特定的異常類(lèi)型(記住我們使用了一個(gè)關(guān)鍵字字段!)。
您還可以嘗試搜索特定的URL,如以 " /Home/About "和" /Home/About" 路徑的兩種搜索方式 。您會(huì)注意到第一種情況包括引用者是 "/Home/About" 的事件,而第二種情況則只能正確返回路徑為 "/Home/About" 的事件。
一旦你熟悉了數(shù)據(jù),以及如何查詢(xún)數(shù)據(jù),那么可以用數(shù)據(jù)創(chuàng)建一些有趣的圖形。
首先,我們將創(chuàng)建一個(gè)圖表,顯示每分鐘記錄的異常數(shù)。

  • 轉(zhuǎn)到Kibana的 可視化 (Visualize) 頁(yè)面,并創(chuàng)建一個(gè)新的 垂直條形圖 (Vertical bar chart) 。

  • 選擇Y軸作為計(jì)數(shù),X軸上為日期的直方圖。

  • 將間隔設(shè)置為每分鐘,最后在搜索框中添加一個(gè)過(guò)濾器 "hasException:true" 。

一個(gè)很棒的圖表,顯示每分鐘記錄的異常數(shù)目:

每分鐘記錄的異常數(shù)目


接下來(lái),顯示每個(gè) category 隨時(shí)間記錄的消息數(shù)量,限于前5個(gè) category :

  • 轉(zhuǎn)到Kibana的 可視化 (Visualize) 頁(yè)面,并創(chuàng)建一個(gè)新的 線型圖 (Line chart) 。

  • 再次選擇Y軸作為計(jì)數(shù),X軸上為日期的直方圖,選擇dateTime作為字段,間隔為每分鐘。

  • 現(xiàn)在添加一個(gè) sub-bucket 并選擇 "split lines" 。使用 "significant terms" 作為聚合,category 為字段,單位為5個(gè)。

這將繪制類(lèi)似于以下的圖表:

隨著時(shí)間的推移


嘗試在搜索框中添加一些過(guò)濾器,并查看它對(duì)結(jié)果的影響。
最后,我們添加另一個(gè)圖表,我們將看到前五個(gè)出現(xiàn)最多的消息和前五個(gè) categories 的消息。

  • 轉(zhuǎn)到Kibana的 可視化 (Visualize) 頁(yè)面,并創(chuàng)建一個(gè)新的 餅圖 (Pie chart) 。

  • 像之前一樣,選擇Y軸的計(jì)數(shù)

  • 現(xiàn)在,將 "Terms" 作為聚合,將 "category" 作為字段,數(shù)量作為單位,限制前五個(gè),畫(huà)出圖表。

  • 然后將 "Terms" 作為聚合來(lái)分割切片,"message.keyword" 作為字段,數(shù)量作為單位,限制前五個(gè)。
    一旦你有了這些設(shè)置,你會(huì)看到一個(gè)類(lèi)似于這個(gè)圖表:

每個(gè) category 中最常見(jiàn)的消息


花時(shí)間觀察下數(shù)據(jù)(百分比,message/category 顯示在圖表元素上)。例如,您將觀察到由
DeveloperExceptionPageMiddleware類(lèi)記錄的異常。

結(jié)論

Elasticsearch是一個(gè)強(qiáng)大的數(shù)據(jù)索引和查詢(xún)平臺(tái)。雖然它本身相當(dāng)令人印象深刻,但與其他應(yīng)用程序(如Kibana)相結(jié)合,可以很好地分析、報(bào)告和可視化數(shù)據(jù)。只要您開(kāi)始使用,只是蜻蜓點(diǎn)水都能的到非凡的結(jié)果。
對(duì)于 .Net 和 .Net Core,Elasticsearch 官方的 API 已經(jīng)覆蓋,因?yàn)樗鼈冎С?.Net Standard 1.3和更高版本(他們?nèi)匀辉跒?.1提供支持)。
正如我們已經(jīng)看到的,在 ASP.Net Core 項(xiàng)目中使用這個(gè) API 是很方便的,我們可以輕松地將其 REST API 作為存儲(chǔ),以及在應(yīng)用程序中作為日志提供程序。
最后但并非不重要的一點(diǎn),我希望您使用Docker。嘗試使用 Elasticsearch,同時(shí)思考Docker可以為您和您的團(tuán)隊(duì)做些什么。

本文題目:使用ElasticSearch,Kibana,ASP.NETCore和Docker可視化數(shù)據(jù)
分享地址:http://chinadenli.net/article20/pgdhco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT建站公司、移動(dòng)網(wǎng)站建設(shè)微信公眾號(hào)、小程序開(kāi)發(fā)網(wǎng)站改版

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

小程序開(kāi)發(fā)