Журналы из контейнерного WebApp не отправляются в Elasticsearch через Serilog.Sinks.Elasticsearch - PullRequest
0 голосов
/ 30 октября 2019

Я тестирую комбинацию библиотеки Serilog.Sinks.Elasticsearch и стека ELK (Elasticsearch & Kibana) для сбора журналов из моего приложения ASP.NET Core 2.2. Веб-приложение и службы ELK контейнеризируются через Docker.

При вращении всех контейнеров через docker-compose все в порядке, за исключением того, что по какой-то причине Elasticsearch Sink не передает журналы, созданные в HomeController.cs, в Elasticsearch. Это можно проверить на http://localhost:9200/_cat/indices?v, где не создается новый индекс с logstash- *.

Интересно то, что при запуске комбинации WebApp через IIS (не в контейнере) и стека ELK в контейнере,журналы создаются и отправляются в Elasticsearch. Я предполагаю, что что-то не так с конфигурацией порта или сети WebApp в файле docker-compose.yml.

Я также пытался переключить localhost сasticsearch (фактическое имя контейнераasticsearch) в appsettings.Development.json но безрезультатно.

Может кто-нибудь помочь мне с этой проблемой? Спасибо.

Файл Docker-compose.yml:

version: '3.4'
services:
  elastic.serilog.web:
    image: ${DOCKER_REGISTRY-}elasticserilogweb
    build:
      context: .
      dockerfile: Elastic.Serilog.Web/Dockerfile

  elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
   container_name: elasticsearch
   ports:
    - "9200:9200"
   volumes:
    - elasticsearch-data:/usr/share/elasticsearch/data
   environment:
    - discovery.type=single-node
    - xpack.security.enabled=false
    - xpack.monitoring.enabled=true
    - xpack.watcher.enabled=false
    - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
   networks:
    - docker-network

  kibana:
   image: docker.elastic.co/kibana/kibana:7.2.0
   container_name: kibana
   ports:
    - "5601:5601"
   depends_on:
    - elasticsearch
   environment:
    - ELASTICSEARCH_HOSTS="http://elasticsearch:9200"
    - XPACK_MONITORING_ENABLED=true
   networks:
    - docker-network

networks:
  docker-network:
    driver: bridge

volumes:
  elasticsearch-data:

Файл Docker-compose.override.yml:

version: '3.4'
services:
  elastic.serilog.web:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "80:7000"

Dockerfile:

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY Elastic.Serilog.Web/Elastic.Serilog.Web.csproj Elastic.Serilog.Web/
RUN dotnet restore Elastic.Serilog.Web/Elastic.Serilog.Web.csproj
COPY . .
WORKDIR /src/Elastic.Serilog.Web
RUN dotnet build Elastic.Serilog.Web.csproj -c Release -o /app

FROM build AS publish
RUN dotnet publish Elastic.Serilog.Web.csproj -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Elastic.Serilog.Web.dll"]

Appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
        "Default": "Error",
        "System": "Error",
        "Microsoft": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ElasticConfiguration": {
    "Uri": "http://localhost:9200/"
  }
}

Startup.cs:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Exceptions;
using Serilog.Sinks.Elasticsearch;
using System;

namespace Elastic.Serilog.Web
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(hostingEnvironment.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{hostingEnvironment.EnvironmentName}.json", reloadOnChange: true, optional: true)
                .AddEnvironmentVariables();

            Configuration = builder.Build();

            var elasticUri = Configuration["ElasticConfiguration:Uri"];

            Log.Logger = new LoggerConfiguration()
               .Enrich.FromLogContext()
               .Enrich.WithExceptionDetails()
               .Enrich.WithMachineName()
               .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticUri))
               {
                   AutoRegisterTemplate = true,
               })
            .CreateLogger();
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
             loggerFactory.AddSerilog();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            // app.UseHttpsRedirection();
            app.UseStaticFiles();
            // app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

HomeController.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Elastic.Serilog.Web.Models;
using Microsoft.Extensions.Logging;
using Serilog;

namespace Elastic.Serilog.Web.Controllers
{
    public class HomeController : Controller
    {
        ILogger<HomeController> _logger;
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        } 

        public IActionResult Index()
        {
            _logger.LogInformation($"oh hai there! : {DateTime.UtcNow}");

            Log.Error("Test Serilog!");

            try
            {
                throw new Exception("oops. i haz cause error in UR codez.");
            }
            catch (Exception ex)
            {
                _logger.LogCritical("ur app haz critical error", ex);
                _logger.LogError(ex, "ur code iz buggy.");

                Log.Information("Test Serilog!");

            }

            return View();
        }

        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

        public IActionResult Contact()
        {
            ViewData["Message"] = "Your contact page.";

            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

1 Ответ

0 голосов
/ 04 ноября 2019

Решено:

1.) Убедитесь, что все службы, определенные в docker-compose.yml, находятся в одной сети. В нашем случае мы должны поместить все сервисы в пользовательскую « docker-network ». (Если мы пропустим определение пользовательской сети, Docker будет использовать стандарт по умолчанию, который также находится в режиме моста - поэтому теоретически все контейнеры все равно будут использовать одну и ту же сеть).

2.) Поскольку мы запускаем службы в контейнерах "localhost" , более не актуален для адресации порта 9200 в appsettings.Development.json . Нам нужно изменить localhost на фактическое имя контейнера Elastic Search - в нашем случае "asticsearch ":

"ElasticConfiguration": { "Uri": "http://elasticsearch:9200/" }

После выполнения этих двух шагов serilog-sinks-asticsearch отправит все журналы в Elastic Search, и в дальнейшем по умолчанию в журнале будет виден индекс logstash- *.

...