logger.h.xml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <chapter xml:id="logger.h">
  2. <title><tt>__vic/logger.h</tt></title>
  3. <chapter xml:id="logger">
  4. <title><tt>logger</tt></title>
  5. <code-block lang="C++"><![CDATA[
  6. class logger : private non_copyable
  7. {
  8. public:
  9. enum class severity : unsigned char
  10. {
  11. trace,
  12. debug,
  13. info,
  14. notice,
  15. warning,
  16. error,
  17. fatal
  18. };
  19. using severity_t = severity; // use this alias as a type name
  20. struct output
  21. {
  22. virtual void publish_record(severity_t , const char * , size_t ) = 0;
  23. protected:
  24. ~output() = default;
  25. };
  26. class settings_t
  27. {
  28. struct output &output() const;
  29. severity_t level() const;
  30. };
  31. class record;
  32. explicit logger(output &out, severity_t = severity::info);
  33. explicit logger(settings_t s);
  34. ~logger();
  35. severity_t level() const;
  36. void level(severity_t new_level);
  37. settings_t settings() const;
  38. output &reset_output(output &out);
  39. output &get_output();
  40. const output &get_output() const;
  41. static constexpr size_t min_buffer_size = ...;
  42. void shrink_buffer(size_t limit);
  43. void message(severity_t severity, const char *msg, size_t msg_len);
  44. #if __cpp_lib_string_view // C++17
  45. void message(severity_t severity, std::string_view msg);
  46. void trace(std::string_view msg);
  47. void debug(std::string_view msg);
  48. void info(std::string_view msg);
  49. void notice(std::string_view msg);
  50. void warning(std::string_view msg);
  51. void error(std::string_view msg);
  52. void fatal(std::string_view msg);
  53. #else // until C++17
  54. void message(severity_t severity, const char *msg);
  55. void message(severity_t severity, const std::string &msg);
  56. void trace(const char *msg);
  57. void debug(const char *msg);
  58. void info(const char *msg);
  59. void notice(const char *msg);
  60. void warning(const char *msg);
  61. void error(const char *msg);
  62. void fatal(const char *msg);
  63. void trace(const std::string &msg);
  64. void debug(const std::string &msg);
  65. void info(const std::string &msg);
  66. void notice(const std::string &msg);
  67. void warning(const std::string &msg);
  68. void error(const std::string &msg);
  69. void fatal(const std::string &msg);
  70. #endif
  71. #if __cpp_lib_format >= 202106L // C++20 + P2508
  72. template<class... Args>
  73. void format(severity_t s,
  74. std::format_string<Args...> fmt, Args&&... args);
  75. template<class Arg1, class... Args>
  76. void trace(
  77. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  78. template<class Arg1, class... Args>
  79. void debug(
  80. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  81. template<class Arg1, class... Args>
  82. void info(
  83. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  84. template<class Arg1, class... Args>
  85. void notice(
  86. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  87. template<class Arg1, class... Args>
  88. void warning(
  89. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  90. template<class Arg1, class... Args>
  91. void error(
  92. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  93. template<class Arg1, class... Args>
  94. void fatal(
  95. std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args);
  96. #endif
  97. record trace();
  98. record debug();
  99. record info();
  100. record notice();
  101. record warning();
  102. record error();
  103. record fatal();
  104. bool trace_visible() const;
  105. bool debug_visible() const;
  106. bool info_visible() const;
  107. bool notice_visible() const;
  108. bool warning_visible() const;
  109. bool error_visible() const;
  110. bool fatal_visible() const;
  111. };
  112. class logger::record
  113. {
  114. public:
  115. record(logger &log, severity_t sev);
  116. ~record();
  117. record append(const char *str, size_t str_len);
  118. template<class T> record operator<<(const T &v);
  119. };
  120. const char *to_string(logger::severity_t s);
  121. #if __cpp_lib_string_view // C++17
  122. constexpr std::string_view to_string_view(logger::severity s);
  123. #endif
  124. ]]></code-block>
  125. <p>Front-end логгера. Реализует построение записей с помощью оператора
  126. <tt>&lt;&lt;</tt>, подобно стандартной библиотеке потоков <tt>iostream</tt>.
  127. Каждая запись лога имеет назначенный приоритет. Логгер может фильтровать вывод
  128. записей по этому приоритету. Предопределены 6 уровней приоритета (в порядке
  129. возрастания):</p>
  130. <list style="numbered">
  131. <item>TRACE - подробная отладка,</item>
  132. <item>DEBUG - отладка,</item>
  133. <item>INFO - информационное сообщение,</item>
  134. <item>NOTICE - нормальное, но важное событие,</item>
  135. <item>WARNING - незначительная ошибка или подозрительная ситуация,</item>
  136. <item>ERROR - серьёзная ошибка, но приложение может продолжать
  137. работу,</item>
  138. <item>FATAL - критическая ошибка, приложение не может продолжить
  139. выполнение.</item>
  140. </list>
  141. <p>INFO является уровнем логирования по умолчанию. Если сообщение (запись)
  142. имеет приоритет ниже текущего уровня логирования, то оно игнорируется и никуда
  143. не выводится.</p>
  144. <p>Для создания сообщений с нужным приоритетом предоставляется набор одноимённых
  145. функций. Например, <tt>info()</tt> для сообщений INFO. Также есть универсальная
  146. функция <tt>message()</tt>, в которой приоритет задаётся параметром, но, обычно,
  147. следует использовать специфичные функции.</p>
  148. <p>Существует 2 способа создания сообщений. Первый прост и обычен:</p>
  149. <code-block lang="C++">
  150. log.trace("Trace message");
  151. log.debug("Debug message");
  152. log.info("Info message");
  153. log.notice("Notice");
  154. log.warning("Warning");
  155. log.error("Recoverable error");
  156. log.fatal("Fatal error");
  157. </code-block>
  158. <p>Второй немного более сложен, но предоставляет гораздо большие возможности:</p>
  159. <code-block lang="C++"><![CDATA[
  160. log.error() << "Cannot open file " << filename << '!';
  161. log.warning() << "Loop iteration no " << i;
  162. ]]></code-block>
  163. <p>Вызов функции без параметров создаёт объект типа <tt>logger::record</tt> с
  164. соответствующим приоритетом. Теперь в него можно писать сообщение с
  165. использованием оператора <tt>&lt;&lt;</tt>. Сформированная запись будет
  166. выведена в лог по завершении вычисления «полного выражения» (термин из
  167. Стандарта)</p>
  168. <p>Если сформировать запись лога сложно или невозможно одним выражением, то
  169. следует явно создать объект <tt>logger::record</tt> и писать в него. Запись
  170. будет выведена с лог при вызове деструктора данного объекта:</p>
  171. <code-block lang="C++"><![CDATA[
  172. {
  173. logger::record rec = log.info(); // Начало формирования записи
  174. rec << "List elements: ";
  175. for(auto el : list) rec << el << ", ";
  176. // Сформированная запись попадёт в лог при выходе из блока
  177. }
  178. ]]></code-block>
  179. <note>В целях повышения эффективности используйте обычную функциональную запись,
  180. если строка уже готова для вывода:</note>
  181. <code-block lang="C++"><![CDATA[
  182. log.info("Message");
  183. // а не
  184. log.info() << "Message";
  185. ]]></code-block>
  186. <p>Вывод записей с приоритетами DEBUG и TRACE обычно отключен в нормальных
  187. условиях. Такие записи хоть и не попадут в лог, но время на их форматирование
  188. всё равно будет тратиться. Поэтому перед попыткой сформировать какую-нибудь
  189. отладочную запись с помощью операторов <tt>&lt;&lt;</tt> проверьте, включена ли
  190. отладка, с помощью вызова <tt>debug_visible()</tt> или <tt>trace_visible()</tt>:
  191. </p>
  192. <code-block lang="C++"><![CDATA[
  193. if(log.debug_visible())
  194. log.debug() << ...; // формируем запись
  195. ]]></code-block>
  196. <p>Это не относится к обычным вызовам <tt>debug(msg)</tt> и <tt>trace(msg)</tt>,
  197. которым передаётся уже готовая к выводу строка, и никакого дополнительного
  198. форматирования не требуется.</p>
  199. <p>Для использования <tt>logger</tt> нужно реализовать абстрактный базовый класс
  200. <tt>logger::output</tt> (определить <tt>publish_record()</tt>). Реализация
  201. должна вывести куда-то сформированную запись, например, в файл или БД.
  202. <tt>output</tt>, переданный в <tt>logger</tt> при конструировании, впоследствии
  203. можно заменить с помощью вызова <tt>reset_output()</tt>.</p>
  204. <section><title>Члены класса</title>
  205. <synopsis>
  206. <prototype>severity::trace</prototype>
  207. <prototype>severity::debug</prototype>
  208. <prototype>severity::info</prototype>
  209. <prototype>severity::notice</prototype>
  210. <prototype>severity::warning</prototype>
  211. <prototype>severity::error</prototype>
  212. <prototype>severity::fatal</prototype>
  213. <p>Константы приоритетов и уровней логирования. Данная форма используется как в
  214. режиме C++11, так и в C++98.</p>
  215. </synopsis>
  216. <synopsis>
  217. <prototype>typename severity_t</prototype>
  218. <p>Используйте данный идентификатор, если коду требуется совместимость с режимом
  219. C++98. Начиная с C++11 это просто синоним <tt>severity</tt>.</p>
  220. </synopsis>
  221. <synopsis>
  222. <prototype>class output</prototype>
  223. <p>Интерфейс back-end'а логирования.</p>
  224. </synopsis>
  225. <synopsis>
  226. <prototype>void output::publish_record(severity_t sev, const char *buf, size_t buf_len)</prototype>
  227. <p>Реализация этой чисто виртуальной функции должна вывести содержимое
  228. <tt>buf</tt> длиной <tt>buf_len</tt> в лог как одну запись. Функция вызывается
  229. только когда переданный <tt>sev >= level()</tt>. Реализация может полагаться на
  230. это предусловие.</p>
  231. </synopsis>
  232. <synopsis>
  233. <prototype>class settings_t</prototype>
  234. <p>Хранит настройки логгера: уровень логирования и ссылку на вывод
  235. (<tt>level()</tt> + <tt>get_output()</tt>).</p>
  236. </synopsis>
  237. <synopsis>
  238. <prototype>explicit logger(output &amp;out, severity_t level = severity::info)</prototype>
  239. <p>Создаёт логгер с данным выводом и уровнем логирования. Время жизни объекта,
  240. на который ссылается <tt>out</tt>, должно превосходить время жизни логгера!</p>
  241. <postcondition><tt>this->level() == level &amp;&amp; &amp;this->get_output() == &amp;out</tt></postcondition>
  242. </synopsis>
  243. <synopsis>
  244. <prototype>explicit logger(settings_t s)</prototype>
  245. <p>Создаёт логгер с указанными настройками.</p>
  246. </synopsis>
  247. <synopsis>
  248. <prototype>severity_t level() const</prototype>
  249. <p>Возвращает текущий уровень логирования.</p>
  250. </synopsis>
  251. <synopsis>
  252. <prototype>void level(severity_t new_level)</prototype>
  253. <p>Устанавливает уровень логирования.</p>
  254. <postcondition><tt>level() == new_level</tt></postcondition>
  255. </synopsis>
  256. <synopsis>
  257. <prototype>settings_t settings() const</prototype>
  258. <p>Возвращает текущие настройки.</p>
  259. </synopsis>
  260. <synopsis>
  261. <prototype>output &amp;reset_output(output &amp;out)</prototype>
  262. <p>Устанавливает новый вывод и возвращает старый.</p>
  263. <postcondition><tt>&amp;get_output() == &amp;out</tt></postcondition>
  264. </synopsis>
  265. <synopsis>
  266. <prototype>output &amp;get_output()</prototype>
  267. <prototype>const output &amp;get_output() const</prototype>
  268. <p>Возвращает ссылку на текущий вывод.</p>
  269. </synopsis>
  270. <synopsis>
  271. <prototype>static constexpr size_t min_buffer_size</prototype>
  272. <p>Минимальный размер внутреннего буфера в байтах.</p>
  273. </synopsis>
  274. <synopsis>
  275. <prototype>void shrink_buffer(size_t limit)</prototype>
  276. <p>Устанавливает размер внутреннего буфера в <tt>min_buffer_size</tt>, если он
  277. превосходит <tt>limit</tt> байтов. Позволяет предотвратить бесконрольное
  278. разрастание используемой памяти при выводе записей большого размера.</p>
  279. </synopsis>
  280. <synopsis>
  281. <prototype>void message(severity_t severity, const char *msg, size_t msg_len)</prototype>
  282. <prototype>void message(severity_t severity, std::string_view msg) <sign>C++17</sign></prototype>
  283. <prototype>void message(severity_t severity, const char *msg) <sign>until C++17</sign></prototype>
  284. <prototype>void message(severity_t severity, const std::string &amp;msg) <sign>until C++17</sign></prototype>
  285. <p>Выводит сообщение с заданным приоритетом.</p>
  286. </synopsis>
  287. <synopsis>
  288. <prototype>void trace(std::string_view msg) <sign>C++17</sign></prototype>
  289. <prototype>void trace(const char *msg) <sign>until C++17</sign></prototype>
  290. <prototype>void trace(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  291. <prototype>void debug(std::string_view msg) <sign>C++17</sign></prototype>
  292. <prototype>void debug(const char *msg) <sign>until C++17</sign></prototype>
  293. <prototype>void debug(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  294. <prototype>void info(std::string_view msg) <sign>C++17</sign></prototype>
  295. <prototype>void info(const char *msg) <sign>until C++17</sign></prototype>
  296. <prototype>void info(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  297. <prototype>void notice(std::string_view msg) <sign>C++17</sign></prototype>
  298. <prototype>void notice(const char *msg) <sign>until C++17</sign></prototype>
  299. <prototype>void notice(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  300. <prototype>void warning(std::string_view msg) <sign>C++17</sign></prototype>
  301. <prototype>void warning(const char *msg) <sign>until C++17</sign></prototype>
  302. <prototype>void warning(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  303. <prototype>void error(std::string_view msg) <sign>C++17</sign></prototype>
  304. <prototype>void error(const char *msg) <sign>until C++17</sign></prototype>
  305. <prototype>void error(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  306. <prototype>void fatal(std::string_view msg) <sign>C++17</sign></prototype>
  307. <prototype>void fatal(const char *msg) <sign>until C++17</sign></prototype>
  308. <prototype>void fatal(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  309. <p>Выводит сообщение с соответствующим приоритетом.</p>
  310. </synopsis>
  311. <synopsis>
  312. <prototype><![CDATA[template<class... Args>
  313. void format(severity_t s,
  314. std::format_string<Args...> fmt, Args&&... args)]]> <sign>C++20</sign></prototype>
  315. <p>Форматирует сообщение используя указанную строку формата и аргументы
  316. (подобно <tt>std::format</tt>), затем выводит его с заданным приоритетом.</p>
  317. </synopsis>
  318. <synopsis>
  319. <prototype><![CDATA[template<class Arg1, class... Args>
  320. void trace(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  321. <prototype><![CDATA[template<class Arg1, class... Args>
  322. void debug(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  323. <prototype><![CDATA[template<class Arg1, class... Args>
  324. void info(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  325. <prototype><![CDATA[template<class Arg1, class... Args>
  326. void notice(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  327. <prototype><![CDATA[template<class Arg1, class... Args>
  328. void warning(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  329. <prototype><![CDATA[template<class Arg1, class... Args>
  330. void error(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  331. <prototype><![CDATA[template<class Arg1, class... Args>
  332. void fatal(std::format_string<Arg1,Args...> fmt, Arg1 &&arg1, Args&&... args)]]> <sign>C++20</sign></prototype>
  333. <p>Форматирует сообщение используя указанную строку формата и аргументы
  334. (подобно <tt>std::format</tt>), затем выводит его с соответствующим
  335. приоритетом.</p>
  336. </synopsis>
  337. <synopsis>
  338. <prototype>logger::record trace()</prototype>
  339. <prototype>logger::record debug()</prototype>
  340. <prototype>logger::record info()</prototype>
  341. <prototype>logger::record notice()</prototype>
  342. <prototype>logger::record warning()</prototype>
  343. <prototype>logger::record error()</prototype>
  344. <prototype>logger::record fatal()</prototype>
  345. <p>Создаёт новую запись c соответствующим приоритетом и позволяет писать в неё
  346. части сообщения с помощью оператора <tt>&lt;&lt;</tt>.</p>
  347. </synopsis>
  348. <synopsis>
  349. <prototype>bool trace_visible() const</prototype>
  350. <prototype>bool debug_visible() const</prototype>
  351. <prototype>bool info_visible() const</prototype>
  352. <prototype>bool notice_visible() const</prototype>
  353. <prototype>bool warning_visible() const</prototype>
  354. <prototype>bool error_visible() const</prototype>
  355. <prototype>bool fatal_visible() const</prototype>
  356. <p>Возвращает <tt>true</tt>, если запись с указанным уровнем логирования будет
  357. выведена в лог при текущих настройках. Использование данных функций позволяет
  358. исключить форматирование сообщений, которые всё равно не попадут в лог.</p>
  359. </synopsis>
  360. <synopsis>
  361. <prototype>record::record(logger &amp;log, severity_t sev)</prototype>
  362. <p>Создаёт запись лога с указанным приоритетом. Обычно вместо явного вызова
  363. данного конструктора следует использовать функции <tt>logger</tt>’а, вроде
  364. <tt>info()</tt> без параметров, для создания объекта.</p>
  365. </synopsis>
  366. <synopsis>
  367. <prototype>record::~record()</prototype>
  368. <p>Выводит сформированную запись в лог.</p>
  369. </synopsis>
  370. <synopsis>
  371. <prototype>record record::append(const char *str, size_t str_len)</prototype>
  372. <p>Добавляет строку к сообщению.</p>
  373. </synopsis>
  374. <synopsis>
  375. <prototype>template&lt;class T> record record::operator&lt;&lt;(const T &amp;v)</prototype>
  376. <p>Набор инсертеров для различных типов данных. Вызывают <tt>sb &lt;&lt; v</tt>,
  377. где <tt>sb</tt> имеет тип <tt>__vic::string_buffer</tt>.</p>
  378. </synopsis>
  379. </section>
  380. <section><title>Свободные функции</title>
  381. <synopsis>
  382. <prototype>const char *to_string(logger::severity_t s)</prototype>
  383. <prototype>constexpr std::string_view to_string_view(logger::severity s) <sign>C++17</sign></prototype>
  384. <p>Преобразует приоритет записи лога в текстовое представление, которое можно,
  385. например, вывести в лог. Пример: для <tt>severity::debug</tt> возвращается
  386. "<tt>DEBUG</tt>" и т.п.</p>
  387. </synopsis>
  388. </section>
  389. <section><title>Пример</title>
  390. <code-block lang="C++"><![CDATA[
  391. /////////////////////////////////////////////////////////////////////////////
  392. // Вывод сообщений в std::clog с указанием приоритета
  393. class coutput : public __vic::logger::output
  394. {
  395. public:
  396. void publish_record(__vic::logger::severity_t s,
  397. const char *rec, size_t rec_n)
  398. {
  399. std::clog << to_string(s) << ": ";
  400. std::clog.write(rec, rec_n) << std::endl;
  401. }
  402. };
  403. /////////////////////////////////////////////////////////////////////////////
  404. int main()
  405. {
  406. coutput log_output:
  407. __vic::logger log(log_output, __vic::logger::severity::debug);
  408. log.info("Application is started");
  409. for(int i = 0; i < 5; i++)
  410. log.debug() << "Loop i = " << i;
  411. log.warning("Application end");
  412. }
  413. ]]></code-block>
  414. <p>Результат:</p>
  415. <tty>
  416. INFO: Application is started
  417. DEBUG: Loop i = 0
  418. DEBUG: Loop i = 1
  419. DEBUG: Loop i = 2
  420. DEBUG: Loop i = 3
  421. DEBUG: Loop i = 4
  422. WARNING: Application end
  423. </tty>
  424. </section>
  425. </chapter>
  426. </chapter>