Comments 11
Спасибо за интересное и полезное решение. Даже один IsEnabled уже стоит того, чтобы использовать подобный подход и не вычислять строку не зависимо от уровня логгирования. Или я ошибаясь и библиотеках логгирования тоже есть подобный механизм позволяющий не вычислять интерполяционные строки для не соответсвующего уровня?
Обычно, где-то внутри ILogger идёт проверка if(IsEnabled(level)), и если не включён уровень - ничего не вычисляется, и не логируется.
Например вот: https://source.dot.net/#Microsoft.Extensions.Logging.Console/ConsoleLogger.cs,38
При работе с FormattableString аналогично, тк она в принципе никогда в настоящую строку не собирается.
Да, внутри Logger проверка само-собой есть. Вот только, если мы даже будем использовать обычный метод ILog.LogInformation(string template, param object[] args)
, то массив args
все равно будет аллоцирован, ведь проверка - она уже где-то там внутри.
Если же мы с этим же методом попробуем использовать интерполированную строку, то получим по факту вызов вида LogInformation(string.Format(template, args), Array.Empty<string>())
. А значит выполним сначала весьма дорогой вызов string.Format
, а потом уже, внутри, просто выкинем его результат на свалку.
Так что для высокопроизводительного логирования проверять вручную IsEnabled все равно может иметь смысл. И те самые новые source generators это тоже делают, равно как и предложенный мной подход.
А есть бенчмарки?
Вроде ещё до C# 10 можно было сделать структурное логирование на интерполированных строках, при помощи FormattableString:
https://github.com/Drizin/InterpolatedLogging
Интересно было бы увидеть сравнение в производительности.
А ещё есть вариант на source generators, но это немного не то: https://github.com/dotnet/designs/blob/main/accepted/2021/logging-generator.md
У структурного логирования есть еще один, не самый очевидный, побочный эффект:
Если хранилище логов индексирует все свойства сообщения (как это, например, делает Elasticsearch с настройками по-умолчанию), то увеличение количества структурированных сообщений будет сказываться на производительности хранилища.
Andrew Lock тоже писал про использование source generators в логгировании https://andrewlock.net/exploring-dotnet-6-part-8-improving-logging-performance-with-source-generators/
В последние годы все большую популярность у разработчиков завоевывает структурное логирование.
Меня удивляет, что это происходит только последние годы, хотя самому понятию (и Serilog) уже едва не 10 лет. Даже если не использовать структурное хранилище, а просто сливать в текстовые логи - как минимум логирование упрощается. А еще можно использовать scopes, в них тоже есть destructuring. Вот про InterpolatedStringHandler не знал, спасибо, увы, мы пока еще на VS 2019.
Структурное логирование и интерполированные строки в C# 10