log_linked_list.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * This file implements a linked list-based approach for storing and retrieving
  8. * log tag levels in the ESP-IDF log library. It provides functions to set and
  9. * get log levels for specific tags using a linked list data structure. The
  10. * linked list stores log tags and their corresponding log levels as individual
  11. * nodes.
  12. *
  13. * The esp_log_linked_list_set_level() function allows users to set the log level
  14. * for a specific tag, and if the tag does not exist in the linked list, it adds
  15. * a new entry for that tag. The esp_log_linked_list_get_level() function
  16. * retrieves the log level for a given tag from the linked list. Please note that
  17. * this approach searches through the entire tag string to find a matching tag
  18. * during log level retrieval.
  19. *
  20. * The esp_log_linked_list_clean() function enables users to clear the entire linked
  21. * list, freeing the memory occupied by the list entries.
  22. *
  23. * The linked list approach provides a simple and memory-efficient method for
  24. * managing log levels, making it suitable for use in environments with limited
  25. * resources. However, due to its linear search nature, log level retrieval from
  26. * the linked list may become slower as the number of tags increases.
  27. */
  28. #include <string.h>
  29. #include "queue.h"
  30. #include "log_linked_list.h"
  31. typedef struct uncached_tag_entry_ {
  32. SLIST_ENTRY(uncached_tag_entry_) entries;
  33. uint8_t level; // esp_log_level_t as uint8_t
  34. char tag[0]; // beginning of a zero-terminated string
  35. } uncached_tag_entry_t;
  36. static SLIST_HEAD(log_tags_head, uncached_tag_entry_) s_log_tags = SLIST_HEAD_INITIALIZER(s_log_tags);
  37. static inline esp_err_t add_to_list(const char *tag, esp_log_level_t level);
  38. static inline bool set_log_level(const char *tag, esp_log_level_t level);
  39. bool esp_log_linked_list_set_level(const char *tag, esp_log_level_t level)
  40. {
  41. if (!set_log_level(tag, level)) {
  42. // no existing tag, append new one
  43. return add_to_list(tag, level) == ESP_OK;
  44. }
  45. return true;
  46. }
  47. // Getting the log level from linked list
  48. // if tag is not found then returns false.
  49. bool esp_log_linked_list_get_level(const char *tag, esp_log_level_t *level)
  50. {
  51. // Walk the linked list of all tags and see if given tag is present in the list.
  52. // This is slow because tags are compared as strings.
  53. uncached_tag_entry_t *it;
  54. SLIST_FOREACH(it, &s_log_tags, entries) {
  55. if (strcmp(tag, it->tag) == 0) {
  56. *level = (esp_log_level_t) it->level;
  57. return true;
  58. }
  59. }
  60. return false;
  61. }
  62. void esp_log_linked_list_clean(void)
  63. {
  64. uncached_tag_entry_t *it;
  65. while ((it = SLIST_FIRST(&s_log_tags)) != NULL) {
  66. SLIST_REMOVE_HEAD(&s_log_tags, entries);
  67. free(it);
  68. }
  69. }
  70. static inline esp_err_t add_to_list(const char *tag, esp_log_level_t level)
  71. {
  72. // allocate new linked list entry and append it to the head of the list
  73. size_t tag_len = strlen(tag) + 1;
  74. size_t entry_size = offsetof(uncached_tag_entry_t, tag) + tag_len;
  75. uncached_tag_entry_t *new_entry = (uncached_tag_entry_t *) malloc(entry_size);
  76. if (!new_entry) {
  77. return ESP_ERR_NO_MEM;
  78. }
  79. new_entry->level = (uint8_t) level;
  80. memcpy(new_entry->tag, tag, tag_len);
  81. SLIST_INSERT_HEAD(&s_log_tags, new_entry, entries);
  82. return ESP_OK;
  83. }
  84. static inline bool set_log_level(const char *tag, esp_log_level_t level)
  85. {
  86. // search for existing tag
  87. uncached_tag_entry_t *it = NULL;
  88. SLIST_FOREACH(it, &s_log_tags, entries) {
  89. if (strcmp(it->tag, tag) == 0) {
  90. // one tag in the linked list matched, update the level
  91. it->level = level;
  92. return true;
  93. }
  94. }
  95. return false;
  96. }