Почему в журнале не используется интерполяция строк - PullRequest
0 голосов
/ 06 сентября 2018

Я следил Вход в ASP.NET Core , который работает просто отлично.

У меня вопрос по этой строке

_logger.LogWarning(LoggingEvents.GetItemNotFound, "GetById({ID}) NOT FOUND", id);

Мне интересно, почему они не используют $ - интерполяция строк ?

_logger.LogWarning(LoggingEvents.GetItemNotFound, $"GetById({ID}) NOT FOUND");

Почему расширение LogWarning имеет параметр params object[] args?

Какой момент, когда вы можете просто отправить все в строковое сообщение.

Полагаю, для этого есть причина, но я нигде не смог найти объяснения. Мне интересно, какой метод я должен использовать для правильной регистрации в .net core.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Я подозреваю, что вопрос можно перефразировать следующим образом:

Почему они не предоставляют перегрузки, которые принимают FormattableString для передачи шаблонов и параметров сообщений с использованием синтаксиса строковой интерполяции, как это делает EF Core для параметризованных запросов?

Я бы сказал, что они правильно поняли. На данный момент использование FormattableString предлагает минимальные преимущества, но создает лот путаницы.

Я только что обнаружил, что Автор Serilog объясняет, почему это не такая хорошая идея , хотя библиотека семантической регистрации выглядит естественным образом для этого сценария

Семантическое ведение журнала

Можно утверждать, что FormattableString будет отличным дополнением к библиотекам семантической регистрации, таким как Serilog. В этом случае интерполированная строка действительно теряет важную информацию.

Звонок

Log.Information("Logged in {UserId}", loggedInUserId);

Не будет просто записывать строку на основе шаблона, он будет хранить имена и значения параметров и предоставлять их фильтрам и целям. Не было бы замечательно получить тот же результат с:

Log.Information($"Logged in {loggedInUserId}");

Автор Серилога так не считает и объясняет, что:

  1. Хорошее имя переменной не обязательно является хорошим именем свойства
  2. Отверстия не всегда имеют очевидные имена, например Log.Information($"Enabling categories {new[]{1, 2, 3}}");

и приходит к выводу, что

Строковая интерполяция - отличная функция, которую я давно ждал в C #. Идея предоставления прямой поддержки Serilog очень интересна и заслуживает изучения, но я все больше убеждаюсь, что в этом нет необходимости.

Интерполяция удобна, когда она сохраняет код СУХОЙ, удаляя лишний беспорядок {0} и {1} и предотвращая несоответствия параметров.

В случае с Serilog я считаю неправильным считать имена свойств, такие как {UserId}, как избыточные; в хорошо реализованной стратегии ведения журнала они являются невероятно важной частью картины, которая заслуживает их собственного рассмотрения. Вы не позволите именам переменных определять имена таблиц и столбцов в реляционной базе данных - здесь рассматривается тот же компромисс.

Исходное объяснение

На самом деле это одна из самых противоречивых возможностей EF Core, и она может легко привести к тем проблемам с SQL-инъекцией и преобразованием, которых нужно избегать с помощью параметров.

Этот звонок:

string city = "London";
var londonCustomers = context.Customers
    .FromSql($"SELECT * FROM Customers WHERE City = {city}");

вызывает FromSql(FormattableString) и создает параметризованный запрос:

SELECT * FROM Customers WHERE City = @p0

И передать London в качестве значения параметра.

С другой стороны это:

string city = "London";
var query=$"SELECT * FROM Customers WHERE City = {city}";
var londonCustomers = context.Customers.FromSql(query);

вызывает FromSql(string) и генерирует:

SELECT * FROM Customers WHERE City = London

Что неверно. Слишком часто можно попасть в эту ловушку, даже если вы действительно знаете о риске.

Это совсем не помогает, если у вас уже есть предопределенные запросы или сообщения. Такое использование гораздо чаще встречается в журналах, где вы (должны) использовать определенные шаблоны сообщений, определенные в хорошо известных местах, вместо того, чтобы разбрасывать похожие строки в каждом месте журнала.

Можно утверждать, что это добавление сделало EF Core 2.0 несколько безопаснее , потому что люди уже начали использовать интерполяцию строк в EF Core 1.0, что приводило к неверным запросам. Добавив перегрузку FormattableString, команда EF Core смогла смягчить сценарий , упрощая случайное возникновение другой проблемы.

На данный момент разработчики лесозаготовок решили избежать этой путаницы. Регистрация необработанной строки не имеет таких катастрофических последствий.

0 голосов
/ 06 сентября 2018

Как минимум две причины.

Во-первых, ведение журнала предшествует интерполяции строк, и Microsoft еще не изобрела машину времени. Строковая интерполяция была введена в C # 6 только в июле 2015 года, но методы ведения журнала следуют той же схеме, что и в Microsoft.Build.Utilities, начиная с dotnet framework 2.0.

Во-вторых, производительность. Если используется строковая интерполяция и в качестве параметра передается строка, тогда интерполяция выполняется перед вызовом Log. Однако не каждый вызов Log приводит к тому, что что-то регистрируется - это зависит от конфигурации.

Если вы регистрируете что-то на уровне DEBUG и ваша текущая конфигурация предназначена для уровня INFORMATION, то для выполнения интерполяции строк - пустая трата времени, вы можете просто сказать «Спасибо, но нет, спасибо» и сразу вернуться ничего не делая с аргументами.

Расширение на второе, производительность Внутренне большинство логгеров выглядят в основном так:

void LogDebug(string Message, params object[] args){
    if(this.DebugEnabled){
        Log.Write(string.Format(Message,args)); 
    }
}

// 1 with parameters
LogDebug("GetById({ID}) NOT FOUND", id);
// 2 interpolated
LogDebug($"GetById({id}) NOT FOUND");

Таким образом, если отладка не включена, выполняется одна операция интерполяции меньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...