Согласно приложению 12 factor приложение должно записывать все журналы в stdout
/ stderr
.
Затем вам нужно собрать все журналы вместе и направить к одному или нескольким конечным пунктам назначения для просмотра ( Elasticserach ). Для этой цели доступны маршрутизаторы с открытым исходным кодом (например, FluentBit , Fluentd и Logplex ).
Итак, приложение никогда не касается сам с маршрутизацией или хранением своих логов. В приложении do tnet Вы можете легко добиться этого, используя Serilog
Допустим, у нас есть следующие настройки логгера в appsettings. json
"Logging": {
"OutputFormat": "console",
"MinimumLevel": "Information"
}
Мы можем создать метод расширения
private static IWebHostBuilder CreateWebHostBuilder() =>
WebHost.CreateDefaultBuilder()
.UseStartup<Startup>()
.UseLogging();
}
, который может записывать журналы в консоль как в виде простого текста, так и в форматеasticsearch. Журналы в виде простого текста будут полезны для разработки, потому что они более удобочитаемы. На Производстве мы включаем форматasticsearch и видим все журналы только в Кибане.
Код расширения с комментариями:
public static IWebHostBuilder UseLogging(this IWebHostBuilder webHostBuilder, string applicationName = null) =>
webHostBuilder
.UseSetting("suppressStatusMessages", "True") // disable startup logs
.UseSerilog((context, loggerConfiguration) =>
{
var logLevel = context.Configuration.GetValue<string>("Logging:MinimumLevel"); // read level from appsettings.json
if (!Enum.TryParse<LogEventLevel>(logLevel, true, out var level))
{
level = LogEventLevel.Information; // or set default value
}
// get application name from appsettings.json
applicationName = string.IsNullOrWhiteSpace(applicationName) ? context.Configuration.GetValue<string>("App:Name") : applicationName;
loggerConfiguration.Enrich
.FromLogContext()
.MinimumLevel.Is(level)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.Enrich.WithProperty("Environment", context.HostingEnvironment.EnvironmentName)
.Enrich.WithProperty("ApplicationName", applicationName);
// read other Serilog configuration
loggerConfiguration.ReadFrom.Configuration(context.Configuration);
// get output format from appsettings.json.
var outputFormat = context.Configuration.GetValue<string>("Logging:OutputFormat");
switch (outputFormat)
{
case "elasticsearch":
loggerConfiguration.WriteTo.Console(new ElasticsearchJsonFormatter());
break;
default:
loggerConfiguration.WriteTo.Console(
theme: AnsiConsoleTheme.Code,
outputTemplate: "[{Timestamp:yy-MM-dd HH:mm:ss.sssZ} {Level:u3}] {Message:lj} <s:{Environment}{Application}/{SourceContext}>{NewLine}{Exception}");
break;
}
});
Когда OutputFormat
равен elasticsearch
, журнал будет похож на
{"@ timestamp": "2020-02-07T16: 02: 03.4329033 + 02: 00", "level": "Information", "messageTemplate": "Получить клиента по id: {CustomerId } "," message ":" Получить клиента по id: 20 "," fields ": {" CustomerId ": 20," SourceContext ":" Customers.Api.Controllers.CustomerController "," ActionId ":" c9d77549-bb25- 4f87-8ea8-576dc6aa1c57 "," ActionName ":" Customers.Api.Controllers.CustomerController.Get (Customers.Api) "," RequestId ":" 0HLTBQP5CQHLM: 00000004 "," RequestPath ":" / v1 / Customers "," CorrelationId ":" daef8849b662117e», "ConnectionId": "0HLTBQP5CQHLM", "Окружающая среда": "Развитие", "ApplicationName": "API", "Отметка": "2020-02-07T14: 02: 03.4329033Z"}}
в другом случае (использовать только для отладки)
[20-02-07 13: 59: 16.16Z INF] Получить клиента по id: 20
Тогда вам нужно настроить лог-маршрут r собрать журналы из контейнера и отправить их в Elasticsearch.
Если все журналы структурированы , это улучшает поиск и создание индексов в Kibana.