среда, 4 мая 2016 г.

[prog.c++11] Внес маленькую лепту в развитие spdlog

Есть для C++11 обалденно классная и удобная библиотека для логирования -- spdlog. Небольшая, header-only, под MIT-лицензией. При этом использует фичи еще одной очень хорошей C++ной библиотеки cppformat (он же fmtlib).

Но была в spdlog до недавнего времени небольшая закавыка: если использовать daily_file_sink, то имена суточных лог-файлов строились в виде basname_YYYY-MM-DD_hh-mm.ext. И все, больше никак. Т.е., если программа стартовала в 13:02, то будет создан лог-файл с именем basename_2016-05-02_13-02.ext. А если в 13:04 она рестартует, то рядом появится файл basename_2016-05-02_13-04.ext.

Мне было не очень удобно отлаживаться с таким подходом к логированию. Вместо того, чтобы один раз в отдельной консоли запустить tail -f basename_2016-05-02.ext и следить за тем, что пишется в лог, в том числе и при рестартах, приходится постоянно переключаться между логами.

В итоге я это дело в spdlog::sinks::daily_file_sink подправил и теперь для этого sink-а можно задать свой генератор имен лог-файлов. Делается это через еще один шаблонный параметр для класса daily_file_sink. По умолчанию этот параметр имеет значение spdlog::sinks::default_daily_file_name_calculator. Данный генератор имен суточных лог-файлов создает имена традиционным для spdlog способом -- с добавлением к дате часа и минуты, как показано выше.

Но вторым параметром в daily_file_sink можно подсунуть свой собственный генератор. Например, вот такой:

struct custom_daily_file_name_calculator
{
    static spdlog::filename_t calc_filename(const spdlog::filename_t& basename, const spdlog::filename_t& extension)
    {
        std::tm tm = spdlog::details::os::localtime();
        fmt::MemoryWriter w;
        w.write("{}{:04d}{:02d}{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, extension);
        return w.str();
    }
};

После чего создать logger посредством функции spdlog::create с указанием custom_daily_file_name_calculator:

using sink_type = spdlog::sinks::daily_file_sink< std::mutex, custom_daily_file_name_calculator>;
auto logger = spdlog::create<sink_type>("logger", basename, "log"00true);

И у вас будут суточные файлы с именами вида logger20160502.log.

Так же в spdlog::sinks добавлен тип dateonly_daily_file_name_calculator, который создает имена лог-файлов вида basename_YYYY-MM-DD.ext. Так что можно сразу брать готовый генератор имен и не писать свой.

Эти изменения уже приняты в spdlog, так что начиная с коммита ef9842c этой функциональностью можно пользоваться прям из коробки ;)