backend.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/log.h" // For _dbg_assert_
  6. #include "common/logging/backend.h"
  7. #include "common/logging/log.h"
  8. #include "common/logging/text_formatter.h"
  9. namespace Log {
  10. static std::shared_ptr<Logger> global_logger;
  11. /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
  12. #define ALL_LOG_CLASSES() \
  13. CLS(Log) \
  14. CLS(Common) \
  15. SUB(Common, Filesystem) \
  16. SUB(Common, Memory) \
  17. CLS(Core) \
  18. SUB(Core, ARM11) \
  19. CLS(Config) \
  20. CLS(Debug) \
  21. SUB(Debug, Emulated) \
  22. SUB(Debug, GPU) \
  23. SUB(Debug, Breakpoint) \
  24. CLS(Kernel) \
  25. SUB(Kernel, SVC) \
  26. CLS(Service) \
  27. SUB(Service, SRV) \
  28. SUB(Service, FS) \
  29. SUB(Service, APT) \
  30. SUB(Service, GSP) \
  31. SUB(Service, AC) \
  32. SUB(Service, PTM) \
  33. SUB(Service, CFG) \
  34. SUB(Service, DSP) \
  35. SUB(Service, HID) \
  36. CLS(HW) \
  37. SUB(HW, Memory) \
  38. SUB(HW, GPU) \
  39. CLS(Frontend) \
  40. CLS(Render) \
  41. SUB(Render, Software) \
  42. SUB(Render, OpenGL) \
  43. CLS(Loader)
  44. Logger::Logger() {
  45. // Register logging classes so that they can be queried at runtime
  46. size_t parent_class;
  47. all_classes.reserve((size_t)Class::Count);
  48. #define CLS(x) \
  49. all_classes.push_back(Class::x); \
  50. parent_class = all_classes.size() - 1;
  51. #define SUB(x, y) \
  52. all_classes.push_back(Class::x##_##y); \
  53. all_classes[parent_class].num_children += 1;
  54. ALL_LOG_CLASSES()
  55. #undef CLS
  56. #undef SUB
  57. // Ensures that ALL_LOG_CLASSES isn't missing any entries.
  58. _dbg_assert_(Log, all_classes.size() == (size_t)Class::Count);
  59. }
  60. // GetClassName is a macro defined by Windows.h, grrr...
  61. const char* Logger::GetLogClassName(Class log_class) {
  62. switch (log_class) {
  63. #define CLS(x) case Class::x: return #x;
  64. #define SUB(x, y) case Class::x##_##y: return #x "." #y;
  65. ALL_LOG_CLASSES()
  66. #undef CLS
  67. #undef SUB
  68. }
  69. return "Unknown";
  70. }
  71. const char* Logger::GetLevelName(Level log_level) {
  72. #define LVL(x) case Level::x: return #x
  73. switch (log_level) {
  74. LVL(Trace);
  75. LVL(Debug);
  76. LVL(Info);
  77. LVL(Warning);
  78. LVL(Error);
  79. LVL(Critical);
  80. }
  81. return "Unknown";
  82. #undef LVL
  83. }
  84. void Logger::LogMessage(Entry entry) {
  85. ring_buffer.Push(std::move(entry));
  86. }
  87. size_t Logger::GetEntries(Entry* out_buffer, size_t buffer_len) {
  88. return ring_buffer.BlockingPop(out_buffer, buffer_len);
  89. }
  90. std::shared_ptr<Logger> InitGlobalLogger() {
  91. global_logger = std::make_shared<Logger>();
  92. return global_logger;
  93. }
  94. Entry CreateEntry(Class log_class, Level log_level,
  95. const char* filename, unsigned int line_nr, const char* function,
  96. const char* format, va_list args) {
  97. using std::chrono::steady_clock;
  98. using std::chrono::duration_cast;
  99. static steady_clock::time_point time_origin = steady_clock::now();
  100. std::array<char, 4 * 1024> formatting_buffer;
  101. Entry entry;
  102. entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
  103. entry.log_class = log_class;
  104. entry.log_level = log_level;
  105. snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr);
  106. entry.location = std::string(formatting_buffer.data());
  107. vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
  108. entry.message = std::string(formatting_buffer.data());
  109. return std::move(entry);
  110. }
  111. void LogMessage(Class log_class, Level log_level,
  112. const char* filename, unsigned int line_nr, const char* function,
  113. const char* format, ...) {
  114. va_list args;
  115. va_start(args, format);
  116. Entry entry = CreateEntry(log_class, log_level,
  117. filename, line_nr, function, format, args);
  118. va_end(args);
  119. if (global_logger != nullptr && !global_logger->IsClosed()) {
  120. global_logger->LogMessage(std::move(entry));
  121. } else {
  122. // Fall back to directly printing to stderr
  123. PrintMessage(entry);
  124. }
  125. }
  126. }