В проект, которому сейчас помогаю, коллеги подключили spdlog. В частности, потребовался функционал автоматической ротации log-файлов. Но, к сожалению, не без сложностей т.к. штатный rotating_file_sink не подошел. Генерация имен новых log-файлов в нем захардкожена намертво, а требовалось добавлять в каждое имя специфическую для проекта информацию. Пришлось делать свой тип sink-а.
В rotating_file_sink за формирование имени очередного файла отвечает статический метод calc_filename, вызов которого зашит в код rotating_file_sink. Поэтому просто так отнаследоваться от rotating_file_sink и переопределить calc_filename в собственном производном классе нельзя.
Пришлось коллегам копипастить код rotating_file_sink к себе в проект и дорабатывать его напильником в нужных местах.
Внезапно™ вспомнилось, что когда-то давно я сам засылал PR в spdlog, который даже был принят, но забылось что именно я там предлагал делать. А оказалось, что предлагал как раз решение подобной проблемы. Но только для daily_file_sink.
Суть в том, чтобы шаблон класса daily_file_sink требовал не один параметр шаблона, а два. Вторым параметром является тип, который предоставляет статический метод calc_filename. Тем самым calc_filename выносится из самого класса sink-а в параметр шаблона. И если нам нужны собственные правила генерации имен новых log-файлов, то мы всего лишь делаем простой класс с публичным статическим методом calc_filename, после чего подсовываем этот класс в параметр шаблона daily_file_sink. Что гораздо проще и надежнее, чем брать за основу код существующего sink-класса и переделывать его под себя.
Удивительно то, что хотя я заслал это изменение девять лет назад, этот подход с дополнительным параметром шаблона почему-то не применяется для rotating_file_sink. Хотя используется, например, в hourly_file_sink. Такое ощущение, что соответствующий PR никто не присылал, а автор spdlog не стал переделывать старую реализацию rotating_file_sink.
Думаю, что если бы я готовил подобный PR сейчас, то постарался бы обойти одну небольшую проблемку, которая есть в параметре FileNameCalc. Т.к. метод calc_filename у FileNameCalc должен быть статическим, то мы имеем дело со stateless-генерацией имен файлов. Что OK в большинстве случаев, но не всегда. Иногда может быть нужно, чтобы calc_filename сохранял какую-то информацию для использования в следующем вызове. Но сохранять ее негде. Поэтому сейчас бы я думал в сторону того, чтобы поддерживалась stateful-генерация имен.
В C++20 это вообще бы не представляло проблемы:
template <typename Mutex, typename FileNameCalc = daily_filename_calculator>
class daily_file_sink final : public base_sink<Mutex> {
[[no_unique_address]]
FileNameCalc _filеNameCalc;
...
public:
Если фактический тип FileNameCalc пуст, то _fileNameCalc не увеличивал бы размер daily_file_sink.
Но в более старых версиях C++ пришлось бы наследоваться от FileNameCalc дабы воспользоваться empty base optimization. Что не так очевидно и красиво.
Плюс еще нужно было бы предусматривать для sink-ов конструкторы, которые могли бы получать начальные значения для _fileNameCalc...
В общем, иногда кастомные stateful-генераторы имен могли бы быть полезными. Но вот во что бы вылилась их поддержка в коде spdlog? И стоило бы оно того? Хорошие вопросы, ответов на которые у меня нет.
Комментариев нет:
Отправить комментарий