Byndyusoft / Byndyusoft.Logging

Структурные логи в json формате

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Byndyusoft.Logging Nuget Downloads

Структурные логи в json формате.

Библиотека является набором пресетов для Serilog, которые позволяют добавлять поддержку логирования в несколько строк.

using Byndyusoft.Logging.Configuration;
using Serilog;

...

Host.CreateDefaultBuilder(args)
    .UseSerilog((context, configuration) => configuration
        .UseDefaultSettings(context.Configuration, "Sample project")
    )

В результате такого подключения будут добавлено логирование в стандартный вывод логов в формате json. Каждый вывод в лог производится с новой строки и занимает 1 строку.

Например, для тестового вывода будет, будет получен следущей лог:

var values = new[] {"value1", "value2"};
logger.LogInformation("запрошены {@Values}", (object)values);

Вывод (отформатированный):
{
	"Timestamp": "2021-04-09T13:12:58.2633978Z",
	"Message": "запрошены [\"value1\", \"value2\"]",
	"MessageTemplateHash": "05114bc8",
	"Level": "Information",
	"Properties": {
		"Values": [
			"value1",
			"value2"
		]
	}
}

Где:

  • Timestamp — время в utc в которое создана запись лога
  • Message — залогированное сообщение с подставленными параметрами
  • MessageTemplateHash — хэш шаблона сообщения, который не зависит от параметров
  • Level — уровень лога
  • Properties.* — все остальные свойства сообщения
  • Values — параметры сообщения

Кроме того Properties.* обогащается полями добавленными в контекст лога. Т.е. если вызывать logger.LogInformation("запрошены {@Values}", (object)values) из метода контроллера, то в Properties добавятся следующие поля, которые добавляет инфраструктура asp.net

"SourceContext": "Byndyusoft.Logging.Sample.Controllers.ValuesController",
"ActionId": "21eb782a-3717-4616-9927-7d2a5a23c8b8",
"ActionName": "Byndyusoft.Logging.Sample.Controllers.ValuesController.Get (Byndyusoft.Logging.Sample)",
"RequestId": "0HM7RB4OJU2MI:00000001",
"RequestPath": "/api/values",
"SpanId": "|b01373be-4fffa4bff3ac61ea.",
"TraceId": "b01373be-4fffa4bff3ac61ea",
"ParentId": "",
"ConnectionId": "0HM7RB4OJU2MI",

В случе логирования исключения, добавляет информация об исключении (ToString()) и хэш стектрейса для поиска аналогичных исключений. Хэш считается без учёта номеров строк.

logger.LogError(ex, "Должен совпасть хэш ошибки")

{
    "Timestamp":"2021-04-09T10:10:16.6873034Z",
    "Message":"Должен совпасть хэш ошибки",
    "MessageTemplateHash":"3e4763a9",
    "Level":"Error",
    "Exception":"System.Exception: Что-то пошло не так\r\n ---> System.NotImplementedException: Скоро сделаем\r\n   at Byndyusoft.Logging.Sample.Controllers.ValuesController.ThrowError() in C:\\work\\reps\\Byndyusoft.Logging\\src\\Byndyusoft.Logging.Sample\\Controllers\\ValuesController.cs:line 58\r\n   at Byndyusoft.Logging.Sample.Controllers.ValuesController.ThrowErrorWithInnerError() in C:\\work\\reps\\Byndyusoft.Logging\\src\\Byndyusoft.Logging.Sample\\Controllers\\ValuesController.cs:line 65\r\n   --- End of inner exception stack trace ---\r\n   at Byndyusoft.Logging.Sample.Controllers.ValuesController.ThrowErrorWithInnerError() in C:\\work\\reps\\Byndyusoft.Logging\\src\\Byndyusoft.Logging.Sample\\Controllers\\ValuesController.cs:line 69\r\n   at Byndyusoft.Logging.Sample.Controllers.ValuesController.GetError() in C:\\work\\reps\\Byndyusoft.Logging\\src\\Byndyusoft.Logging.Sample\\Controllers\\ValuesController.cs:line 44",
    "ExceptionHash":"533f548e",
    ...
}

Поддержка трассировки

OpenTracing Nuget Downloads

Сначала нужно подключить Byndyusoft.Logging.OpenTracing

Можно заменить значения TraceId и SpanId на полученные от OpenTracing. ParentId совсем удаляет.

.UseSerilog((context, configuration) => configuration
    .UseOpenTracingTraces()

Можно сделать так, чтобы всё что пишется в логи, оказалось в трасах.

.UseSerilog((context, configuration) => configuration
    .WriteToOpenTracing()

OpenTelemetry Nuget Downloads

Сначала нужно подключить Byndyusoft.Logging.OpenTelemetry

Можно заменить значения TraceId и SpanId на полученные от OpenTelemetry. ParentId совсем удаляет.

.UseSerilog((context, configuration) => configuration
    .UseOpenTelemetryTraces()

Можно сделать так, чтобы всё что пишется в логи, оказалось в трасах.

.UseSerilog((context, configuration) => configuration
    .WriteToOpenTelemetry()

Предусмотренные сценарии

Как добавить вывод в файл?

.UseSerilog((context, configuration) => configuration
    .UseFileWriterSettings()

В рабочей паке будут добавлены 2 файла logs/verbose.log и error.log

Как изменить уровень логирования на проде?

Это просто Serilog. Поэтому в ваших настройках должен быть параметр Serilog:MinimumLevel:Default с желаемым уровнем логирования. В переменных окружения : нужно заменить на __: Serilog__MinimumLevel__Default.

Мне не подходят стандартные настройки

Помните, что это всё ещё обычный Serilog. Вы можете изменить настройки так, как вам нравится. Скажем UseDefaultSettings представляет из себя следующей вызов:

return loggerConfiguration
    .Enrich.FromLogContext()
    .UseConsoleWriterSettings(restrictedToMinimumLevel)
    .OverrideDefaultLoggers()
    .ReadFrom.Configuration(configuration)

Можно использовать только те его части, которые подходят вашему проекту.

Хочу положить в события трассировок только заданные мной параметры, а не весь лог (структурные события)

Если использовать стандартный способ переноса логов в события трассы, то в них будут попадать само сообщение лога, его свойства и остальные дополнительные параметры, такие как уровень логирования и контекст логирования. В трассах выглядит следующим образом:

Not Structured Logs

Если требуется, чтобы в событиях трассы попадали только параметры без дублирования их в сообщении, то можно использовать структурные события. Они позволяют записать события в виде название события и его параметров. Пример:

Not Structured Logs

Чтобы заработали структурные события, нужно подключить StructuredActivityEventBuilder:

.UseSerilog((context, configuration) => configuration
    .WriteToOpenTelemetry(activityEventBuilder: StructuredActivityEventBuilder.Instance)

После этого можно создавать структурные события с помощью логирования по конвенции или вспомогательного метода.

Логирование структурных событий по конвенции

Для этого в логах должно быть свойство TraceEventName, которое будет использоваться как название события в трассе:

_logger.LogInformation("{TraceEventName} Parameters: Company.Name = {Company_Name}; Id = {Id}", "MethodInput", "Byndyusoft", 10);

В логи сообщение попадёт как обычно, а событие трассы будет содержать только два параметра: Id и Company.Name. Имя события будет MethodInput. События будут выглядеть, как на картинке выше.

Логирование структурных событий через вспомогательный метод

Чтобы явно указать на использование структурных событий, можно воспользоваться вспомогательным методом LogStructuredActivityEvent, который находится в пакете Byndyusoft.Logging.OpenTelemetry.Abstractions.

Nuget Downloads

Чтобы создать событие трассировки, аналогичное картинке выше, нужно написать следующее:

var eventItems = new[]
{
    new StructuredActivityEventItem("Id", 10),
    new StructuredActivityEventItem("Company.Name", "Byndyusoft")
};
_logger.LogStructuredActivityEvent("MethodInput", eventItems);

Пример выше полностью аналогичен коду логирования по конвенции:

_logger.LogInformation("Structured Event {TraceEventName} Properties: Id = {Id}; Company.Name = {Company_Name}; ", "MethodInput", 10, "Byndyusoft");

По умолчанию структурные события попадают в логи с уровнем Information.

Обогащение дополнительными полями

Для обогащения информацией о параметрах окружения с наименованием BUILD_*, именем сервиса и версией сервиса можно воспользоваться библиотекой Byndyusoft.Telemetry.Logging.Serilog. Документация - тут.

About

Структурные логи в json формате

License:MIT License


Languages

Language:C# 100.0%