Вдохновившись публикацией «Logger с функциями-членами, которых нет», решил выдать на всеобщее обозрение свой мета-велосипед для рефлекшена, которым вполне успешно пользуюсь, и не только для логгирования. Но начнем всё же с простого логгирования, продолжая вышеупомянутую публикацию.
При реализации логгирования, задачи для себя были поставлены следующие:
- Решить задачу на «мета-уровне», чтобы быть отвязанным от конечной реализации
- Фронтенд апи для логгирования должен быть простым и прозрачным
- Иметь возможность выключать ненужные уровни логгирования на этапе компиляции одной константой; например: все что выше LOG_NOTICE не должно попасть в результирующий бинари
Фронтенд выглядит так:
1. В конструкторе CConnection мы логгируем:
TestLog::Log<LOG_NOTICE>() << *this << "connection created";
2. Где CConnection унаследован от
public TLogHeader<'c', CConnection>
3.Который, используя CRTP, знает, что в CConnection есть такое:
using this_t = CConnection;
int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>;
std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>;
char m_state; using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>;
using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>;
3. И превращает эти данные в строчку лога:
c:23:test_conn 1:a:connection created
Где через двоеточие перечислены: с — первый параметр шаблона TLogHeader, и далее значения m_id, m_name, m_state
В моем случае все это дальше пишется в rsyslog и там разбирается в соответствующие поля для MongoDB (в зависимости от типа заголовка, т.е. первый параметр до двоеточия).
Сейчас этот подход у меня в продакшене на высоконагруженной системе, так что любые конструктивные камни будут в пику, или лучше под кат. А если лень, то вот работающий пример на http://coliru.stacked-crooked.com/ т.к. по катом кода на 250 строк, но очень много букв в описании.
Читать полностью »