logger.h.xml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. record trace();
  72. record debug();
  73. record info();
  74. record notice();
  75. record warning();
  76. record error();
  77. record fatal();
  78. bool trace_visible() const;
  79. bool debug_visible() const;
  80. bool info_visible() const;
  81. bool notice_visible() const;
  82. bool warning_visible() const;
  83. bool error_visible() const;
  84. bool fatal_visible() const;
  85. };
  86. class logger::record
  87. {
  88. public:
  89. record(logger &log, severity_t sev);
  90. ~record();
  91. record append(const char *str, size_t str_len);
  92. template<class T> record operator<<(const T &v);
  93. };
  94. const char *to_string(logger::severity_t s);
  95. #if __cpp_lib_string_view // C++17
  96. constexpr std::string_view to_string_view(logger::severity s);
  97. #endif
  98. ]]></code-block>
  99. <p>Front-end логгера. Реализует построение записей с помощью оператора
  100. <tt>&lt;&lt;</tt>, подобно стандартной библиотеке потоков <tt>iostream</tt>.
  101. Каждая запись лога имеет назначенный приоритет. Логгер может фильтровать вывод
  102. записей по этому приоритету. Предопределены 6 уровней приоритета (в порядке
  103. возрастания):</p>
  104. <list style="numbered">
  105. <item>TRACE - подробная отладка,</item>
  106. <item>DEBUG - отладка,</item>
  107. <item>INFO - информационное сообщение,</item>
  108. <item>NOTICE - нормальное, но важное событие,</item>
  109. <item>WARNING - незначительная ошибка или подозрительная ситуация,</item>
  110. <item>ERROR - серьёзная ошибка, но приложение может продолжать
  111. работу,</item>
  112. <item>FATAL - критическая ошибка, приложение не может продолжить
  113. выполнение.</item>
  114. </list>
  115. <p>INFO является уровнем логирования по умолчанию. Если сообщение (запись)
  116. имеет приоритет ниже текущего уровня логирования, то оно игнорируется и никуда
  117. не выводится.</p>
  118. <p>Для создания сообщений с нужным приоритетом предоставляется набор одноимённых
  119. функций. Например, <tt>info()</tt> для сообщений INFO. Также есть универсальная
  120. функция <tt>message()</tt>, в которой приоритет задаётся параметром, но, обычно,
  121. следует использовать специфичные функции.</p>
  122. <p>Существует 2 способа создания сообщений. Первый прост и обычен:</p>
  123. <code-block lang="C++">
  124. log.trace("Trace message");
  125. log.debug("Debug message");
  126. log.info("Info message");
  127. log.notice("Notice");
  128. log.warning("Warning");
  129. log.error("Recoverable error");
  130. log.fatal("Fatal error");
  131. </code-block>
  132. <p>Второй немного более сложен, но предоставляет гораздо большие возможности:</p>
  133. <code-block lang="C++"><![CDATA[
  134. log.error() << "Cannot open file " << filename << '!';
  135. log.warning() << "Loop iteration no " << i;
  136. ]]></code-block>
  137. <p>Вызов функции без параметров создаёт объект типа <tt>logger::record</tt> с
  138. соответствующим приоритетом. Теперь в него можно писать сообщение с
  139. использованием оператора <tt>&lt;&lt;</tt>. Сформированная запись будет
  140. выведена в лог по завершении вычисления «полного выражения» (термин из
  141. Стандарта)</p>
  142. <p>Если сформировать запись лога сложно или невозможно одним выражением, то
  143. следует явно создать объект <tt>logger::record</tt> и писать в него. Запись
  144. будет выведена с лог при вызове деструктора данного объекта:</p>
  145. <code-block lang="C++"><![CDATA[
  146. {
  147. logger::record rec = log.info(); // Начало формирования записи
  148. rec << "List elements: ";
  149. for(auto el : list) rec << el << ", ";
  150. // Сформированная запись попадёт в лог при выходе из блока
  151. }
  152. ]]></code-block>
  153. <note>В целях повышения эффективности используйте обычную функциональную запись,
  154. если строка уже готова для вывода:</note>
  155. <code-block lang="C++"><![CDATA[
  156. log.info("Message");
  157. // а не
  158. log.info() << "Message";
  159. ]]></code-block>
  160. <p>Вывод записей с приоритетами DEBUG и TRACE обычно отключен в нормальных
  161. условиях. Такие записи хоть и не попадут в лог, но время на их форматирование
  162. всё равно будет тратиться. Поэтому перед попыткой сформировать какую-нибудь
  163. отладочную запись с помощью операторов <tt>&lt;&lt;</tt> проверьте, включена ли
  164. отладка, с помощью вызова <tt>debug_visible()</tt> или <tt>trace_visible()</tt>:
  165. </p>
  166. <code-block lang="C++"><![CDATA[
  167. if(log.debug_visible())
  168. log.debug() << ...; // формируем запись
  169. ]]></code-block>
  170. <p>Это не относится к обычным вызовам <tt>debug(msg)</tt> и <tt>trace(msg)</tt>,
  171. которым передаётся уже готовая к выводу строка, и никакого дополнительного
  172. форматирования не требуется.</p>
  173. <p>Для использования <tt>logger</tt> нужно реализовать абстрактный базовый класс
  174. <tt>logger::output</tt> (определить <tt>publish_record()</tt>). Реализация
  175. должна вывести куда-то сформированную запись, например, в файл или БД.
  176. <tt>output</tt>, переданный в <tt>logger</tt> при конструировании, впоследствии
  177. можно заменить с помощью вызова <tt>reset_output()</tt>.</p>
  178. <section><title>Члены класса</title>
  179. <synopsis>
  180. <prototype>severity::trace</prototype>
  181. <prototype>severity::debug</prototype>
  182. <prototype>severity::info</prototype>
  183. <prototype>severity::notice</prototype>
  184. <prototype>severity::warning</prototype>
  185. <prototype>severity::error</prototype>
  186. <prototype>severity::fatal</prototype>
  187. <p>Константы приоритетов и уровней логирования. Данная форма используется как в
  188. режиме C++11, так и в C++98.</p>
  189. </synopsis>
  190. <synopsis>
  191. <prototype>typename severity_t</prototype>
  192. <p>Используйте данный идентификатор, если коду требуется совместимость с режимом
  193. C++98. Начиная с C++11 это просто синоним <tt>severity</tt>.</p>
  194. </synopsis>
  195. <synopsis>
  196. <prototype>class output</prototype>
  197. <p>Интерфейс back-end'а логирования.</p>
  198. </synopsis>
  199. <synopsis>
  200. <prototype>void output::publish_record(severity_t sev, const char *buf, size_t buf_len)</prototype>
  201. <p>Реализация этой чисто виртуальной функции должна вывести содержимое
  202. <tt>buf</tt> длиной <tt>buf_len</tt> в лог как одну запись. Функция вызывается
  203. только когда переданный <tt>sev >= level()</tt>. Реализация может полагаться на
  204. это предусловие.</p>
  205. </synopsis>
  206. <synopsis>
  207. <prototype>class settings_t</prototype>
  208. <p>Хранит настройки логгера: уровень логирования и ссылку на вывод
  209. (<tt>level()</tt> + <tt>get_output()</tt>).</p>
  210. </synopsis>
  211. <synopsis>
  212. <prototype>explicit logger(output &amp;out, severity_t level = severity::info)</prototype>
  213. <p>Создаёт логгер с данным выводом и уровнем логирования. Время жизни объекта,
  214. на который ссылается <tt>out</tt>, должно превосходить время жизни логгера!</p>
  215. <postcondition><tt>this->level() == level &amp;&amp; &amp;this->get_output() == &amp;out</tt></postcondition>
  216. </synopsis>
  217. <synopsis>
  218. <prototype>explicit logger(settings_t s)</prototype>
  219. <p>Создаёт логгер с указанными настройками.</p>
  220. </synopsis>
  221. <synopsis>
  222. <prototype>severity_t level() const</prototype>
  223. <p>Возвращает текущий уровень логирования.</p>
  224. </synopsis>
  225. <synopsis>
  226. <prototype>void level(severity_t new_level)</prototype>
  227. <p>Устанавливает уровень логирования.</p>
  228. <postcondition><tt>level() == new_level</tt></postcondition>
  229. </synopsis>
  230. <synopsis>
  231. <prototype>settings_t settings() const</prototype>
  232. <p>Возвращает текущие настройки.</p>
  233. </synopsis>
  234. <synopsis>
  235. <prototype>output &amp;reset_output(output &amp;out)</prototype>
  236. <p>Устанавливает новый вывод и возвращает старый.</p>
  237. <postcondition><tt>&amp;get_output() == &amp;out</tt></postcondition>
  238. </synopsis>
  239. <synopsis>
  240. <prototype>output &amp;get_output()</prototype>
  241. <prototype>const output &amp;get_output() const</prototype>
  242. <p>Возвращает ссылку на текущий вывод.</p>
  243. </synopsis>
  244. <synopsis>
  245. <prototype>static constexpr size_t min_buffer_size</prototype>
  246. <p>Минимальный размер внутреннего буфера в байтах.</p>
  247. </synopsis>
  248. <synopsis>
  249. <prototype>void shrink_buffer(size_t limit)</prototype>
  250. <p>Устанавливает размер внутреннего буфера в <tt>min_buffer_size</tt>, если он
  251. превосходит <tt>limit</tt> байтов. Позволяет предотвратить бесконрольное
  252. разрастание используемой памяти при выводе записей большого размера.</p>
  253. </synopsis>
  254. <synopsis>
  255. <prototype>void message(severity_t severity, const char *msg, size_t msg_len)</prototype>
  256. <prototype>void message(severity_t severity, std::string_view msg) <sign>C++17</sign></prototype>
  257. <prototype>void message(severity_t severity, const char *msg) <sign>until C++17</sign></prototype>
  258. <prototype>void message(severity_t severity, const std::string &amp;msg) <sign>until C++17</sign></prototype>
  259. <p>Выводит сообщение с заданным приоритетом.</p>
  260. </synopsis>
  261. <synopsis>
  262. <prototype>void trace(std::string_view msg) <sign>C++17</sign></prototype>
  263. <prototype>void trace(const char *msg) <sign>until C++17</sign></prototype>
  264. <prototype>void trace(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  265. <prototype>void debug(std::string_view msg) <sign>C++17</sign></prototype>
  266. <prototype>void debug(const char *msg) <sign>until C++17</sign></prototype>
  267. <prototype>void debug(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  268. <prototype>void info(std::string_view msg) <sign>C++17</sign></prototype>
  269. <prototype>void info(const char *msg) <sign>until C++17</sign></prototype>
  270. <prototype>void info(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  271. <prototype>void notice(std::string_view msg) <sign>C++17</sign></prototype>
  272. <prototype>void notice(const char *msg) <sign>until C++17</sign></prototype>
  273. <prototype>void notice(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  274. <prototype>void warning(std::string_view msg) <sign>C++17</sign></prototype>
  275. <prototype>void warning(const char *msg) <sign>until C++17</sign></prototype>
  276. <prototype>void warning(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  277. <prototype>void error(std::string_view msg) <sign>C++17</sign></prototype>
  278. <prototype>void error(const char *msg) <sign>until C++17</sign></prototype>
  279. <prototype>void error(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  280. <prototype>void fatal(std::string_view msg) <sign>C++17</sign></prototype>
  281. <prototype>void fatal(const char *msg) <sign>until C++17</sign></prototype>
  282. <prototype>void fatal(const std::string &amp;msg) <sign>until C++17</sign></prototype>
  283. <p>Выводит сообщение с соответствующим приоритетом.</p>
  284. </synopsis>
  285. <synopsis>
  286. <prototype>logger::record trace()</prototype>
  287. <prototype>logger::record debug()</prototype>
  288. <prototype>logger::record info()</prototype>
  289. <prototype>logger::record notice()</prototype>
  290. <prototype>logger::record warning()</prototype>
  291. <prototype>logger::record error()</prototype>
  292. <prototype>logger::record fatal()</prototype>
  293. <p>Создаёт новую запись c соответствующим приоритетом и позволяет писать в неё
  294. части сообщения с помощью оператора <tt>&lt;&lt;</tt>.</p>
  295. </synopsis>
  296. <synopsis>
  297. <prototype>bool trace_visible() const</prototype>
  298. <prototype>bool debug_visible() const</prototype>
  299. <prototype>bool info_visible() const</prototype>
  300. <prototype>bool notice_visible() const</prototype>
  301. <prototype>bool warning_visible() const</prototype>
  302. <prototype>bool error_visible() const</prototype>
  303. <prototype>bool fatal_visible() const</prototype>
  304. <p>Возвращает <tt>true</tt>, если запись с указанным уровнем логирования будет
  305. выведена в лог при текущих настройках. Использование данных функций позволяет
  306. исключить форматирование сообщений, которые всё равно не попадут в лог.</p>
  307. </synopsis>
  308. <synopsis>
  309. <prototype>record::record(logger &amp;log, severity_t sev)</prototype>
  310. <p>Создаёт запись лога с указанным приоритетом. Обычно вместо явного вызова
  311. данного конструктора следует использовать функции <tt>logger</tt>’а, вроде
  312. <tt>info()</tt> без параметров, для создания объекта.</p>
  313. </synopsis>
  314. <synopsis>
  315. <prototype>record::~record()</prototype>
  316. <p>Выводит сформированную запись в лог.</p>
  317. </synopsis>
  318. <synopsis>
  319. <prototype>record record::append(const char *str, size_t str_len)</prototype>
  320. <p>Добавляет строку к сообщению.</p>
  321. </synopsis>
  322. <synopsis>
  323. <prototype>template&lt;class T> record record::operator&lt;&lt;(const T &amp;v)</prototype>
  324. <p>Набор инсертеров для различных типов данных. Вызывают <tt>sb &lt;&lt; v</tt>,
  325. где <tt>sb</tt> имеет тип <tt>__vic::string_buffer</tt>.</p>
  326. </synopsis>
  327. </section>
  328. <section><title>Свободные функции</title>
  329. <synopsis>
  330. <prototype>const char *to_string(logger::severity_t s)</prototype>
  331. <prototype>constexpr std::string_view to_string_view(logger::severity s) <sign>C++17</sign></prototype>
  332. <p>Преобразует приоритет записи лога в текстовое представление, которое можно,
  333. например, вывести в лог. Пример: для <tt>severity::debug</tt> возвращается
  334. "<tt>DEBUG</tt>" и т.п.</p>
  335. </synopsis>
  336. </section>
  337. <section><title>Пример</title>
  338. <code-block lang="C++"><![CDATA[
  339. /////////////////////////////////////////////////////////////////////////////
  340. // Вывод сообщений в std::clog с указанием приоритета
  341. class coutput : public __vic::logger::output
  342. {
  343. public:
  344. void publish_record(__vic::logger::severity_t s,
  345. const char *rec, size_t rec_n)
  346. {
  347. std::clog << to_string(s) << ": ";
  348. std::clog.write(rec, rec_n) << std::endl;
  349. }
  350. };
  351. /////////////////////////////////////////////////////////////////////////////
  352. int main()
  353. {
  354. coutput log_output:
  355. __vic::logger log(log_output, __vic::logger::severity::debug);
  356. log.info("Application is started");
  357. for(int i = 0; i < 5; i++)
  358. log.debug() << "Loop i = " << i;
  359. log.warning("Application end");
  360. }
  361. ]]></code-block>
  362. <p>Результат:</p>
  363. <tty>
  364. INFO: Application is started
  365. DEBUG: Loop i = 0
  366. DEBUG: Loop i = 1
  367. DEBUG: Loop i = 2
  368. DEBUG: Loop i = 3
  369. DEBUG: Loop i = 4
  370. WARNING: Application end
  371. </tty>
  372. </section>
  373. </chapter>
  374. </chapter>