logger.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #pragma once
  2. #include "public.h"
  3. #include <library/cpp/yt/string/format.h>
  4. #include <library/cpp/yt/memory/ref.h>
  5. #include <library/cpp/yt/cpu_clock/public.h>
  6. #include <library/cpp/yt/yson_string/string.h>
  7. #include <library/cpp/yt/misc/guid.h>
  8. #include <library/cpp/yt/misc/thread_name.h>
  9. #include <library/cpp/yt/memory/leaky_singleton.h>
  10. #include <util/system/src_location.h>
  11. #include <util/generic/size_literals.h>
  12. #include <atomic>
  13. namespace NYT::NLogging {
  14. ////////////////////////////////////////////////////////////////////////////////
  15. constexpr double DefaultStructuredValidationSamplingRate = 0.01;
  16. struct TLoggingCategory
  17. {
  18. TString Name;
  19. //! This value is used for early dropping of plaintext events in order
  20. //! to reduce load on logging thread for events which are definitely going
  21. //! to be dropped due to rule setup.
  22. //! NB: this optimization is used only for plaintext events since structured
  23. //! logging rate is negligible comparing to the plaintext logging rate.
  24. std::atomic<ELogLevel> MinPlainTextLevel;
  25. std::atomic<int> CurrentVersion;
  26. std::atomic<int>* ActualVersion;
  27. std::atomic<double> StructuredValidationSamplingRate = DefaultStructuredValidationSamplingRate;
  28. };
  29. ////////////////////////////////////////////////////////////////////////////////
  30. struct TLoggingAnchor
  31. {
  32. std::atomic<bool> Registered = false;
  33. ::TSourceLocation SourceLocation = {TStringBuf{}, 0};
  34. TString AnchorMessage;
  35. TLoggingAnchor* NextAnchor = nullptr;
  36. std::atomic<int> CurrentVersion = 0;
  37. std::atomic<bool> Enabled = false;
  38. struct TCounter
  39. {
  40. i64 Current = 0;
  41. i64 Previous = 0;
  42. };
  43. TCounter MessageCounter;
  44. TCounter ByteCounter;
  45. };
  46. ////////////////////////////////////////////////////////////////////////////////
  47. // Declare some type aliases to avoid circular dependencies.
  48. using TThreadId = size_t;
  49. using TFiberId = size_t;
  50. using TTraceId = TGuid;
  51. using TRequestId = TGuid;
  52. ////////////////////////////////////////////////////////////////////////////////
  53. DEFINE_ENUM(ELogMessageKind,
  54. (Unstructured)
  55. (Structured)
  56. );
  57. struct TLogEvent
  58. {
  59. const TLoggingCategory* Category = nullptr;
  60. ELogLevel Level = ELogLevel::Minimum;
  61. ELogFamily Family = ELogFamily::PlainText;
  62. bool Essential = false;
  63. ELogMessageKind MessageKind = ELogMessageKind::Unstructured;
  64. TSharedRef MessageRef;
  65. TCpuInstant Instant = 0;
  66. TThreadId ThreadId = {};
  67. TThreadName ThreadName = {};
  68. TFiberId FiberId = {};
  69. TTraceId TraceId;
  70. TRequestId RequestId;
  71. TStringBuf SourceFile;
  72. int SourceLine = -1;
  73. TLoggingAnchor* Anchor = nullptr;
  74. };
  75. ////////////////////////////////////////////////////////////////////////////////
  76. struct ILogManager
  77. {
  78. virtual ~ILogManager() = default;
  79. virtual void RegisterStaticAnchor(
  80. TLoggingAnchor* anchor,
  81. ::TSourceLocation sourceLocation,
  82. TStringBuf anchorMessage) = 0;
  83. virtual void UpdateAnchor(TLoggingAnchor* anchor) = 0;
  84. virtual void Enqueue(TLogEvent&& event) = 0;
  85. virtual const TLoggingCategory* GetCategory(TStringBuf categoryName) = 0;
  86. virtual void UpdateCategory(TLoggingCategory* category) = 0;
  87. virtual bool GetAbortOnAlert() const = 0;
  88. };
  89. ILogManager* GetDefaultLogManager();
  90. ////////////////////////////////////////////////////////////////////////////////
  91. struct TLoggingContext
  92. {
  93. TCpuInstant Instant;
  94. TThreadId ThreadId;
  95. TThreadName ThreadName;
  96. TFiberId FiberId;
  97. TTraceId TraceId;
  98. TRequestId RequestId;
  99. TStringBuf TraceLoggingTag;
  100. };
  101. TLoggingContext GetLoggingContext();
  102. ////////////////////////////////////////////////////////////////////////////////
  103. //! Sets the minimum logging level for messages in current thread.
  104. // NB: In fiber environment, min log level is attached to a fiber,
  105. // so after context switch thread min log level might change.
  106. void SetThreadMinLogLevel(ELogLevel minLogLevel);
  107. ELogLevel GetThreadMinLogLevel();
  108. ////////////////////////////////////////////////////////////////////////////////
  109. static constexpr auto NullLoggerMinLevel = ELogLevel::Maximum;
  110. // Min level for non-null logger depends on whether we are in debug or release build.
  111. // - For release mode default behavior is to omit trace logging,
  112. // this is done by setting logger min level to Debug by default.
  113. // - For debug mode logger min level is set to trace by default, so that trace logging is
  114. // allowed by logger, but still may be discarded by category min level.
  115. #ifdef NDEBUG
  116. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Debug;
  117. #else
  118. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Trace;
  119. #endif
  120. class TLogger
  121. {
  122. public:
  123. using TStructuredValidator = std::function<void(const NYson::TYsonString&)>;
  124. using TStructuredValidators = std::vector<TStructuredValidator>;
  125. using TStructuredTag = std::pair<TString, NYson::TYsonString>;
  126. // TODO(max42): switch to TCompactVector after YT-15430.
  127. using TStructuredTags = std::vector<TStructuredTag>;
  128. TLogger() = default;
  129. TLogger(const TLogger& other) = default;
  130. TLogger& operator=(const TLogger& other) = default;
  131. TLogger(ILogManager* logManager, TStringBuf categoryName);
  132. explicit TLogger(TStringBuf categoryName);
  133. explicit operator bool() const;
  134. //! Enables using |Logger| in YT_LOG_* macros as both data members and functions
  135. //! (e.g. those introduced by YT_DEFINE_GLOBAL).
  136. const TLogger& operator()() const;
  137. const TLoggingCategory* GetCategory() const;
  138. //! Validate that level is admitted by logger's own min level
  139. //! and by category's min level.
  140. bool IsLevelEnabled(ELogLevel level) const;
  141. bool GetAbortOnAlert() const;
  142. bool IsEssential() const;
  143. bool IsAnchorUpToDate(const TLoggingAnchor& anchor) const;
  144. void UpdateAnchor(TLoggingAnchor* anchor) const;
  145. void RegisterStaticAnchor(TLoggingAnchor* anchor, ::TSourceLocation sourceLocation, TStringBuf message) const;
  146. void Write(TLogEvent&& event) const;
  147. void AddRawTag(const TString& tag);
  148. template <class... TArgs>
  149. void AddTag(const char* format, TArgs&&... args);
  150. template <class TType>
  151. void AddStructuredTag(TStringBuf key, TType value);
  152. TLogger WithRawTag(const TString& tag) const;
  153. template <class... TArgs>
  154. TLogger WithTag(const char* format, TArgs&&... args) const;
  155. template <class TType>
  156. TLogger WithStructuredTag(TStringBuf key, TType value) const;
  157. TLogger WithStructuredValidator(TStructuredValidator validator) const;
  158. TLogger WithMinLevel(ELogLevel minLevel) const;
  159. TLogger WithEssential(bool essential = true) const;
  160. const TString& GetTag() const;
  161. const TStructuredTags& GetStructuredTags() const;
  162. const TStructuredValidators& GetStructuredValidators() const;
  163. protected:
  164. // These fields are set only during logger creation, so they are effectively const
  165. // and accessing them is thread-safe.
  166. ILogManager* LogManager_ = nullptr;
  167. const TLoggingCategory* Category_ = nullptr;
  168. bool Essential_ = false;
  169. ELogLevel MinLevel_ = NullLoggerMinLevel;
  170. TString Tag_;
  171. TStructuredTags StructuredTags_;
  172. TStructuredValidators StructuredValidators_;
  173. private:
  174. //! This method checks level against category's min level.
  175. //! Refer to comment in TLogger::IsLevelEnabled for more details.
  176. bool IsLevelEnabledHeavy(ELogLevel level) const;
  177. };
  178. ////////////////////////////////////////////////////////////////////////////////
  179. void LogStructuredEvent(
  180. const TLogger& logger,
  181. NYson::TYsonString message,
  182. ELogLevel level);
  183. ////////////////////////////////////////////////////////////////////////////////
  184. #ifdef YT_ENABLE_TRACE_LOGGING
  185. #define YT_LOG_TRACE(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Trace, __VA_ARGS__)
  186. #define YT_LOG_TRACE_IF(condition, ...) if (condition) YT_LOG_TRACE(__VA_ARGS__)
  187. #define YT_LOG_TRACE_UNLESS(condition, ...) if (!(condition)) YT_LOG_TRACE(__VA_ARGS__)
  188. #else
  189. #define YT_LOG_UNUSED(...) if (true) { } else { YT_LOG_DEBUG(__VA_ARGS__); }
  190. #define YT_LOG_TRACE(...) YT_LOG_UNUSED(__VA_ARGS__)
  191. #define YT_LOG_TRACE_IF(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  192. #define YT_LOG_TRACE_UNLESS(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  193. #endif
  194. #define YT_LOG_DEBUG(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Debug, __VA_ARGS__)
  195. #define YT_LOG_DEBUG_IF(condition, ...) if (condition) YT_LOG_DEBUG(__VA_ARGS__)
  196. #define YT_LOG_DEBUG_UNLESS(condition, ...) if (!(condition)) YT_LOG_DEBUG(__VA_ARGS__)
  197. #define YT_LOG_INFO(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Info, __VA_ARGS__)
  198. #define YT_LOG_INFO_IF(condition, ...) if (condition) YT_LOG_INFO(__VA_ARGS__)
  199. #define YT_LOG_INFO_UNLESS(condition, ...) if (!(condition)) YT_LOG_INFO(__VA_ARGS__)
  200. #define YT_LOG_WARNING(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Warning, __VA_ARGS__)
  201. #define YT_LOG_WARNING_IF(condition, ...) if (condition) YT_LOG_WARNING(__VA_ARGS__)
  202. #define YT_LOG_WARNING_UNLESS(condition, ...) if (!(condition)) YT_LOG_WARNING(__VA_ARGS__)
  203. #define YT_LOG_ERROR(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Error, __VA_ARGS__)
  204. #define YT_LOG_ERROR_IF(condition, ...) if (condition) YT_LOG_ERROR(__VA_ARGS__)
  205. #define YT_LOG_ERROR_UNLESS(condition, ...) if (!(condition)) YT_LOG_ERROR(__VA_ARGS__)
  206. #define YT_LOG_ALERT(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Alert, __VA_ARGS__);
  207. #define YT_LOG_ALERT_IF(condition, ...) if (condition) YT_LOG_ALERT(__VA_ARGS__)
  208. #define YT_LOG_ALERT_UNLESS(condition, ...) if (!(condition)) YT_LOG_ALERT(__VA_ARGS__)
  209. #define YT_LOG_FATAL(...) \
  210. do { \
  211. YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Fatal, __VA_ARGS__); \
  212. Y_UNREACHABLE(); \
  213. } while(false)
  214. #define YT_LOG_FATAL_IF(condition, ...) if (Y_UNLIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  215. #define YT_LOG_FATAL_UNLESS(condition, ...) if (!Y_LIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  216. #define YT_LOG_EVENT(logger, level, ...) \
  217. YT_LOG_EVENT_WITH_ANCHOR(logger, level, nullptr, __VA_ARGS__)
  218. #define YT_LOG_EVENT_WITH_ANCHOR(logger, level, anchor, ...) \
  219. do { \
  220. const auto& logger__ = (logger)(); \
  221. auto level__ = (level); \
  222. \
  223. if (!logger__.IsLevelEnabled(level__)) { \
  224. break; \
  225. } \
  226. \
  227. auto location__ = __LOCATION__; \
  228. \
  229. ::NYT::NLogging::TLoggingAnchor* anchor__ = (anchor); \
  230. if (!anchor__) { \
  231. static ::NYT::TLeakyStorage<::NYT::NLogging::TLoggingAnchor> staticAnchor__; \
  232. anchor__ = staticAnchor__.Get(); \
  233. } \
  234. \
  235. bool anchorUpToDate__ = logger__.IsAnchorUpToDate(*anchor__); \
  236. if (anchorUpToDate__ && !anchor__->Enabled.load(std::memory_order::relaxed)) { \
  237. break; \
  238. } \
  239. \
  240. auto loggingContext__ = ::NYT::NLogging::GetLoggingContext(); \
  241. auto message__ = ::NYT::NLogging::NDetail::BuildLogMessage(loggingContext__, logger__, __VA_ARGS__); \
  242. \
  243. if (!anchorUpToDate__) { \
  244. logger__.RegisterStaticAnchor(anchor__, location__, message__.Anchor); \
  245. logger__.UpdateAnchor(anchor__); \
  246. } \
  247. \
  248. if (!anchor__->Enabled.load(std::memory_order::relaxed)) { \
  249. break; \
  250. } \
  251. \
  252. ::NYT::NLogging::NDetail::LogEventImpl( \
  253. loggingContext__, \
  254. logger__, \
  255. level__, \
  256. location__, \
  257. anchor__, \
  258. std::move(message__.MessageRef)); \
  259. } while (false)
  260. ////////////////////////////////////////////////////////////////////////////////
  261. } // namespace NYT::NLogging
  262. #define LOGGER_INL_H_
  263. #include "logger-inl.h"
  264. #undef LOGGER_INL_H_