elog.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. /*
  2. * This file is part of the EasyLogger Library.
  3. *
  4. * Copyright (c) 2015-2018, Armink, <armink.ztl@gmail.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * 'Software'), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  21. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. *
  25. * Function: Initialize function and other general function.
  26. * Created on: 2015-04-28
  27. */
  28. #define LOG_TAG "elog"
  29. #include <elog.h>
  30. #include <string.h>
  31. #include <stdarg.h>
  32. #include <stdio.h>
  33. #if !defined(ELOG_OUTPUT_LVL)
  34. #error "Please configure static output log level (in elog_cfg.h)"
  35. #endif
  36. #if !defined(ELOG_LINE_NUM_MAX_LEN)
  37. #error "Please configure output line number max length (in elog_cfg.h)"
  38. #endif
  39. #if !defined(ELOG_LINE_BUF_SIZE)
  40. #error "Please configure buffer size for every line's log (in elog_cfg.h)"
  41. #endif
  42. #if !defined(ELOG_FILTER_TAG_MAX_LEN)
  43. #error "Please configure output filter's tag max length (in elog_cfg.h)"
  44. #endif
  45. #if !defined(ELOG_FILTER_KW_MAX_LEN)
  46. #error "Please configure output filter's keyword max length (in elog_cfg.h)"
  47. #endif
  48. #if !defined(ELOG_NEWLINE_SIGN)
  49. #error "Please configure output newline sign (in elog_cfg.h)"
  50. #endif
  51. /* output filter's tag level max num */
  52. #ifndef ELOG_FILTER_TAG_LVL_MAX_NUM
  53. #define ELOG_FILTER_TAG_LVL_MAX_NUM 4
  54. #endif
  55. #ifdef ELOG_COLOR_ENABLE
  56. /**
  57. * CSI(Control Sequence Introducer/Initiator) sign
  58. * more information on https://en.wikipedia.org/wiki/ANSI_escape_code
  59. */
  60. #define CSI_START "\033["
  61. #define CSI_END "\033[0m"
  62. /* output log front color */
  63. #define F_BLACK "30;"
  64. #define F_RED "31;"
  65. #define F_GREEN "32;"
  66. #define F_YELLOW "33;"
  67. #define F_BLUE "34;"
  68. #define F_MAGENTA "35;"
  69. #define F_CYAN "36;"
  70. #define F_WHITE "37;"
  71. /* output log background color */
  72. #define B_NULL
  73. #define B_BLACK "40;"
  74. #define B_RED "41;"
  75. #define B_GREEN "42;"
  76. #define B_YELLOW "43;"
  77. #define B_BLUE "44;"
  78. #define B_MAGENTA "45;"
  79. #define B_CYAN "46;"
  80. #define B_WHITE "47;"
  81. /* output log fonts style */
  82. #define S_BOLD "1m"
  83. #define S_UNDERLINE "4m"
  84. #define S_BLINK "5m"
  85. #define S_NORMAL "22m"
  86. /* output log default color definition: [front color] + [background color] + [show style] */
  87. #ifndef ELOG_COLOR_ASSERT
  88. #define ELOG_COLOR_ASSERT (F_MAGENTA B_NULL S_NORMAL)
  89. #endif
  90. #ifndef ELOG_COLOR_ERROR
  91. #define ELOG_COLOR_ERROR (F_RED B_NULL S_NORMAL)
  92. #endif
  93. #ifndef ELOG_COLOR_WARN
  94. #define ELOG_COLOR_WARN (F_YELLOW B_NULL S_NORMAL)
  95. #endif
  96. #ifndef ELOG_COLOR_INFO
  97. #define ELOG_COLOR_INFO (F_CYAN B_NULL S_NORMAL)
  98. #endif
  99. #ifndef ELOG_COLOR_DEBUG
  100. #define ELOG_COLOR_DEBUG (F_GREEN B_NULL S_NORMAL)
  101. #endif
  102. #ifndef ELOG_COLOR_VERBOSE
  103. #define ELOG_COLOR_VERBOSE (F_BLUE B_NULL S_NORMAL)
  104. #endif
  105. #endif /* ELOG_COLOR_ENABLE */
  106. /* EasyLogger object */
  107. static EasyLogger elog;
  108. /* every line log's buffer */
  109. static char log_buf[ELOG_LINE_BUF_SIZE] = { 0 };
  110. /* level output info */
  111. static const char *level_output_info[] = {
  112. [ELOG_LVL_ASSERT] = "A/",
  113. [ELOG_LVL_ERROR] = "E/",
  114. [ELOG_LVL_WARN] = "W/",
  115. [ELOG_LVL_INFO] = "I/",
  116. [ELOG_LVL_DEBUG] = "D/",
  117. [ELOG_LVL_VERBOSE] = "V/",
  118. };
  119. #ifdef ELOG_COLOR_ENABLE
  120. /* color output info */
  121. static const char *color_output_info[] = {
  122. [ELOG_LVL_ASSERT] = ELOG_COLOR_ASSERT,
  123. [ELOG_LVL_ERROR] = ELOG_COLOR_ERROR,
  124. [ELOG_LVL_WARN] = ELOG_COLOR_WARN,
  125. [ELOG_LVL_INFO] = ELOG_COLOR_INFO,
  126. [ELOG_LVL_DEBUG] = ELOG_COLOR_DEBUG,
  127. [ELOG_LVL_VERBOSE] = ELOG_COLOR_VERBOSE,
  128. };
  129. #endif /* ELOG_COLOR_ENABLE */
  130. static bool get_fmt_enabled(uint8_t level, size_t set);
  131. static void elog_set_filter_tag_lvl_default(void);
  132. /* EasyLogger assert hook */
  133. void (*elog_assert_hook)(const char* expr, const char* func, size_t line);
  134. extern void elog_port_output(const char *log, size_t size);
  135. extern void elog_port_output_lock(void);
  136. extern void elog_port_output_unlock(void);
  137. /**
  138. * EasyLogger initialize.
  139. *
  140. * @return result
  141. */
  142. ElogErrCode elog_init(void) {
  143. extern ElogErrCode elog_port_init(void);
  144. extern ElogErrCode elog_async_init(void);
  145. ElogErrCode result = ELOG_NO_ERR;
  146. if (elog.init_ok == true) {
  147. return result;
  148. }
  149. /* port initialize */
  150. result = elog_port_init();
  151. if (result != ELOG_NO_ERR) {
  152. return result;
  153. }
  154. #ifdef ELOG_ASYNC_OUTPUT_ENABLE
  155. result = elog_async_init();
  156. if (result != ELOG_NO_ERR) {
  157. return result;
  158. }
  159. #endif
  160. /* enable the output lock */
  161. elog_output_lock_enabled(true);
  162. /* output locked status initialize */
  163. elog.output_is_locked_before_enable = false;
  164. elog.output_is_locked_before_disable = false;
  165. #ifdef ELOG_COLOR_ENABLE
  166. /* enable text color by default */
  167. elog_set_text_color_enabled(true);
  168. #endif
  169. /* set level is ELOG_LVL_VERBOSE */
  170. elog_set_filter_lvl(ELOG_LVL_VERBOSE);
  171. /* set tag_level to default val */
  172. elog_set_filter_tag_lvl_default();
  173. elog.init_ok = true;
  174. return result;
  175. }
  176. /**
  177. * EasyLogger deinitialize.
  178. *
  179. */
  180. void elog_deinit(void) {
  181. extern ElogErrCode elog_port_deinit(void);
  182. extern ElogErrCode elog_async_deinit(void);
  183. if (!elog.init_ok) {
  184. return ;
  185. }
  186. #ifdef ELOG_ASYNC_OUTPUT_ENABLE
  187. elog_async_deinit();
  188. #endif
  189. /* port deinitialize */
  190. elog_port_deinit();
  191. elog.init_ok = false;
  192. }
  193. /**
  194. * EasyLogger start after initialize.
  195. */
  196. void elog_start(void) {
  197. if (!elog.init_ok) {
  198. return ;
  199. }
  200. /* enable output */
  201. elog_set_output_enabled(true);
  202. #if defined(ELOG_ASYNC_OUTPUT_ENABLE)
  203. elog_async_enabled(true);
  204. #elif defined(ELOG_BUF_OUTPUT_ENABLE)
  205. elog_buf_enabled(true);
  206. #endif
  207. /* show version */
  208. log_i("EasyLogger V%s is initialize success.", ELOG_SW_VERSION);
  209. }
  210. /**
  211. * EasyLogger stop after initialize.
  212. */
  213. void elog_stop(void) {
  214. if (!elog.init_ok) {
  215. return ;
  216. }
  217. /* disable output */
  218. elog_set_output_enabled(false);
  219. #if defined(ELOG_ASYNC_OUTPUT_ENABLE)
  220. elog_async_enabled(false);
  221. #elif defined(ELOG_BUF_OUTPUT_ENABLE)
  222. elog_buf_enabled(false);
  223. #endif
  224. /* show version */
  225. log_i("EasyLogger V%s is deinitialize success.", ELOG_SW_VERSION);
  226. }
  227. /**
  228. * set output enable or disable
  229. *
  230. * @param enabled TRUE: enable FALSE: disable
  231. */
  232. void elog_set_output_enabled(bool enabled) {
  233. ELOG_ASSERT((enabled == false) || (enabled == true));
  234. elog.output_enabled = enabled;
  235. }
  236. #ifdef ELOG_COLOR_ENABLE
  237. /**
  238. * set log text color enable or disable
  239. *
  240. * @param enabled TRUE: enable FALSE:disable
  241. */
  242. void elog_set_text_color_enabled(bool enabled) {
  243. elog.text_color_enabled = enabled;
  244. }
  245. /**
  246. * get log text color enable status
  247. *
  248. * @return enable or disable
  249. */
  250. bool elog_get_text_color_enabled(void) {
  251. return elog.text_color_enabled;
  252. }
  253. #endif /* ELOG_COLOR_ENABLE */
  254. /**
  255. * get output is enable or disable
  256. *
  257. * @return enable or disable
  258. */
  259. bool elog_get_output_enabled(void) {
  260. return elog.output_enabled;
  261. }
  262. /**
  263. * set log output format. only enable or disable
  264. *
  265. * @param level level
  266. * @param set format set
  267. */
  268. void elog_set_fmt(uint8_t level, size_t set) {
  269. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  270. elog.enabled_fmt_set[level] = set;
  271. }
  272. /**
  273. * set log filter all parameter
  274. *
  275. * @param level level
  276. * @param tag tag
  277. * @param keyword keyword
  278. */
  279. void elog_set_filter(uint8_t level, const char *tag, const char *keyword) {
  280. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  281. elog_set_filter_lvl(level);
  282. elog_set_filter_tag(tag);
  283. elog_set_filter_kw(keyword);
  284. }
  285. /**
  286. * set log filter's level
  287. *
  288. * @param level level
  289. */
  290. void elog_set_filter_lvl(uint8_t level) {
  291. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  292. elog.filter.level = level;
  293. }
  294. /**
  295. * set log filter's tag
  296. *
  297. * @param tag tag
  298. */
  299. void elog_set_filter_tag(const char *tag) {
  300. strncpy(elog.filter.tag, tag, ELOG_FILTER_TAG_MAX_LEN);
  301. }
  302. /**
  303. * set log filter's keyword
  304. *
  305. * @param keyword keyword
  306. */
  307. void elog_set_filter_kw(const char *keyword) {
  308. strncpy(elog.filter.keyword, keyword, ELOG_FILTER_KW_MAX_LEN);
  309. }
  310. /**
  311. * lock output
  312. */
  313. void elog_output_lock(void) {
  314. if (elog.output_lock_enabled) {
  315. elog_port_output_lock();
  316. elog.output_is_locked_before_disable = true;
  317. } else {
  318. elog.output_is_locked_before_enable = true;
  319. }
  320. }
  321. /**
  322. * unlock output
  323. */
  324. void elog_output_unlock(void) {
  325. if (elog.output_lock_enabled) {
  326. elog_port_output_unlock();
  327. elog.output_is_locked_before_disable = false;
  328. } else {
  329. elog.output_is_locked_before_enable = false;
  330. }
  331. }
  332. /**
  333. * set log filter's tag level val to default
  334. */
  335. static void elog_set_filter_tag_lvl_default(void)
  336. {
  337. uint8_t i = 0;
  338. for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
  339. memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
  340. elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
  341. elog.filter.tag_lvl[i].tag_use_flag = false;
  342. }
  343. }
  344. /**
  345. * Set the filter's level by different tag.
  346. * The log on this tag which level is less than it will stop output.
  347. *
  348. * example:
  349. * // the example tag log enter silent mode
  350. * elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_SILENT);
  351. * // the example tag log which level is less than INFO level will stop output
  352. * elog_set_filter_tag_lvl("example", ELOG_LVL_INFO);
  353. * // remove example tag's level filter, all level log will resume output
  354. * elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_ALL);
  355. *
  356. * @param tag log tag
  357. * @param level The filter level. When the level is ELOG_FILTER_LVL_SILENT, the log enter silent mode.
  358. * When the level is ELOG_FILTER_LVL_ALL, it will remove this tag's level filer.
  359. * Then all level log will resume output.
  360. *
  361. */
  362. void elog_set_filter_tag_lvl(const char *tag, uint8_t level)
  363. {
  364. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  365. ELOG_ASSERT(tag != ((void *)0));
  366. uint8_t i = 0;
  367. if (!elog.init_ok) {
  368. return;
  369. }
  370. elog_output_lock();
  371. /* find the tag in arr */
  372. for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
  373. if (elog.filter.tag_lvl[i].tag_use_flag == true &&
  374. !strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
  375. break;
  376. }
  377. }
  378. if (i < ELOG_FILTER_TAG_LVL_MAX_NUM){
  379. /* find OK */
  380. if (level == ELOG_FILTER_LVL_ALL){
  381. /* remove current tag's level filter when input level is the lowest level */
  382. elog.filter.tag_lvl[i].tag_use_flag = false;
  383. memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
  384. elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
  385. } else{
  386. elog.filter.tag_lvl[i].level = level;
  387. }
  388. } else{
  389. /* only add the new tag's level filer when level is not ELOG_FILTER_LVL_ALL */
  390. if (level != ELOG_FILTER_LVL_ALL){
  391. for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
  392. if (elog.filter.tag_lvl[i].tag_use_flag == false){
  393. strncpy(elog.filter.tag_lvl[i].tag, tag, ELOG_FILTER_TAG_MAX_LEN);
  394. elog.filter.tag_lvl[i].level = level;
  395. elog.filter.tag_lvl[i].tag_use_flag = true;
  396. break;
  397. }
  398. }
  399. }
  400. }
  401. elog_output_unlock();
  402. }
  403. /**
  404. * get the level on tag's level filer
  405. *
  406. * @param tag tag
  407. *
  408. * @return It will return the lowest level when tag was not found.
  409. * Other level will return when tag was found.
  410. */
  411. uint8_t elog_get_filter_tag_lvl(const char *tag)
  412. {
  413. ELOG_ASSERT(tag != ((void *)0));
  414. uint8_t i = 0;
  415. uint8_t level = ELOG_FILTER_LVL_ALL;
  416. if (!elog.init_ok) {
  417. return level;
  418. }
  419. elog_output_lock();
  420. /* find the tag in arr */
  421. for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
  422. if (elog.filter.tag_lvl[i].tag_use_flag == true &&
  423. !strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
  424. level = elog.filter.tag_lvl[i].level;
  425. break;
  426. }
  427. }
  428. elog_output_unlock();
  429. return level;
  430. }
  431. /**
  432. * output RAW format log
  433. *
  434. * @param format output format
  435. * @param ... args
  436. */
  437. void elog_raw(const char *format, ...) {
  438. va_list args;
  439. size_t log_len = 0;
  440. int fmt_result;
  441. /* check output enabled */
  442. if (!elog.output_enabled) {
  443. return;
  444. }
  445. /* args point to the first variable parameter */
  446. va_start(args, format);
  447. /* lock output */
  448. elog_output_lock();
  449. /* package log data to buffer */
  450. fmt_result = vsnprintf(log_buf, ELOG_LINE_BUF_SIZE, format, args);
  451. /* output converted log */
  452. if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
  453. log_len = fmt_result;
  454. } else {
  455. log_len = ELOG_LINE_BUF_SIZE;
  456. }
  457. /* output log */
  458. #if defined(ELOG_ASYNC_OUTPUT_ENABLE)
  459. extern void elog_async_output(uint8_t level, const char *log, size_t size);
  460. /* raw log will using assert level */
  461. elog_async_output(ELOG_LVL_ASSERT, log_buf, log_len);
  462. #elif defined(ELOG_BUF_OUTPUT_ENABLE)
  463. extern void elog_buf_output(const char *log, size_t size);
  464. elog_buf_output(log_buf, log_len);
  465. #else
  466. elog_port_output(log_buf, log_len);
  467. #endif
  468. /* unlock output */
  469. elog_output_unlock();
  470. va_end(args);
  471. }
  472. /**
  473. * output the log
  474. *
  475. * @param level level
  476. * @param tag tag
  477. * @param file file name
  478. * @param func function name
  479. * @param line line number
  480. * @param format output format
  481. * @param ... args
  482. *
  483. */
  484. void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
  485. const long line, const char *format, ...) {
  486. extern const char *elog_port_get_time(void);
  487. extern const char *elog_port_get_p_info(void);
  488. extern const char *elog_port_get_t_info(void);
  489. size_t tag_len = strlen(tag), log_len = 0, newline_len = strlen(ELOG_NEWLINE_SIGN);
  490. char line_num[ELOG_LINE_NUM_MAX_LEN + 1] = { 0 };
  491. char tag_sapce[ELOG_FILTER_TAG_MAX_LEN / 2 + 1] = { 0 };
  492. va_list args;
  493. int fmt_result;
  494. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  495. /* check output enabled */
  496. if (!elog.output_enabled) {
  497. return;
  498. }
  499. /* level filter */
  500. if (level > elog.filter.level || level > elog_get_filter_tag_lvl(tag)) {
  501. return;
  502. } else if (!strstr(tag, elog.filter.tag)) { /* tag filter */
  503. return;
  504. }
  505. /* args point to the first variable parameter */
  506. va_start(args, format);
  507. /* lock output */
  508. elog_output_lock();
  509. #ifdef ELOG_COLOR_ENABLE
  510. /* add CSI start sign and color info */
  511. if (elog.text_color_enabled) {
  512. log_len += elog_strcpy(log_len, log_buf + log_len, CSI_START);
  513. log_len += elog_strcpy(log_len, log_buf + log_len, color_output_info[level]);
  514. }
  515. #endif
  516. /* package level info */
  517. if (get_fmt_enabled(level, ELOG_FMT_LVL)) {
  518. log_len += elog_strcpy(log_len, log_buf + log_len, level_output_info[level]);
  519. }
  520. /* package tag info */
  521. if (get_fmt_enabled(level, ELOG_FMT_TAG)) {
  522. log_len += elog_strcpy(log_len, log_buf + log_len, tag);
  523. /* if the tag length is less than 50% ELOG_FILTER_TAG_MAX_LEN, then fill space */
  524. if (tag_len <= ELOG_FILTER_TAG_MAX_LEN / 2) {
  525. memset(tag_sapce, ' ', ELOG_FILTER_TAG_MAX_LEN / 2 - tag_len);
  526. log_len += elog_strcpy(log_len, log_buf + log_len, tag_sapce);
  527. }
  528. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  529. }
  530. /* package time, process and thread info */
  531. if (get_fmt_enabled(level, ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
  532. log_len += elog_strcpy(log_len, log_buf + log_len, "[");
  533. /* package time info */
  534. if (get_fmt_enabled(level, ELOG_FMT_TIME)) {
  535. log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_time());
  536. if (get_fmt_enabled(level, ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
  537. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  538. }
  539. }
  540. /* package process info */
  541. if (get_fmt_enabled(level, ELOG_FMT_P_INFO)) {
  542. log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_p_info());
  543. if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
  544. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  545. }
  546. }
  547. /* package thread info */
  548. if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
  549. log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_t_info());
  550. }
  551. log_len += elog_strcpy(log_len, log_buf + log_len, "] ");
  552. }
  553. /* package file directory and name, function name and line number info */
  554. if (get_fmt_enabled(level, ELOG_FMT_DIR | ELOG_FMT_FUNC | ELOG_FMT_LINE)) {
  555. log_len += elog_strcpy(log_len, log_buf + log_len, "(");
  556. /* package file info */
  557. if (get_fmt_enabled(level, ELOG_FMT_DIR)) {
  558. log_len += elog_strcpy(log_len, log_buf + log_len, file);
  559. if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
  560. log_len += elog_strcpy(log_len, log_buf + log_len, ":");
  561. } else if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
  562. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  563. }
  564. }
  565. /* package line info */
  566. if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
  567. snprintf(line_num, ELOG_LINE_NUM_MAX_LEN, "%ld", line);
  568. log_len += elog_strcpy(log_len, log_buf + log_len, line_num);
  569. if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
  570. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  571. }
  572. }
  573. /* package func info */
  574. if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
  575. log_len += elog_strcpy(log_len, log_buf + log_len, func);
  576. }
  577. log_len += elog_strcpy(log_len, log_buf + log_len, ")");
  578. }
  579. /* package other log data to buffer. '\0' must be added in the end by vsnprintf. */
  580. fmt_result = vsnprintf(log_buf + log_len, ELOG_LINE_BUF_SIZE - log_len, format, args);
  581. va_end(args);
  582. /* calculate log length */
  583. if ((log_len + fmt_result <= ELOG_LINE_BUF_SIZE) && (fmt_result > -1)) {
  584. log_len += fmt_result;
  585. } else {
  586. /* using max length */
  587. log_len = ELOG_LINE_BUF_SIZE;
  588. }
  589. /* overflow check and reserve some space for CSI end sign and newline sign */
  590. #ifdef ELOG_COLOR_ENABLE
  591. if (log_len + (sizeof(CSI_END) - 1) + newline_len > ELOG_LINE_BUF_SIZE) {
  592. /* using max length */
  593. log_len = ELOG_LINE_BUF_SIZE;
  594. /* reserve some space for CSI end sign */
  595. log_len -= (sizeof(CSI_END) - 1);
  596. #else
  597. if (log_len + newline_len > ELOG_LINE_BUF_SIZE) {
  598. /* using max length */
  599. log_len = ELOG_LINE_BUF_SIZE;
  600. #endif /* ELOG_COLOR_ENABLE */
  601. /* reserve some space for newline sign */
  602. log_len -= newline_len;
  603. }
  604. /* keyword filter */
  605. if (elog.filter.keyword[0] != '\0') {
  606. /* add string end sign */
  607. log_buf[log_len] = '\0';
  608. /* find the keyword */
  609. if (!strstr(log_buf, elog.filter.keyword)) {
  610. /* unlock output */
  611. elog_output_unlock();
  612. return;
  613. }
  614. }
  615. #ifdef ELOG_COLOR_ENABLE
  616. /* add CSI end sign */
  617. if (elog.text_color_enabled) {
  618. log_len += elog_strcpy(log_len, log_buf + log_len, CSI_END);
  619. }
  620. #endif
  621. /* package newline sign */
  622. log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
  623. /* output log */
  624. #if defined(ELOG_ASYNC_OUTPUT_ENABLE)
  625. extern void elog_async_output(uint8_t level, const char *log, size_t size);
  626. elog_async_output(level, log_buf, log_len);
  627. #elif defined(ELOG_BUF_OUTPUT_ENABLE)
  628. extern void elog_buf_output(const char *log, size_t size);
  629. elog_buf_output(log_buf, log_len);
  630. #else
  631. elog_port_output(log_buf, log_len);
  632. #endif
  633. /* unlock output */
  634. elog_output_unlock();
  635. }
  636. /**
  637. * get format enabled
  638. *
  639. * @param level level
  640. * @param set format set
  641. *
  642. * @return enable or disable
  643. */
  644. static bool get_fmt_enabled(uint8_t level, size_t set) {
  645. ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
  646. if (elog.enabled_fmt_set[level] & set) {
  647. return true;
  648. } else {
  649. return false;
  650. }
  651. }
  652. /**
  653. * enable or disable logger output lock
  654. * @note disable this lock is not recommended except you want output system exception log
  655. *
  656. * @param enabled true: enable false: disable
  657. */
  658. void elog_output_lock_enabled(bool enabled) {
  659. elog.output_lock_enabled = enabled;
  660. /* it will re-lock or re-unlock before output lock enable */
  661. if (elog.output_lock_enabled) {
  662. if (!elog.output_is_locked_before_disable && elog.output_is_locked_before_enable) {
  663. /* the output lock is unlocked before disable, and the lock will unlocking after enable */
  664. elog_port_output_lock();
  665. } else if (elog.output_is_locked_before_disable && !elog.output_is_locked_before_enable) {
  666. /* the output lock is locked before disable, and the lock will locking after enable */
  667. elog_port_output_unlock();
  668. }
  669. }
  670. }
  671. /**
  672. * Set a hook function to EasyLogger assert. It will run when the expression is false.
  673. *
  674. * @param hook the hook function
  675. */
  676. void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) {
  677. elog_assert_hook = hook;
  678. }
  679. /**
  680. * find the log level
  681. * @note make sure the log level is output on each format
  682. *
  683. * @param log log buffer
  684. *
  685. * @return log level, found failed will return -1
  686. */
  687. int8_t elog_find_lvl(const char *log) {
  688. ELOG_ASSERT(log);
  689. /* make sure the log level is output on each format */
  690. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ASSERT] & ELOG_FMT_LVL);
  691. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ERROR] & ELOG_FMT_LVL);
  692. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_WARN] & ELOG_FMT_LVL);
  693. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_INFO] & ELOG_FMT_LVL);
  694. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_DEBUG] & ELOG_FMT_LVL);
  695. ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_VERBOSE] & ELOG_FMT_LVL);
  696. #ifdef ELOG_COLOR_ENABLE
  697. uint8_t i;
  698. size_t csi_start_len = strlen(CSI_START);
  699. for(i = 0; i < ELOG_LVL_TOTAL_NUM; i ++) {
  700. if (!strncmp(color_output_info[i], log + csi_start_len, strlen(color_output_info[i]))) {
  701. return i;
  702. }
  703. }
  704. /* found failed */
  705. return -1;
  706. #else
  707. switch (log[0]) {
  708. case 'A': return ELOG_LVL_ASSERT;
  709. case 'E': return ELOG_LVL_ERROR;
  710. case 'W': return ELOG_LVL_WARN;
  711. case 'I': return ELOG_LVL_INFO;
  712. case 'D': return ELOG_LVL_DEBUG;
  713. case 'V': return ELOG_LVL_VERBOSE;
  714. default: return -1;
  715. }
  716. #endif
  717. }
  718. /**
  719. * find the log tag
  720. * @note make sure the log tag is output on each format
  721. * @note the tag don't have space in it
  722. *
  723. * @param log log buffer
  724. * @param lvl log level, you can get it by @see elog_find_lvl
  725. * @param tag_len found tag length
  726. *
  727. * @return log tag, found failed will return NULL
  728. */
  729. const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len) {
  730. const char *tag = NULL, *tag_end = NULL;
  731. ELOG_ASSERT(log);
  732. ELOG_ASSERT(tag_len);
  733. ELOG_ASSERT(lvl < ELOG_LVL_TOTAL_NUM);
  734. /* make sure the log tag is output on each format */
  735. ELOG_ASSERT(elog.enabled_fmt_set[lvl] & ELOG_FMT_TAG);
  736. #ifdef ELOG_COLOR_ENABLE
  737. tag = log + strlen(CSI_START) + strlen(color_output_info[lvl]) + strlen(level_output_info[lvl]);
  738. #else
  739. tag = log + strlen(level_output_info[lvl]);
  740. #endif
  741. /* find the first space after tag */
  742. if ((tag_end = memchr(tag, ' ', ELOG_FILTER_TAG_MAX_LEN)) != NULL) {
  743. *tag_len = tag_end - tag;
  744. } else {
  745. tag = NULL;
  746. }
  747. return tag;
  748. }
  749. /**
  750. * dump the hex format data to log
  751. *
  752. * @param name name for hex object, it will show on log header
  753. * @param width hex number for every line, such as: 16, 32
  754. * @param buf hex buffer
  755. * @param size buffer size
  756. */
  757. void elog_hexdump(const char *name, uint8_t width, const void *buf, uint16_t size)
  758. {
  759. #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
  760. uint16_t i, j;
  761. uint16_t log_len = 0;
  762. const uint8_t *buf_p = buf;
  763. char dump_string[8] = {0};
  764. int fmt_result;
  765. if (!elog.output_enabled) {
  766. return;
  767. }
  768. /* level filter */
  769. if (ELOG_LVL_DEBUG > elog.filter.level) {
  770. return;
  771. } else if (!strstr(name, elog.filter.tag)) { /* tag filter */
  772. return;
  773. }
  774. /* lock output */
  775. elog_output_lock();
  776. for (i = 0; i < size; i += width) {
  777. /* package header */
  778. fmt_result = snprintf(log_buf, ELOG_LINE_BUF_SIZE, "D/HEX %s: %04X-%04X: ", name, i, i + width - 1);
  779. /* calculate log length */
  780. if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
  781. log_len = fmt_result;
  782. } else {
  783. log_len = ELOG_LINE_BUF_SIZE;
  784. }
  785. /* dump hex */
  786. for (j = 0; j < width; j++) {
  787. if (i + j < size) {
  788. snprintf(dump_string, sizeof(dump_string), "%02X ", buf_p[i + j]);
  789. } else {
  790. strncpy(dump_string, " ", sizeof(dump_string));
  791. }
  792. log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
  793. if ((j + 1) % 8 == 0) {
  794. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  795. }
  796. }
  797. log_len += elog_strcpy(log_len, log_buf + log_len, " ");
  798. /* dump char for hex */
  799. for (j = 0; j < width; j++) {
  800. if (i + j < size) {
  801. snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf_p[i + j]) ? buf_p[i + j] : '.');
  802. log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
  803. }
  804. }
  805. /* overflow check and reserve some space for newline sign */
  806. if (log_len + strlen(ELOG_NEWLINE_SIGN) > ELOG_LINE_BUF_SIZE) {
  807. log_len = ELOG_LINE_BUF_SIZE - strlen(ELOG_NEWLINE_SIGN);
  808. }
  809. /* package newline sign */
  810. log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
  811. /* do log output */
  812. #if defined(ELOG_ASYNC_OUTPUT_ENABLE)
  813. extern void elog_async_output(uint8_t level, const char *log, size_t size);
  814. elog_async_output(ELOG_LVL_DEBUG, log_buf, log_len);
  815. #elif defined(ELOG_BUF_OUTPUT_ENABLE)
  816. extern void elog_buf_output(const char *log, size_t size);
  817. elog_buf_output(log_buf, log_len);
  818. #else
  819. elog_port_output(log_buf, log_len);
  820. #endif
  821. }
  822. /* unlock output */
  823. elog_output_unlock();
  824. }