Comments 29
… и именно поэтому последующая смена одного или другого обходится дорого.
Но согласитесь глупо выбирать контейнер или логгер и не пользоваться его фичами, за которые его же и выбирали
Глупо. А вот не дать этим фичам просочиться в клиентский код — уже не глупо.
И эти компоненты обычно не меняются часто, если вообще меняются.
Они не меняются часто именно потому, что их дорого поменять. Я сейчас как раз думаю, как бы так изолировать код от логгера, чтобы в случае необходимости логгер сменить.
По второму пункту думал примерно так же как и вы. Абстракция над логгером прожила 3 года. Потом перешли на Serilog и она превратилась в тыкву :)
Что вы подразумеваете под просочиться и под клиентский код
Я имею в виду, что когда у меня в системе есть 100500 мест, использующих логгирование, все они начинают зависеть от (например) Serilog.ILogger
. И в этот момент выбрасывание серилога начинает стоить денег.
При том что в принципе даже абстракция вас не спасет, так как Serilog использует свое форматирование. Тоесть даже если прокинуть MyFanceAbstractLogger и написать,
Logger.Info("Something went wrong during {@Something} because user is {Reason}", Something, Reason)
то вы все равно упретесь в переписывание всех сообщений. Опять вас абстракция не спасет :)
Сейчас я использую абстракции вида LibLog для распространяемых библиотек.
Серверный код просто использует специфичные для Serilog врапперы для удобного DI типа ILogger.
А есть ли смысл выбрасывать? Я за 12 лет менял логгер 3 раза. 3!
Ну вот, раз в четыре года в среднем. У меня, кстати, приблизительно та же статистика. А на большом приложении это правда дорого.
При том что в принципе даже абстракция вас не спасет, так как Serilog использует свое форматирование.
Ну так абстракция форматирование тоже должна абстрагировать.
Я, заметим, не говорю, что абстракция всех спасет. Просто ее отсутствие может представлять проблему. Типичный компромис (который я для себя на конкретном текущем проекте пока сбалансировать не могу).
Форматирование очень тяжело абстрагировать, так как старое поколение (Log4Net, NLog2) не являются структурными логгерами, а SLAB — тихий ужас :)
Я свой проект веде уже 4 года и пришел к выводу, что уменьшение количества абстракций положительно сказывается на проекте :D
Я свой проект веде уже 4 года и пришел к выводу, что уменьшение количества абстракций положительно сказывается на проекте
… если вам так повезло, что вы не собираетесь никогда менять уже абстрагированное.
Можно с этого места поподробнее? Я вижу 3 варианта:
1) писать Logger.Info(«Something went wrong during {@Something} because user is {Reason}», Something, Reason), то есть использовать синтаксис того, что под руками
2) писать Logger.Info(«Something went wrong during {0} because user is {1}», Something, Reason), как более «стандартное», с оверхедом и надеждой, что следующий логгер будет совместим.
3) писать Logger.Info(«Something went wrong during %%0%% because user is %%1%%», Something, Reason) — придумать свой синтаксис, который потом поддерживать в каждом логгере.
При этом первый подход типа не абстрагирует, но чиниться таким же враппером, какой у 2 и 3. А второй вызывает желание форкнуть логгер и выпилить странный синтаксис, вред от которого превышает пользу.
Вы каким путём идёте?
Мы пока не идем никаким путем, мы размышляем. Но одна из веток размышления выглядит как "взять семантически подходящий синтаксис (Serilog-овский выглядит подходящим), затем адаптировать его для тех, кто его не поддерживает".
Мы написали абстракции над серилогом только для того чтобы иметь возможность настраивать декораторы для каждого типа сообщения. Какие-то события подробнее логгируются, кто-то добавляет специфические Enrichers при вызове. Есть некоторые костыли в прокидывании динамически формируемого набора Enrichers с доступом к контексту класа, передаем Func внутрь вызова логера. А так да, согласен, структурный логгер это то что нужно, после всех "старичков"...
- да, часто вагон и маленькая тележка БЛ.
- более чем в половине случаев работа с унаследованными системами, нужен какой-то repair-toolkit для рефакторинга
- необходимость в быстром прототипировании
пример
Отличительной особенностью данного подхода от реализации паттерна «декоратор» средствами ООП является возможность добавлять вспомогательную функциональность к любым типам без необходимости создавать наследников. Подход также решает проблему множественного наследования.
А при чем тут множественное наследование?
Разумное АОП для поклонников IOC-контейнеров