Logging.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Logging.h
  3. * ---------
  4. * Purpose: General logging
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "openmpt/logging/Logger.hpp"
  12. #include "mptPathString.h"
  13. #include "mptString.h"
  14. #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
  15. #include <atomic>
  16. #endif
  17. OPENMPT_NAMESPACE_BEGIN
  18. /*
  19. Build time logging configuration:
  20. * #define MPT_LOG_GLOBAL_LEVEL_STATIC
  21. #define MPT_LOG_GLOBAL_LEVEL #
  22. Define the former (to anything) and the latter (to one of the log levels
  23. below) in order to statically select the verbosity of logging at build time.
  24. MPT_LOG calls that exceed the specified logging level will get dead-code
  25. eliminated at compile time.
  26. This especially means that, when setting MPT_LOG_GLOBAL_LEVEL to 0, no
  27. MPT_LOG call (with a constant level parameter) remains in the resulting
  28. binary, however, they still do get parsed and properly type checked by the
  29. compiler.
  30. Logging:
  31. If the context is related to a particular CSoundfile instance, use
  32. CSoundfile::AddToLog.
  33. Logging a simple message:
  34. MPT_LOG_GLOBAL(LogWarning, "sounddev", "some message");
  35. MPT_LOG_GLOBAL(LogWarning, "sounddev", U_("some message"));
  36. Facility is some course grained code section identifier (more coarse grained
  37. than the current file name probably), useful to do some selective logging.
  38. Logging a more complex message:
  39. MPT_LOG_GLOBAL(LogWarning, "sounddev", MPT_UFORMAT("Some message: foo={}, bar=0x{}")(foo, mpt::ufmt::hex0<8>(bar)));
  40. Note that even with full enabled logging and a runtime configurable logging
  41. level, the runtime overhead of a MPT_LOG_GLOBAL(level, facility, text) call is just a
  42. single conditional in case the verbosity does not require logging the respective
  43. message. Even the expression "text" is not evaluated.
  44. */
  45. inline mpt::ustring LogLevelToString(LogLevel level)
  46. {
  47. switch(level)
  48. {
  49. case LogError: return U_("error"); break;
  50. case LogWarning: return U_("warning"); break;
  51. case LogNotification: return U_("notify"); break;
  52. case LogInformation: return U_("info"); break;
  53. case LogDebug: return U_("debug"); break;
  54. }
  55. return U_("unknown");
  56. }
  57. class ILog
  58. {
  59. protected:
  60. virtual ~ILog() { }
  61. public:
  62. virtual void AddToLog(LogLevel level, const mpt::ustring &text) const = 0;
  63. };
  64. namespace mpt
  65. {
  66. namespace log
  67. {
  68. #if defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
  69. #if (MPT_LOG_GLOBAL_LEVEL <= 0)
  70. // All logging has beeen statically disabled.
  71. // All logging code gets compiled and immediately dead-code eliminated.
  72. #define MPT_LOG_IS_DISABLED
  73. #endif
  74. inline constexpr int GlobalLogLevel = MPT_LOG_GLOBAL_LEVEL ;
  75. #else
  76. extern int GlobalLogLevel;
  77. #endif
  78. #if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED)
  79. extern bool FileEnabled;
  80. extern bool DebuggerEnabled;
  81. extern bool ConsoleEnabled;
  82. void SetFacilities(const std::string &solo, const std::string &blocked);
  83. bool IsFacilityActive(const char *facility) noexcept;
  84. #else
  85. MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) noexcept { return true; }
  86. #endif
  87. class GlobalLogger final
  88. : public ILogger
  89. {
  90. public:
  91. GlobalLogger() = default;
  92. ~GlobalLogger() final = default;
  93. public:
  94. bool IsLevelActive(LogLevel level) const noexcept override
  95. {
  96. return (mpt::log::GlobalLogLevel >= level);
  97. }
  98. bool IsFacilityActive(const char *facility) const noexcept override
  99. {
  100. return mpt::log::IsFacilityActive(facility);
  101. }
  102. void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &message) const override;
  103. };
  104. #define MPT_LOG_GLOBAL(level, facility, text) MPT_LOG(mpt::log::GlobalLogger{}, (level), (facility), (text))
  105. #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
  106. namespace Trace {
  107. // This is not strictly thread safe in all corner cases because of missing barriers.
  108. // We do not care in order to not harm the fast path with additional barriers.
  109. // Enabled tracing incurs a runtime overhead with multiple threads as a global atomic variable
  110. // gets modified.
  111. // This cacheline bouncing does not matter at all
  112. // if there are not multiple thread adding trace points at high frequency (way greater than 1000Hz),
  113. // which, in OpenMPT, is only ever the case for just a single thread (the audio thread), if at all.
  114. extern std::atomic<bool> g_Enabled;
  115. inline bool IsEnabled() { return g_Enabled; }
  116. enum class Direction : int8
  117. {
  118. Unknown = 0,
  119. Enter = 1,
  120. Leave = -1,
  121. };
  122. MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction = Direction::Unknown) noexcept;
  123. enum ThreadKind {
  124. ThreadKindGUI,
  125. ThreadKindAudio,
  126. ThreadKindNotify,
  127. ThreadKindWatchdir,
  128. };
  129. void Enable(std::size_t numEntries);
  130. void Disable();
  131. void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id);
  132. uint32 GetThreadId(mpt::log::Trace::ThreadKind kind);
  133. void Seal();
  134. bool Dump(const mpt::PathString &filename);
  135. class Scope
  136. {
  137. private:
  138. const mpt::source_location loc;
  139. public:
  140. MPT_FORCEINLINE Scope(mpt::source_location loc) noexcept
  141. : loc(loc)
  142. {
  143. if(mpt::log::Trace::g_Enabled)
  144. {
  145. mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Enter);
  146. }
  147. }
  148. MPT_FORCEINLINE ~Scope() noexcept
  149. {
  150. if(mpt::log::Trace::g_Enabled)
  151. {
  152. mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Leave);
  153. }
  154. }
  155. };
  156. #define MPT_TRACE_CONCAT_HELPER(x, y) x ## y
  157. #define MPT_TRACE_CONCAT(x, y) MPT_TRACE_CONCAT_HELPER(x, y)
  158. #define MPT_TRACE_SCOPE() mpt::log::Trace::Scope MPT_TRACE_CONCAT(MPT_TRACE_VAR, __LINE__)(MPT_SOURCE_LOCATION_CURRENT())
  159. #define MPT_TRACE() do { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_SOURCE_LOCATION_CURRENT()); } } while(0)
  160. } // namespace Trace
  161. #else // !MODPLUG_TRACKER
  162. #define MPT_TRACE_SCOPE() do { } while(0)
  163. #define MPT_TRACE() do { } while(0)
  164. #endif // MODPLUG_TRACKER
  165. } // namespace log
  166. } // namespace mpt
  167. OPENMPT_NAMESPACE_END