Часть 2: Как оптимизировать логирование в .NET: советы и примеры
Сравниваем производительность стандартного логирования и LoggerMessage. Узнайте, как ускорить .NET-приложение.
1К открытий8К показов
Это продолжение нашей серии о логировании в .NET. В первой части мы разобрали, как стандартные методы могут замедлять приложение, и познакомились с LoggerMessage. Теперь пора перейти к практике: мы покажем реальные тесты производительности и расскажем, как автоматизировать переход на эффективное логирование.
Сравнение производительности: стандартное логирование против LoggerMessage
Чтобы сравнить производительность LoggerMessage и методов расширения интерфейса, мы решили написать программу, подсчитывающую сумму четных элементов массива. Предварительно добавили несколько новых методов для записи дополнительных событий. Вот объявления для новых событий:
Обновленный код приложения:
Здесь строки вызова методов расширения ILogger закомментированы. А вызовы наших методов, построенных через механизм LoggerMessage, раскомментированы. Таким образом, можно прогнать программу, используя ILogger, либо, наоборот, LoggerMessage
При использовании механизма LoggerMessage затраты на выполнение методов логирования, которые мы вызывали в цикле (LogIterationStart и LogIterationComplete), составили 0,58% и 0,52% процессорного времени от общих затрат.
При использовании методов расширения ILogger затраты на выполнение метода ILogger.LogInformation составили 35,12% от общих затрат.
Да, можно заметить, что в затраты попали вызовы метода LoggerMessage.Define. Но заметим, что эти методы выполняются один раз на старте приложения. И если наше приложение серверное (долгоживущее), то затраты станут ничтожными по отношению к общим затратам за всё время жизни приложения.
При использовании же методов расширения ILogger затраты на выполнение будут расти, создавая нагрузку как на процессор, так и на память.
AutoLoggerMessage: как легко перейти на высокопроизводительное логирование
Мы рассмотрели два способа типизированных методов для ILogger. LoggerMessageAttribute упрощает процесс, но перевод готового проекта всё равно сложный.
К счастью, есть nuget-пакет, который умеет преобразовывать методы расширения ILogger.Log* из пространства имен Microsoft.Extensions.Logging в строго типизированные методы LoggerMessage.
Чтобы воспользоваться этим пакетом, нужно выполнить два простых шага:
Добавить в проект nuget-пакет stbychkov.AutoLoggerMessage
Это можно сделать либо через консоль с помощью инструмента Nuget package Manager, либо добавив ссылку на пакет в файл проекта.
Команда консоли Nuget Package Manager:
Install-Package stbychkov.AutoLoggerMessage
Добавление пакета с помощью утилиты dotnet:
dotnet add package stbychkov.AutoLoggerMessage
Разрешить перехватчики для генерации исходного кода
Для тестирования этого пакета мы создали отдельный проект консольного приложения и подключили в него указанный nuget-пакет. Далее добавили в модуль Program.cs пару строк с вызовами ILogger.LogInformation:
Если попытаться перейти к реализации метода LogInformation с помощью команды Go To Implementation, мы увидим, что попали не в метод расширения класса LoggerExtensions, а в строго типизированный метод в классе GenericLoggerExtensions:
Для первого вызова, где передана только строка сообщения, будет вызван этот метод:
Для второго вызова, где передан параметр типа TimeSpan, будет вызван следующий метод:
Как видите, второй метод имеет обобщенный параметр.
Можно заметить, что внутри есть вызовы LoggerExtensions, которые не строго типизированы. Это нужно, поскольку во время компиляции вложенный вызов logger.Log должен быть заменен сгенерированным кодом, который в итоге будет вызывать подходящий строго типизированный метод расширения класса LoggerMessageExtensions.
Сборка проекта как в MS Visual Studio 2022, так и в JetBrains Rider, прошла без проблем. Так, если в IDE Rider запустить отладку проекта, предварительно поставив точку останова на вызове одного из методов logger.LogInformation(), то можно увидеть код, который будет вызван. Для этого выберите команду Step Into:
Мы можем видеть, что дальше управление передается сгенерированному методу с типизированными параметрами:
Этот код построен на LoggerMessage.Define – следующим шагом мы попадаем в один из методов расширения класса LoggerMessage:
Таким образом, пакет AutoLoggerMessage позволяет перейти на высокопроизводительное логирование без ручного изменения исходного кода.
Правда, у AutoLoggerMessage есть ограничения:
- Поддерживается с .NET 8.0.8 и выше;
- В
ILogger.Log*()может быть не более 6 параметров, иначе параметры передаются как массив object, то есть вызывается упаковка значимых типов.
Какой подход к логированию выбрать
Подводя итоги, приведем плюсы и минусы каждого подхода.
ILogger и методы расширения Log*() класса LoggerExtensions
+ Если используете ILogger из коробки, вам не нужно добавлять статический класс с объявлениями методов расширения.
- Так как дополнительные параметры передаются как object, то выполняется упаковка значимых типов.
- Разбор шаблонов сообщений выполняется при каждом вызове, что может увеличить нагрузку.
- Код загрязняется текстом шаблонов сообщений.
- Поскольку сообщения добавляются по мере необходимости прямо в код классов, то возможно дублирование сообщений.
LoggerMessage и строго типизированные методы класса LoggerMessageExtensions
+ Не загрязняют код шаблонами сообщений.
+ Методы расширений имеют строго типизированные параметры — это исключает упаковку значимых типов.
+ Шаблоны сообщений разбираются один раз во время старта приложения.
+ Все сообщения хранятся в одном статическом классе, которым проще управлять.
- Придется добавить статический класс и статический метод для каждого вновь добавляемого сообщения.
В целом, подход с LoggerMessage имеет больше преимуществ. А с пакетом AutoLoggerMessage можно легко перевести проекты на более производительное логирование.
Исходный код можно посмотреть на bitbucket. А узнать больше информации про .NET — в нашем канале.
Полезные ссылки
Logging in C# - .NET | Microsoft Learn
High-performance logging - .NET | Microsoft Learn
Compile-time logging source generation - .NET | Microsoft Learn
1К открытий8К показов










