log_cmds.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * Copyright (c) 2018 Nordic Semiconductor ASA
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <shell/shell.h>
  7. #include <logging/log_ctrl.h>
  8. #include <logging/log.h>
  9. #include <string.h>
  10. typedef int (*log_backend_cmd_t)(const struct shell *shell,
  11. const struct log_backend *backend,
  12. size_t argc,
  13. char **argv);
  14. static const char * const severity_lvls[] = {
  15. "none",
  16. "err",
  17. "wrn",
  18. "inf",
  19. "dbg",
  20. };
  21. static const char * const severity_lvls_sorted[] = {
  22. "dbg",
  23. "err",
  24. "inf",
  25. "none",
  26. "wrn",
  27. };
  28. /**
  29. * @brief Function for finding backend instance with given name.
  30. *
  31. * @param p_name Name of the backend instance.
  32. *
  33. * @return Pointer to the instance or NULL.
  34. *
  35. */
  36. static const struct log_backend *backend_find(char const *name)
  37. {
  38. const struct log_backend *backend;
  39. size_t slen = strlen(name);
  40. for (int i = 0; i < log_backend_count_get(); i++) {
  41. backend = log_backend_get(i);
  42. if (strncmp(name, backend->name, slen) == 0) {
  43. return backend;
  44. }
  45. }
  46. return NULL;
  47. }
  48. static bool shell_state_precheck(const struct shell *shell)
  49. {
  50. if (shell->log_backend->control_block->state
  51. == SHELL_LOG_BACKEND_UNINIT) {
  52. shell_error(shell, "Shell log backend not initialized.");
  53. return false;
  54. }
  55. return true;
  56. }
  57. /**
  58. * @brief Function for executing command on given backend.
  59. */
  60. static int shell_backend_cmd_execute(const struct shell *shell,
  61. size_t argc,
  62. char **argv,
  63. log_backend_cmd_t func)
  64. {
  65. /* Based on the structure of backend commands, name of the backend can
  66. * be found at -1 (log backend <name> command).
  67. */
  68. char const *name = argv[-1];
  69. const struct log_backend *backend = backend_find(name);
  70. if (backend != NULL) {
  71. func(shell, backend, argc, argv);
  72. } else {
  73. shell_error(shell, "Invalid backend: %s", name);
  74. return -ENOEXEC;
  75. }
  76. return 0;
  77. }
  78. static int log_status(const struct shell *shell,
  79. const struct log_backend *backend,
  80. size_t argc, char **argv)
  81. {
  82. uint32_t modules_cnt = log_sources_count();
  83. uint32_t dynamic_lvl;
  84. uint32_t compiled_lvl;
  85. if (!log_backend_is_active(backend)) {
  86. shell_warn(shell, "Logs are halted!");
  87. }
  88. shell_fprintf(shell, SHELL_NORMAL, "%-40s | current | built-in \r\n",
  89. "module_name");
  90. shell_fprintf(shell, SHELL_NORMAL,
  91. "----------------------------------------------------------\r\n");
  92. for (int16_t i = 0U; i < modules_cnt; i++) {
  93. dynamic_lvl = log_filter_get(backend, CONFIG_LOG_DOMAIN_ID,
  94. i, true);
  95. compiled_lvl = log_filter_get(backend, CONFIG_LOG_DOMAIN_ID,
  96. i, false);
  97. shell_fprintf(shell, SHELL_NORMAL, "%-40s | %-7s | %s\r\n",
  98. log_source_name_get(CONFIG_LOG_DOMAIN_ID, i),
  99. severity_lvls[dynamic_lvl],
  100. severity_lvls[compiled_lvl]);
  101. }
  102. return 0;
  103. }
  104. static int cmd_log_self_status(const struct shell *shell,
  105. size_t argc, char **argv)
  106. {
  107. if (!shell_state_precheck(shell)) {
  108. return 0;
  109. }
  110. log_status(shell, shell->log_backend->backend, argc, argv);
  111. return 0;
  112. }
  113. static int cmd_log_backend_status(const struct shell *shell,
  114. size_t argc, char **argv)
  115. {
  116. shell_backend_cmd_execute(shell, argc, argv, log_status);
  117. return 0;
  118. }
  119. static int module_id_get(const char *name)
  120. {
  121. uint32_t modules_cnt = log_sources_count();
  122. const char *tmp_name;
  123. uint32_t i;
  124. for (i = 0U; i < modules_cnt; i++) {
  125. tmp_name = log_source_name_get(CONFIG_LOG_DOMAIN_ID, i);
  126. if (strncmp(tmp_name, name, 64) == 0) {
  127. return i;
  128. }
  129. }
  130. return -1;
  131. }
  132. static void filters_set(const struct shell *shell,
  133. const struct log_backend *backend,
  134. size_t argc, char **argv, uint32_t level)
  135. {
  136. int i;
  137. int id;
  138. bool all = argc ? false : true;
  139. int cnt = all ? log_sources_count() : argc;
  140. if (!backend->cb->active) {
  141. shell_warn(shell, "Backend not active.");
  142. }
  143. for (i = 0; i < cnt; i++) {
  144. id = all ? i : module_id_get(argv[i]);
  145. if (id >= 0) {
  146. uint32_t set_lvl = log_filter_set(backend,
  147. CONFIG_LOG_DOMAIN_ID,
  148. id, level);
  149. if (set_lvl != level) {
  150. const char *name;
  151. name = all ?
  152. log_source_name_get(
  153. CONFIG_LOG_DOMAIN_ID, i) :
  154. argv[i];
  155. shell_warn(shell, "%s: level set to %s.",
  156. name, severity_lvls[set_lvl]);
  157. }
  158. } else {
  159. shell_error(shell, "%s: unknown source name.", argv[i]);
  160. }
  161. }
  162. }
  163. static int severity_level_get(const char *str)
  164. {
  165. int i;
  166. for (i = 0; i < ARRAY_SIZE(severity_lvls); i++) {
  167. if (strncmp(str, severity_lvls[i], 4) == 0) {
  168. return i;
  169. }
  170. }
  171. return -1;
  172. }
  173. static int log_enable(const struct shell *shell,
  174. const struct log_backend *backend,
  175. size_t argc,
  176. char **argv)
  177. {
  178. int severity_level;
  179. severity_level = severity_level_get(argv[1]);
  180. if (severity_level < 0) {
  181. shell_error(shell, "Invalid severity: %s", argv[1]);
  182. return -ENOEXEC;
  183. }
  184. /* Arguments following severity level are interpreted as module names.*/
  185. filters_set(shell, backend, argc - 2, &argv[2], severity_level);
  186. return 0;
  187. }
  188. static int cmd_log_self_enable(const struct shell *shell,
  189. size_t argc, char **argv)
  190. {
  191. if (!shell_state_precheck(shell)) {
  192. return 0;
  193. }
  194. return log_enable(shell, shell->log_backend->backend, argc, argv);
  195. }
  196. static int cmd_log_backend_enable(const struct shell *shell,
  197. size_t argc, char **argv)
  198. {
  199. return shell_backend_cmd_execute(shell, argc, argv, log_enable);
  200. }
  201. static int log_disable(const struct shell *shell,
  202. const struct log_backend *backend,
  203. size_t argc,
  204. char **argv)
  205. {
  206. filters_set(shell, backend, argc - 1, &argv[1], LOG_LEVEL_NONE);
  207. return 0;
  208. }
  209. static int cmd_log_self_disable(const struct shell *shell,
  210. size_t argc, char **argv)
  211. {
  212. if (!shell_state_precheck(shell)) {
  213. return 0;
  214. }
  215. return log_disable(shell, shell->log_backend->backend, argc, argv);
  216. }
  217. static int cmd_log_backend_disable(const struct shell *shell,
  218. size_t argc, char **argv)
  219. {
  220. return shell_backend_cmd_execute(shell, argc, argv, log_disable);
  221. }
  222. static void module_name_get(size_t idx, struct shell_static_entry *entry);
  223. SHELL_DYNAMIC_CMD_CREATE(dsub_module_name, module_name_get);
  224. static void module_name_get(size_t idx, struct shell_static_entry *entry)
  225. {
  226. entry->handler = NULL;
  227. entry->help = NULL;
  228. entry->subcmd = &dsub_module_name;
  229. entry->syntax = log_source_name_get(CONFIG_LOG_DOMAIN_ID, idx);
  230. }
  231. static void severity_lvl_get(size_t idx, struct shell_static_entry *entry)
  232. {
  233. entry->handler = NULL;
  234. entry->help = NULL;
  235. entry->subcmd = &dsub_module_name;
  236. entry->syntax = (idx < ARRAY_SIZE(severity_lvls_sorted)) ?
  237. severity_lvls_sorted[idx] : NULL;
  238. }
  239. SHELL_DYNAMIC_CMD_CREATE(dsub_severity_lvl, severity_lvl_get);
  240. static int log_halt(const struct shell *shell,
  241. const struct log_backend *backend,
  242. size_t argc,
  243. char **argv)
  244. {
  245. log_backend_deactivate(backend);
  246. return 0;
  247. }
  248. static int cmd_log_self_halt(const struct shell *shell,
  249. size_t argc, char **argv)
  250. {
  251. if (!shell_state_precheck(shell)) {
  252. return 0;
  253. }
  254. return log_halt(shell, shell->log_backend->backend, argc, argv);
  255. }
  256. static int cmd_log_backend_halt(const struct shell *shell,
  257. size_t argc, char **argv)
  258. {
  259. return shell_backend_cmd_execute(shell, argc, argv, log_halt);
  260. }
  261. static int log_go(const struct shell *shell,
  262. const struct log_backend *backend,
  263. size_t argc,
  264. char **argv)
  265. {
  266. log_backend_activate(backend, backend->cb->ctx);
  267. return 0;
  268. }
  269. static int cmd_log_self_go(const struct shell *shell,
  270. size_t argc, char **argv)
  271. {
  272. if (!shell_state_precheck(shell)) {
  273. return 0;
  274. }
  275. return log_go(shell, shell->log_backend->backend, argc, argv);
  276. }
  277. static int cmd_log_backend_go(const struct shell *shell,
  278. size_t argc, char **argv)
  279. {
  280. return shell_backend_cmd_execute(shell, argc, argv, log_go);
  281. }
  282. static int cmd_log_backends_list(const struct shell *shell,
  283. size_t argc, char **argv)
  284. {
  285. int backend_count;
  286. backend_count = log_backend_count_get();
  287. for (int i = 0; i < backend_count; i++) {
  288. const struct log_backend *backend = log_backend_get(i);
  289. shell_fprintf(shell, SHELL_NORMAL,
  290. "%s\r\n"
  291. "\t- Status: %s\r\n"
  292. "\t- ID: %d\r\n\r\n",
  293. backend->name,
  294. backend->cb->active ? "enabled" : "disabled",
  295. backend->cb->id);
  296. }
  297. return 0;
  298. }
  299. static int cmd_log_strdup_utilization(const struct shell *shell,
  300. size_t argc, char **argv)
  301. {
  302. /* Defines needed when string duplication is disabled (LOG_IMMEDIATE is
  303. * on). In that case, this function is not compiled in.
  304. */
  305. #ifndef CONFIG_LOG_STRDUP_BUF_COUNT
  306. #define CONFIG_LOG_STRDUP_BUF_COUNT 0
  307. #endif
  308. #ifndef CONFIG_LOG_STRDUP_MAX_STRING
  309. #define CONFIG_LOG_STRDUP_MAX_STRING 0
  310. #endif
  311. uint32_t cur_cnt = log_get_strdup_pool_current_utilization();
  312. uint32_t buf_cnt = log_get_strdup_pool_utilization();
  313. uint32_t buf_size = log_get_strdup_longest_string();
  314. uint32_t percent = CONFIG_LOG_STRDUP_BUF_COUNT ?
  315. buf_cnt * 100U / CONFIG_LOG_STRDUP_BUF_COUNT : 0U;
  316. shell_print(shell, "Current utilization of the buffer pool: %d.",
  317. cur_cnt);
  318. shell_print(shell,
  319. "Maximal utilization of the buffer pool: %d / %d (%d %%).",
  320. buf_cnt, CONFIG_LOG_STRDUP_BUF_COUNT, percent);
  321. if (buf_cnt == CONFIG_LOG_STRDUP_BUF_COUNT) {
  322. shell_warn(shell, "Buffer count too small.");
  323. }
  324. shell_print(shell,
  325. "Longest duplicated string: %d, buffer capacity: %d.",
  326. buf_size, CONFIG_LOG_STRDUP_MAX_STRING);
  327. if (buf_size > CONFIG_LOG_STRDUP_MAX_STRING) {
  328. shell_warn(shell, "Buffer size too small.");
  329. }
  330. return 0;
  331. }
  332. static int cmd_log_memory_slabs(const struct shell *sh, size_t argc, char **argv)
  333. {
  334. uint32_t slabs_free;
  335. uint32_t used;
  336. uint32_t max;
  337. slabs_free = log_msg_mem_get_free();
  338. used = log_msg_mem_get_used();
  339. shell_print(sh, "Blocks used:\t%d", used);
  340. shell_print(sh, "Blocks free:\t%d", slabs_free);
  341. if (IS_ENABLED(CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION)) {
  342. max = log_msg_mem_get_max_used();
  343. shell_print(sh, "Blocks max:\t%d", max);
  344. } else {
  345. shell_print(
  346. sh,
  347. "Enable CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION to get max memory utilization");
  348. }
  349. return 0;
  350. }
  351. SHELL_STATIC_SUBCMD_SET_CREATE(sub_log_backend,
  352. SHELL_CMD_ARG(disable, &dsub_module_name,
  353. "'log disable <module_0> .. <module_n>' disables logs in "
  354. "specified modules (all if no modules specified).",
  355. cmd_log_backend_disable, 2, 255),
  356. SHELL_CMD_ARG(enable, &dsub_severity_lvl,
  357. "'log enable <level> <module_0> ... <module_n>' enables logs"
  358. " up to given level in specified modules (all if no modules "
  359. "specified).",
  360. cmd_log_backend_enable, 2, 255),
  361. SHELL_CMD(go, NULL, "Resume logging", cmd_log_backend_go),
  362. SHELL_CMD(halt, NULL, "Halt logging", cmd_log_backend_halt),
  363. SHELL_CMD(status, NULL, "Logger status", cmd_log_backend_status),
  364. SHELL_SUBCMD_SET_END
  365. );
  366. static void backend_name_get(size_t idx, struct shell_static_entry *entry)
  367. {
  368. entry->handler = NULL;
  369. entry->help = NULL;
  370. entry->subcmd = &sub_log_backend;
  371. entry->syntax = NULL;
  372. if (idx < log_backend_count_get()) {
  373. const struct log_backend *backend = log_backend_get(idx);
  374. entry->syntax = backend->name;
  375. }
  376. }
  377. SHELL_DYNAMIC_CMD_CREATE(dsub_backend_name_dynamic, backend_name_get);
  378. SHELL_STATIC_SUBCMD_SET_CREATE(
  379. sub_log_stat,
  380. SHELL_CMD(backend, &dsub_backend_name_dynamic, "Logger backends commands.", NULL),
  381. SHELL_COND_CMD_ARG(CONFIG_SHELL_LOG_BACKEND, disable, &dsub_module_name,
  382. "'log disable <module_0> .. <module_n>' disables logs in specified "
  383. "modules (all if no modules specified).",
  384. cmd_log_self_disable, 1, 255),
  385. SHELL_COND_CMD_ARG(CONFIG_SHELL_LOG_BACKEND, enable, &dsub_severity_lvl,
  386. "'log enable <level> <module_0> ... <module_n>' enables logs up to"
  387. " given level in specified modules (all if no modules specified).",
  388. cmd_log_self_enable, 2, 255),
  389. SHELL_COND_CMD(CONFIG_SHELL_LOG_BACKEND, go, NULL, "Resume logging", cmd_log_self_go),
  390. SHELL_COND_CMD(CONFIG_SHELL_LOG_BACKEND, halt, NULL, "Halt logging", cmd_log_self_halt),
  391. SHELL_CMD_ARG(list_backends, NULL, "Lists logger backends.", cmd_log_backends_list, 1, 0),
  392. SHELL_COND_CMD(CONFIG_SHELL_LOG_BACKEND, status, NULL, "Logger status",
  393. cmd_log_self_status),
  394. SHELL_COND_CMD_ARG(CONFIG_LOG_STRDUP_POOL_PROFILING, strdup_utilization, NULL,
  395. "Get utilization of string duplicates pool", cmd_log_strdup_utilization,
  396. 1, 0),
  397. SHELL_COND_CMD(CONFIG_LOG_MODE_DEFERRED, mem, NULL, "Logger memory usage",
  398. cmd_log_memory_slabs),
  399. SHELL_SUBCMD_SET_END);
  400. SHELL_CMD_REGISTER(log, &sub_log_stat, "Commands for controlling logger",
  401. NULL);