使用.NET Standard 2的Elasticsearch,Kibana和Docker

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mzl87/article/details/86516300

目录

介绍

背景

设置基础结构

设置解决方案

控制台文件

packages.config

appsettings.json

Program.cs中

LogProducer文件

BasicLogProducer.cs

配置,运行和测试


现代.NET应用程序的高级日志记录 周日早晨的概念证明。

介绍

在本文中,您将学习如何设置开发环境以将ElasticsearchKibana用于日志记录。在此过程中,您将使用Docker,非常基本的用法,您还将了解在Windows经典桌面应用程序中使用.NET标准库是多么容易。

背景

我将证明ElasticsearchKibana在我们的系统中的集成非常简单。为此,我将设置和配置Docker网络和两个Docker镜像,一个用于Elasticsearch,另一个用于Kibana。此基础结构将由Windows 经典桌面控制台使用,该控制台将执行一些随机日志记录。我将配置三个日志输出,控制台,并且使用Serilog,我将配置并使用滚动文件shinkElasticsearch Shink。这些Shinks将在.NET Standard 2库中使用,但这个库将由控制台应用程序引用,使用最新的Microsoft Dependency Injection Extensions

设置基础结构

首先,我们需要在我们的机器中安装和配置好Docker,我使用Win10Docker for Windows。(如果你没有它,你可以在这里找到它)。我们只需要运行三个命令来设置Docker的所有内容。(这太棒了,不是吗?)

  • docker network create elk-logging-poc --driver=bridge
  • docker run -p 5601:5601 --name kibana -d --network elk-logging-poc kibana
  • docker run -p 9200:9200 -p 9300:9300 --name elasticsearch -d --network elk-logging-poc elasticsearch

第一个创建了一个在这个概念证明中使用的网络,第二个运行Kibana,如果它本地不存在则从Docker Hub中提取图像,第三个用于Elasticsearch

初始状态:

https://www.codeproject.com/KB/dotnet/1218350/InitialStatus.png

  1. 创建网络:

https://www.codeproject.com/KB/dotnet/1218350/NetworkCreated.png

  1. 安装并运行Kibana

https://www.codeproject.com/KB/dotnet/1218350/InstallingKibana.png

此时,安装了Kibana但是如果我们转到localhost5601,我们可以看到Kibana缺少Elasticsearch

https://www.codeproject.com/KB/dotnet/1218350/KibanaFirstLoad.png

安装Elasticsearch

https://www.codeproject.com/KB/dotnet/1218350/InstallingElasticsearch.png

现在Kibana已准备好配置:

https://www.codeproject.com/KB/dotnet/1218350/KibanaSetupIndex.png

设置解决方案

好吧,现在是时候设置我们的解决方案了,正如我所说,我将使用Windows经典桌面控制台应用程序和.NET标准库。所以,我将创建一个新的解决方案和WCD控制台项目:

https://www.codeproject.com/KB/dotnet/1218350/CreatingWcdConsoleProject.png

提示:虽然它是POC,但我总是尝试使用强大的命名空间,我总是记住POC可以成为原型,然后是产品。这些事情发生了。

现在,让我们创建.NET标准库:

https://www.codeproject.com/KB/dotnet/1218350/CreatingNetStandardLibrary.png

结果将如下所示:

https://www.codeproject.com/KB/dotnet/1218350/Solution.png

控制台文件

为了节省您的时间,你需要安装在packages.config中列出的NuGet 包到控制台应用程序,容易手动安装。

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Elasticsearch.Net" 

  version="5.5.0" targetFramework="net462" />
  <package id="Microsoft.DotNet.InternalAbstractions" 

  version="1.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Configuration" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Configuration.Abstractions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Configuration.Binder" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Configuration.FileExtensions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Configuration.Json" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.DependencyInjection" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.DependencyModel" 

  version="1.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.FileProviders.Abstractions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.FileProviders.Physical" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.FileSystemGlobbing" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Logging" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Logging.Abstractions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Logging.Console" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Logging.Debug" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Options" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Options.ConfigurationExtensions" 

  version="2.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.Primitives" 

  version="2.0.0" targetFramework="net462" />
  <package id="Newtonsoft.Json" 

  version="10.0.1" targetFramework="net462" />
  <package id="Serilog" 

  version="2.5.0" targetFramework="net462" />
  <package id="Serilog.Extensions.Logging" 

  version="2.0.2" targetFramework="net462" />
  <package id="Serilog.Settings.Configuration" 

  version="2.4.0" targetFramework="net462" />
  <package id="Serilog.Sinks.Elasticsearch" 

  version="5.4.0" targetFramework="net462" />
  <package id="Serilog.Sinks.File" 

  version="3.2.0" targetFramework="net462" />
  <package id="Serilog.Sinks.PeriodicBatching" 

  version="2.1.0" targetFramework="net462" />
  <package id="Serilog.Sinks.RollingFile" 

  version="3.3.0" targetFramework="net462" />
  <package id="System.Linq" 

  version="4.1.0" targetFramework="net462" />
  <package id="System.Resources.ResourceManager" 

  version="4.0.1" targetFramework="net462" />
  <package id="System.Runtime" 

  version="4.1.0" targetFramework="net462" />
  <package id="System.Runtime.CompilerServices.Unsafe" 

  version="4.4.0" targetFramework="net462" />
</packages>

appsettings.json

{
  "Logging": {
    "IncludeScopes": true,
 
    "Debug": {
      "LogLevel": {
        "Default": "Critical"
      }
    },
    "Console": {
      "LogLevel": {
        "Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
        "Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
        "Microsoft.AspNetCore.Mvc.Razor": "Error",
        "Default": "Critical"
      }
    },
    "LogLevel": {
      "Default": "Critical"
    }
  },
  "Serilog": {
    "WriteTo": [
      {
        "Name": "Elasticsearch",
        "Args": {
          "nodeUris": "http://localhost:9200;http://remotehost:9200/",
          "indexFormat": "elk-poc-index-{0:yyyy.MM}",
          "templateName": "myCustomTemplate",
          "typeName": "myCustomLogEventType",
          "pipelineName": "myCustomPipelineName",
          "batchPostingLimit": 50,
          "period": 2000,
          "inlineFields": true,
          "minimumLogEventLevel": "Trace",
          "bufferBaseFilename": "C:/Logs/docker-elk-serilog-web-buffer",
          "bufferFileSizeLimitBytes": 5242880,
          "bufferLogShippingInterval": 5000,
          "connectionGlobalHeaders": 
          "Authorization=Bearer SOME-TOKEN;OtherHeader=OTHER-HEADER-VALUE"
        }
      }
    ],
    "LogFile": "C:/Logs/ElasticSearchPoc.log",
    "MinimumLevel": "Information"
  }
}

Program.cs

using ElasticSearchPoc.Domain.LogProducer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using System;
 
namespace ElasticSearchPoc.Presentation.WCD.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create service collection
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);
 
            // Create service provider
            var serviceProvider = serviceCollection.BuildServiceProvider();
 
            // Run app (Every execution should create a new RunId)
            serviceProvider.GetService<BasicLogProducer>().Run();
        }
 
        private static void ConfigureServices(IServiceCollection serviceCollection)
        { 
            // Build configuration
            var configuration = new ConfigurationBuilder()
                .SetBasePath(AppContext.BaseDirectory)
                .AddJsonFile("appsettings.json", false)
                .Build();
 
            // Add console logging
            serviceCollection.AddSingleton(new LoggerFactory()
                .AddConsole(configuration.GetSection("Logging"))
                .AddSerilog()
                .AddDebug());
            serviceCollection.AddLogging();
 
            // Add Serilog logging           
            Log.Logger = new LoggerConfiguration()
                .WriteTo.RollingFile(configuration["Serilog:LogFile"])
                .ReadFrom.Configuration(configuration)
                .CreateLogger();
 
            // Add access to generic IConfigurationRoot
            serviceCollection.AddSingleton(configuration);
 
            // Add the App
            serviceCollection.AddTransient<BasicLogProducer>();
        }
    }
}

我想添加一些关于这些文件的评论,看一下appsettings.json中的不同日志级别,以及Elasticsearch选项,设置是这个POC的关键。另外,我想强调一下我们程序的源代码是干净的和SOLID,我必须公开表示感谢.NET基础库及其贡献者对这些非常有用的库和扩展。

我们来看看.NET标准库中的文件LogProducer

LogProducer文件

正如您将看到的,它唯一的依赖是Microsoft.Extensions.Logging......

BasicLogProducer.cs

using Microsoft.Extensions.Logging;
using System;
using System.Threading;
 
namespace ElasticSearchPoc.Domain.LogProducer
{
    public class BasicLogProducer
    {
        private readonly ILogger<BasicLogProducer> _logger;
 
        public BasicLogProducer(ILogger<BasicLogProducer> logger)
        {
            _logger = logger;
        }
 
        public void Run()
        {
            var runDate = DateTime.Now;
            while (true)
            {
                // Let's randomize our logs...
                Array values = Enum.GetValues(typeof(LogLevel));
                Random random = new Random();
                LogLevel randomLogLevel = (LogLevel)values.GetValue(random.Next(values.Length));
 
                switch (randomLogLevel)
                {
                    case LogLevel.Trace:
                        _logger.LogTrace($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Trace; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.Debug:
                        _logger.LogDebug($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Debug; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.Information:
                        _logger.LogInformation($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Information; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.Warning:
                        _logger.LogWarning($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Warning; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.Error:
                        _logger.LogError($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Error; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.Critical:
                        _logger.LogCritical($"RunDate: {runDate}; 
                        Message Id: {Guid.NewGuid()}; LogLevel: Critical; 
                        LogLevelValue: {randomLogLevel.ToString("D")}");
                        break;
                    case LogLevel.None:
                    default:
                        break;
                }
 
                Thread.Sleep(100); 
            }
        } 
    }
}

虽然我总是尝试编写不言自明的源代码,但这个类值得一个简短的解释。它使用DI(依赖注入),ILogger<T>正在创建,因为主机应用程序已注册ILoggingFactorySerilog,因此记录器将具有我们在主应用程序中配置的任何内容,在这种情况下我们的三个Shinks,控制台,文件和Elasticsearch。该Run方法获取初始运行日期并开始在每次迭代时生成具有随机日志级别的日志。这是非常基本但它会完成它的工作。

配置,运行和测试

我不打算提供太多细节。我想通过一些屏幕截图,您可以自己尝试一下。我们要做的第一件事就是在Kibana中配置主索引模式,正如您所看到的,具体而言这是我们在appsettings.json文件中具有的配置参数之一。我使用过"indexFormat": "elk-poc-index-{0:yyyy.MM}",所以我们必须像“ elk-poc-index-*” 那样配置Kibana索引:

https://www.codeproject.com/KB/dotnet/1218350/KibanaSetupIndex1.png

好吧,让我们启动我们的应用程序,看看会发生什么......

根据配置参数,控制台仅记录关键:

https://www.codeproject.com/KB/dotnet/1218350/ConsoleLoggingCriticalOnly.png

我们也正在记录到一个文件,如配置文件中所述,在我们的Main方法中,我将用几个截图来演示如何使用我知道的最好的Tail工具,Tail Blazer(如果你读到这一点,你不知道TailBlazer,那么你必须现在去尝试,因为你会喜欢它):

  1. 平台输出:

https://www.codeproject.com/KB/dotnet/1218350/TailBlazer0.png

https://www.codeproject.com/KB/dotnet/1218350/TailBlazer1.png

  1. 点击右上角的齿轮图标,我们可以添加一些亮点:

https://www.codeproject.com/KB/dotnet/1218350/TailBlazer2.pnghttps://www.codeproject.com/KB/dotnet/1218350/TailBlazer3.png

  1. 而且在主窗口中,我们可以添加一些过滤器:

https://www.codeproject.com/KB/dotnet/1218350/TailBlazer4.png

我会添加Fatal过滤器,所以只看到带有Fatal关键字的条目:

https://www.codeproject.com/KB/dotnet/1218350/TailBlazer5.png

ElasticsearchKibana怎么样?好吧,当我正在做这些截图时,控制台应用程序已经在控制台(仅限关键)中生成日志,在本地文件系统中的文件系统中具有信息级别,就像我们刚刚通过TailBlazer看到的那样,程序已经发送了日志到带有跟踪级别的Elasticsearch Shink,所以,如果我们转到Kibana并选择左侧菜单上的Timelion菜单项,我们应该能够看到一个图表,显示收到的日志数量,如下所示:

https://www.codeproject.com/KB/dotnet/1218350/KibanaTimeline1.png

这个图是有意义的,因为代码每秒发送大约10个日志,因为有一个Thread.Sleep(100),对吗?让我们强制应用程序一点,并将睡眠设置为仅10毫秒。如果我再次运行它,时间轴看起来像这样:

https://www.codeproject.com/KB/dotnet/1218350/KibanaTimeline2.png

如果我退出睡眠并强制我的机器生成尽可能多的日志怎么办?

好吧,文件日志增长得非常快,正如预期的那样(蓝色表示最近创建的,查看时间戳中的毫秒):

https://www.codeproject.com/KB/dotnet/1218350/z_A_tope1.png

CPU达到100%(正如预期的那样):

https://www.codeproject.com/KB/dotnet/1218350/z_A_tope2.png

Kibana的峰值达到每秒772个记录。考虑到一切都在同一台机器上运行并且我正在调试和监视日志文件,这不是太糟糕,我们可能会强制它更多。

https://www.codeproject.com/KB/dotnet/1218350/z_A_tope3.png

而且,嗯,今天就这样了,我仍然不知道如何使用Kibana正确地显示数据,但POC在这里完成,因为它按预期记录。

https://www.codeproject.com/KB/dotnet/1218350/ItLogs.png

 

原文地址:https://www.codeproject.com/Articles/1218350/Elasticsearch-Kibana-and-Docker-using-NET-Standard

猜你喜欢

转载自blog.csdn.net/mzl87/article/details/86516300