123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- <chapter xml:id="logger.h">
- <title><tt>__vic/logger.h</tt></title>
- <chapter xml:id="logger">
- <title><tt>logger</tt></title>
- <code-block lang="C++"><![CDATA[
- class logger : private non_copyable
- {
- public:
- enum class severity : unsigned char
- {
- trace,
- debug,
- info,
- notice,
- warning,
- error,
- fatal
- };
- using severity_t = severity; // use this alias as a type name
- struct output
- {
- virtual void publish_record(severity_t , const char * , size_t ) = 0;
- protected:
- ~output() = default;
- };
- class settings_t
- {
- struct output &output() const;
- severity_t level() const;
- };
- class record;
- explicit logger(output &out, severity_t = severity::info);
- explicit logger(settings_t s);
- ~logger();
- severity_t level() const;
- void level(severity_t new_level);
- settings_t settings() const;
- output &reset_output(output &out);
- output &get_output();
- const output &get_output() const;
- static constexpr size_t min_buffer_size = ...;
- void shrink_buffer(size_t limit);
- void message(severity_t severity, const char *msg, size_t msg_len);
- #if __cpp_lib_string_view // C++17
- void message(severity_t severity, std::string_view msg);
- void trace(std::string_view msg);
- void debug(std::string_view msg);
- void info(std::string_view msg);
- void notice(std::string_view msg);
- void warning(std::string_view msg);
- void error(std::string_view msg);
- void fatal(std::string_view msg);
- #else // until C++17
- void message(severity_t severity, const char *msg);
- void message(severity_t severity, const std::string &msg);
- void trace(const char *msg);
- void debug(const char *msg);
- void info(const char *msg);
- void notice(const char *msg);
- void warning(const char *msg);
- void error(const char *msg);
- void fatal(const char *msg);
- void trace(const std::string &msg);
- void debug(const std::string &msg);
- void info(const std::string &msg);
- void notice(const std::string &msg);
- void warning(const std::string &msg);
- void error(const std::string &msg);
- void fatal(const std::string &msg);
- #endif
- record trace();
- record debug();
- record info();
- record notice();
- record warning();
- record error();
- record fatal();
- bool trace_visible() const;
- bool debug_visible() const;
- bool info_visible() const;
- bool notice_visible() const;
- bool warning_visible() const;
- bool error_visible() const;
- bool fatal_visible() const;
- };
- class logger::record
- {
- public:
- record(logger &log, severity_t sev);
- ~record();
- record append(const char *str, size_t str_len);
- template<class T> record operator<<(const T &v);
- };
- const char *to_string(logger::severity_t s);
- #if __cpp_lib_string_view // C++17
- constexpr std::string_view to_string_view(logger::severity s);
- #endif
- ]]></code-block>
- <p>Front-end логгера. Реализует построение записей с помощью оператора
- <tt><<</tt>, подобно стандартной библиотеке потоков <tt>iostream</tt>.
- Каждая запись лога имеет назначенный приоритет. Логгер может фильтровать вывод
- записей по этому приоритету. Предопределены 6 уровней приоритета (в порядке
- возрастания):</p>
- <list style="numbered">
- <item>TRACE - подробная отладка,</item>
- <item>DEBUG - отладка,</item>
- <item>INFO - информационное сообщение,</item>
- <item>NOTICE - нормальное, но важное событие,</item>
- <item>WARNING - незначительная ошибка или подозрительная ситуация,</item>
- <item>ERROR - серьёзная ошибка, но приложение может продолжать
- работу,</item>
- <item>FATAL - критическая ошибка, приложение не может продолжить
- выполнение.</item>
- </list>
- <p>INFO является уровнем логирования по умолчанию. Если сообщение (запись)
- имеет приоритет ниже текущего уровня логирования, то оно игнорируется и никуда
- не выводится.</p>
- <p>Для создания сообщений с нужным приоритетом предоставляется набор одноимённых
- функций. Например, <tt>info()</tt> для сообщений INFO. Также есть универсальная
- функция <tt>message()</tt>, в которой приоритет задаётся параметром, но, обычно,
- следует использовать специфичные функции.</p>
- <p>Существует 2 способа создания сообщений. Первый прост и обычен:</p>
- <code-block lang="C++">
- log.trace("Trace message");
- log.debug("Debug message");
- log.info("Info message");
- log.notice("Notice");
- log.warning("Warning");
- log.error("Recoverable error");
- log.fatal("Fatal error");
- </code-block>
- <p>Второй немного более сложен, но предоставляет гораздо большие возможности:</p>
- <code-block lang="C++"><![CDATA[
- log.error() << "Cannot open file " << filename << '!';
- log.warning() << "Loop iteration no " << i;
- ]]></code-block>
- <p>Вызов функции без параметров создаёт объект типа <tt>logger::record</tt> с
- соответствующим приоритетом. Теперь в него можно писать сообщение с
- использованием оператора <tt><<</tt>. Сформированная запись будет
- выведена в лог по завершении вычисления «полного выражения» (термин из
- Стандарта)</p>
- <p>Если сформировать запись лога сложно или невозможно одним выражением, то
- следует явно создать объект <tt>logger::record</tt> и писать в него. Запись
- будет выведена с лог при вызове деструктора данного объекта:</p>
- <code-block lang="C++"><![CDATA[
- {
- logger::record rec = log.info(); // Начало формирования записи
- rec << "List elements: ";
- for(auto el : list) rec << el << ", ";
- // Сформированная запись попадёт в лог при выходе из блока
- }
- ]]></code-block>
- <note>В целях повышения эффективности используйте обычную функциональную запись,
- если строка уже готова для вывода:</note>
- <code-block lang="C++"><![CDATA[
- log.info("Message");
- // а не
- log.info() << "Message";
- ]]></code-block>
- <p>Вывод записей с приоритетами DEBUG и TRACE обычно отключен в нормальных
- условиях. Такие записи хоть и не попадут в лог, но время на их форматирование
- всё равно будет тратиться. Поэтому перед попыткой сформировать какую-нибудь
- отладочную запись с помощью операторов <tt><<</tt> проверьте, включена ли
- отладка, с помощью вызова <tt>debug_visible()</tt> или <tt>trace_visible()</tt>:
- </p>
- <code-block lang="C++"><![CDATA[
- if(log.debug_visible())
- log.debug() << ...; // формируем запись
- ]]></code-block>
- <p>Это не относится к обычным вызовам <tt>debug(msg)</tt> и <tt>trace(msg)</tt>,
- которым передаётся уже готовая к выводу строка, и никакого дополнительного
- форматирования не требуется.</p>
- <p>Для использования <tt>logger</tt> нужно реализовать абстрактный базовый класс
- <tt>logger::output</tt> (определить <tt>publish_record()</tt>). Реализация
- должна вывести куда-то сформированную запись, например, в файл или БД.
- <tt>output</tt>, переданный в <tt>logger</tt> при конструировании, впоследствии
- можно заменить с помощью вызова <tt>reset_output()</tt>.</p>
- <section><title>Члены класса</title>
- <synopsis>
- <prototype>severity::trace</prototype>
- <prototype>severity::debug</prototype>
- <prototype>severity::info</prototype>
- <prototype>severity::notice</prototype>
- <prototype>severity::warning</prototype>
- <prototype>severity::error</prototype>
- <prototype>severity::fatal</prototype>
- <p>Константы приоритетов и уровней логирования. Данная форма используется как в
- режиме C++11, так и в C++98.</p>
- </synopsis>
- <synopsis>
- <prototype>typename severity_t</prototype>
- <p>Используйте данный идентификатор, если коду требуется совместимость с режимом
- C++98. Начиная с C++11 это просто синоним <tt>severity</tt>.</p>
- </synopsis>
- <synopsis>
- <prototype>class output</prototype>
- <p>Интерфейс back-end'а логирования.</p>
- </synopsis>
- <synopsis>
- <prototype>void output::publish_record(severity_t sev, const char *buf, size_t buf_len)</prototype>
- <p>Реализация этой чисто виртуальной функции должна вывести содержимое
- <tt>buf</tt> длиной <tt>buf_len</tt> в лог как одну запись. Функция вызывается
- только когда переданный <tt>sev >= level()</tt>. Реализация может полагаться на
- это предусловие.</p>
- </synopsis>
- <synopsis>
- <prototype>class settings_t</prototype>
- <p>Хранит настройки логгера: уровень логирования и ссылку на вывод
- (<tt>level()</tt> + <tt>get_output()</tt>).</p>
- </synopsis>
- <synopsis>
- <prototype>explicit logger(output &out, severity_t level = severity::info)</prototype>
- <p>Создаёт логгер с данным выводом и уровнем логирования. Время жизни объекта,
- на который ссылается <tt>out</tt>, должно превосходить время жизни логгера!</p>
- <postcondition><tt>this->level() == level && &this->get_output() == &out</tt></postcondition>
- </synopsis>
- <synopsis>
- <prototype>explicit logger(settings_t s)</prototype>
- <p>Создаёт логгер с указанными настройками.</p>
- </synopsis>
- <synopsis>
- <prototype>severity_t level() const</prototype>
- <p>Возвращает текущий уровень логирования.</p>
- </synopsis>
- <synopsis>
- <prototype>void level(severity_t new_level)</prototype>
- <p>Устанавливает уровень логирования.</p>
- <postcondition><tt>level() == new_level</tt></postcondition>
- </synopsis>
- <synopsis>
- <prototype>settings_t settings() const</prototype>
- <p>Возвращает текущие настройки.</p>
- </synopsis>
- <synopsis>
- <prototype>output &reset_output(output &out)</prototype>
- <p>Устанавливает новый вывод и возвращает старый.</p>
- <postcondition><tt>&get_output() == &out</tt></postcondition>
- </synopsis>
- <synopsis>
- <prototype>output &get_output()</prototype>
- <prototype>const output &get_output() const</prototype>
- <p>Возвращает ссылку на текущий вывод.</p>
- </synopsis>
- <synopsis>
- <prototype>static constexpr size_t min_buffer_size</prototype>
- <p>Минимальный размер внутреннего буфера в байтах.</p>
- </synopsis>
- <synopsis>
- <prototype>void shrink_buffer(size_t limit)</prototype>
- <p>Устанавливает размер внутреннего буфера в <tt>min_buffer_size</tt>, если он
- превосходит <tt>limit</tt> байтов. Позволяет предотвратить бесконрольное
- разрастание используемой памяти при выводе записей большого размера.</p>
- </synopsis>
- <synopsis>
- <prototype>void message(severity_t severity, const char *msg, size_t msg_len)</prototype>
- <prototype>void message(severity_t severity, std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void message(severity_t severity, const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void message(severity_t severity, const std::string &msg) <sign>until C++17</sign></prototype>
- <p>Выводит сообщение с заданным приоритетом.</p>
- </synopsis>
- <synopsis>
- <prototype>void trace(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void trace(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void trace(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void debug(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void debug(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void debug(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void info(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void info(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void info(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void notice(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void notice(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void notice(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void warning(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void warning(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void warning(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void error(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void error(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void error(const std::string &msg) <sign>until C++17</sign></prototype>
- <prototype>void fatal(std::string_view msg) <sign>C++17</sign></prototype>
- <prototype>void fatal(const char *msg) <sign>until C++17</sign></prototype>
- <prototype>void fatal(const std::string &msg) <sign>until C++17</sign></prototype>
- <p>Выводит сообщение с соответствующим приоритетом.</p>
- </synopsis>
- <synopsis>
- <prototype>logger::record trace()</prototype>
- <prototype>logger::record debug()</prototype>
- <prototype>logger::record info()</prototype>
- <prototype>logger::record notice()</prototype>
- <prototype>logger::record warning()</prototype>
- <prototype>logger::record error()</prototype>
- <prototype>logger::record fatal()</prototype>
- <p>Создаёт новую запись c соответствующим приоритетом и позволяет писать в неё
- части сообщения с помощью оператора <tt><<</tt>.</p>
- </synopsis>
- <synopsis>
- <prototype>bool trace_visible() const</prototype>
- <prototype>bool debug_visible() const</prototype>
- <prototype>bool info_visible() const</prototype>
- <prototype>bool notice_visible() const</prototype>
- <prototype>bool warning_visible() const</prototype>
- <prototype>bool error_visible() const</prototype>
- <prototype>bool fatal_visible() const</prototype>
- <p>Возвращает <tt>true</tt>, если запись с указанным уровнем логирования будет
- выведена в лог при текущих настройках. Использование данных функций позволяет
- исключить форматирование сообщений, которые всё равно не попадут в лог.</p>
- </synopsis>
- <synopsis>
- <prototype>record::record(logger &log, severity_t sev)</prototype>
- <p>Создаёт запись лога с указанным приоритетом. Обычно вместо явного вызова
- данного конструктора следует использовать функции <tt>logger</tt>’а, вроде
- <tt>info()</tt> без параметров, для создания объекта.</p>
- </synopsis>
- <synopsis>
- <prototype>record::~record()</prototype>
- <p>Выводит сформированную запись в лог.</p>
- </synopsis>
- <synopsis>
- <prototype>record record::append(const char *str, size_t str_len)</prototype>
- <p>Добавляет строку к сообщению.</p>
- </synopsis>
- <synopsis>
- <prototype>template<class T> record record::operator<<(const T &v)</prototype>
- <p>Набор инсертеров для различных типов данных. Вызывают <tt>sb << v</tt>,
- где <tt>sb</tt> имеет тип <tt>__vic::string_buffer</tt>.</p>
- </synopsis>
- </section>
- <section><title>Свободные функции</title>
- <synopsis>
- <prototype>const char *to_string(logger::severity_t s)</prototype>
- <prototype>constexpr std::string_view to_string_view(logger::severity s) <sign>C++17</sign></prototype>
- <p>Преобразует приоритет записи лога в текстовое представление, которое можно,
- например, вывести в лог. Пример: для <tt>severity::debug</tt> возвращается
- "<tt>DEBUG</tt>" и т.п.</p>
- </synopsis>
- </section>
- <section><title>Пример</title>
- <code-block lang="C++"><![CDATA[
- /////////////////////////////////////////////////////////////////////////////
- // Вывод сообщений в std::clog с указанием приоритета
- class coutput : public __vic::logger::output
- {
- public:
- void publish_record(__vic::logger::severity_t s,
- const char *rec, size_t rec_n)
- {
- std::clog << to_string(s) << ": ";
- std::clog.write(rec, rec_n) << std::endl;
- }
- };
- /////////////////////////////////////////////////////////////////////////////
- int main()
- {
- coutput log_output:
- __vic::logger log(log_output, __vic::logger::severity::debug);
- log.info("Application is started");
- for(int i = 0; i < 5; i++)
- log.debug() << "Loop i = " << i;
- log.warning("Application end");
- }
- ]]></code-block>
- <p>Результат:</p>
- <tty>
- INFO: Application is started
- DEBUG: Loop i = 0
- DEBUG: Loop i = 1
- DEBUG: Loop i = 2
- DEBUG: Loop i = 3
- DEBUG: Loop i = 4
- WARNING: Application end
- </tty>
- </section>
- </chapter>
- </chapter>
|