filter.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/logging/filter.h"
  6. #include "common/logging/backend.h"
  7. #include "common/string_util.h"
  8. namespace Log {
  9. Filter::Filter(Level default_level) {
  10. ResetAll(default_level);
  11. }
  12. void Filter::ResetAll(Level level) {
  13. class_levels.fill(level);
  14. }
  15. void Filter::SetClassLevel(Class log_class, Level level) {
  16. class_levels[static_cast<size_t>(log_class)] = level;
  17. }
  18. void Filter::SetSubclassesLevel(const ClassInfo& log_class, Level level) {
  19. const size_t log_class_i = static_cast<size_t>(log_class.log_class);
  20. const size_t begin = log_class_i + 1;
  21. const size_t end = begin + log_class.num_children;
  22. for (size_t i = begin; begin < end; ++i) {
  23. class_levels[i] = level;
  24. }
  25. }
  26. void Filter::ParseFilterString(const std::string& filter_str) {
  27. auto clause_begin = filter_str.cbegin();
  28. while (clause_begin != filter_str.cend()) {
  29. auto clause_end = std::find(clause_begin, filter_str.cend(), ' ');
  30. // If clause isn't empty
  31. if (clause_end != clause_begin) {
  32. ParseFilterRule(clause_begin, clause_end);
  33. }
  34. if (clause_end != filter_str.cend()) {
  35. // Skip over the whitespace
  36. ++clause_end;
  37. }
  38. clause_begin = clause_end;
  39. }
  40. }
  41. template <typename It>
  42. static Level GetLevelByName(const It begin, const It end) {
  43. for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {
  44. const char* level_name = Logger::GetLevelName(static_cast<Level>(i));
  45. if (Common::ComparePartialString(begin, end, level_name)) {
  46. return static_cast<Level>(i);
  47. }
  48. }
  49. return Level::Count;
  50. }
  51. template <typename It>
  52. static Class GetClassByName(const It begin, const It end) {
  53. for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {
  54. const char* level_name = Logger::GetLogClassName(static_cast<Class>(i));
  55. if (Common::ComparePartialString(begin, end, level_name)) {
  56. return static_cast<Class>(i);
  57. }
  58. }
  59. return Class::Count;
  60. }
  61. template <typename InputIt, typename T>
  62. static InputIt find_last(InputIt begin, const InputIt end, const T& value) {
  63. auto match = end;
  64. while (begin != end) {
  65. auto new_match = std::find(begin, end, value);
  66. if (new_match != end) {
  67. match = new_match;
  68. ++new_match;
  69. }
  70. begin = new_match;
  71. }
  72. return match;
  73. }
  74. bool Filter::ParseFilterRule(const std::string::const_iterator begin,
  75. const std::string::const_iterator end) {
  76. auto level_separator = std::find(begin, end, ':');
  77. if (level_separator == end) {
  78. LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
  79. std::string(begin, end).c_str());
  80. return false;
  81. }
  82. const Level level = GetLevelByName(level_separator + 1, end);
  83. if (level == Level::Count) {
  84. LOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
  85. return false;
  86. }
  87. if (Common::ComparePartialString(begin, level_separator, "*")) {
  88. ResetAll(level);
  89. return true;
  90. }
  91. auto class_name_end = find_last(begin, level_separator, '.');
  92. if (class_name_end != level_separator &&
  93. !Common::ComparePartialString(class_name_end + 1, level_separator, "*")) {
  94. class_name_end = level_separator;
  95. }
  96. const Class log_class = GetClassByName(begin, class_name_end);
  97. if (log_class == Class::Count) {
  98. LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
  99. return false;
  100. }
  101. if (class_name_end == level_separator) {
  102. SetClassLevel(log_class, level);
  103. }
  104. SetSubclassesLevel(log_class, level);
  105. return true;
  106. }
  107. bool Filter::CheckMessage(Class log_class, Level level) const {
  108. return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
  109. }
  110. }