logger.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. TLoggingAnchor* NextAnchor = nullptr;
  34. ::TSourceLocation SourceLocation = {TStringBuf{}, 0};
  35. TString AnchorMessage;
  36. std::atomic<int> CurrentVersion = 0;
  37. std::atomic<bool> Suppressed = false;
  38. std::atomic<std::optional<ELogLevel>> LevelOverride;
  39. static_assert(decltype(LevelOverride)::is_always_lock_free);
  40. struct TCounter
  41. {
  42. i64 Current = 0;
  43. i64 Previous = 0;
  44. };
  45. TCounter MessageCounter;
  46. TCounter ByteCounter;
  47. };
  48. ////////////////////////////////////////////////////////////////////////////////
  49. // Declare some type aliases to avoid circular dependencies.
  50. using TThreadId = size_t;
  51. using TFiberId = size_t;
  52. using TTraceId = TGuid;
  53. using TRequestId = TGuid;
  54. ////////////////////////////////////////////////////////////////////////////////
  55. DEFINE_ENUM(ELogMessageKind,
  56. (Unstructured)
  57. (Structured)
  58. );
  59. struct TLogEvent
  60. {
  61. const TLoggingCategory* Category = nullptr;
  62. ELogLevel Level = ELogLevel::Minimum;
  63. ELogFamily Family = ELogFamily::PlainText;
  64. bool Essential = false;
  65. ELogMessageKind MessageKind = ELogMessageKind::Unstructured;
  66. TSharedRef MessageRef;
  67. TCpuInstant Instant = 0;
  68. TThreadId ThreadId = {};
  69. TThreadName ThreadName = {};
  70. TFiberId FiberId = {};
  71. TTraceId TraceId;
  72. TRequestId RequestId;
  73. TStringBuf SourceFile;
  74. int SourceLine = -1;
  75. TLoggingAnchor* Anchor = nullptr;
  76. };
  77. ////////////////////////////////////////////////////////////////////////////////
  78. struct ILogManager
  79. {
  80. virtual ~ILogManager() = default;
  81. virtual void RegisterStaticAnchor(
  82. TLoggingAnchor* anchor,
  83. ::TSourceLocation sourceLocation,
  84. TStringBuf anchorMessage) = 0;
  85. virtual void UpdateAnchor(TLoggingAnchor* anchor) = 0;
  86. virtual void Enqueue(TLogEvent&& event) = 0;
  87. virtual const TLoggingCategory* GetCategory(TStringBuf categoryName) = 0;
  88. virtual void UpdateCategory(TLoggingCategory* category) = 0;
  89. virtual bool GetAbortOnAlert() const = 0;
  90. };
  91. ILogManager* GetDefaultLogManager();
  92. ////////////////////////////////////////////////////////////////////////////////
  93. struct TLoggingContext
  94. {
  95. TCpuInstant Instant;
  96. TThreadId ThreadId;
  97. TThreadName ThreadName;
  98. TFiberId FiberId;
  99. TTraceId TraceId;
  100. TRequestId RequestId;
  101. TStringBuf TraceLoggingTag;
  102. };
  103. TLoggingContext GetLoggingContext();
  104. ////////////////////////////////////////////////////////////////////////////////
  105. //! Sets the minimum logging level for messages in current thread.
  106. // NB: In fiber environment, min log level is attached to a fiber,
  107. // so after context switch thread min log level might change.
  108. void SetThreadMinLogLevel(ELogLevel minLogLevel);
  109. ELogLevel GetThreadMinLogLevel();
  110. ////////////////////////////////////////////////////////////////////////////////
  111. static constexpr auto NullLoggerMinLevel = ELogLevel::Maximum;
  112. // Min level for non-null logger depends on whether we are in debug or release build.
  113. // - For release mode default behavior is to omit trace logging,
  114. // this is done by setting logger min level to Debug by default.
  115. // - For debug mode logger min level is set to trace by default, so that trace logging is
  116. // allowed by logger, but still may be discarded by category min level.
  117. #ifdef NDEBUG
  118. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Debug;
  119. #else
  120. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Trace;
  121. #endif
  122. class TLogger
  123. {
  124. public:
  125. using TStructuredValidator = std::function<void(const NYson::TYsonString&)>;
  126. using TStructuredValidators = std::vector<TStructuredValidator>;
  127. using TStructuredTag = std::pair<std::string, NYson::TYsonString>;
  128. // TODO(max42): switch to TCompactVector after YT-15430.
  129. using TStructuredTags = std::vector<TStructuredTag>;
  130. TLogger() = default;
  131. TLogger(const TLogger& other) = default;
  132. TLogger& operator=(const TLogger& other) = default;
  133. TLogger(ILogManager* logManager, TStringBuf categoryName);
  134. explicit TLogger(TStringBuf categoryName);
  135. explicit operator bool() const;
  136. //! Enables using |Logger| in YT_LOG_* macros as both data members and functions
  137. //! (e.g. those introduced by YT_DEFINE_GLOBAL).
  138. const TLogger& operator()() const;
  139. const TLoggingCategory* GetCategory() const;
  140. //! Combines given #level and the override from #anchor.
  141. static ELogLevel GetEffectiveLoggingLevel(ELogLevel level, const TLoggingAnchor& anchor);
  142. //! Validate that level is admitted by logger's own min level
  143. //! and by category's min level.
  144. bool IsLevelEnabled(ELogLevel level) const;
  145. bool GetAbortOnAlert() const;
  146. bool IsEssential() const;
  147. bool IsAnchorUpToDate(const TLoggingAnchor& anchor) const;
  148. void UpdateStaticAnchor(
  149. TLoggingAnchor* anchor,
  150. std::atomic<bool>* anchorRegistered,
  151. ::TSourceLocation sourceLocation,
  152. TStringBuf message) const;
  153. void UpdateDynamicAnchor(TLoggingAnchor* anchor) const;
  154. void Write(TLogEvent&& event) const;
  155. void AddRawTag(const std::string& tag);
  156. template <class... TArgs>
  157. void AddTag(const char* format, TArgs&&... args);
  158. template <class TType>
  159. void AddStructuredTag(TStringBuf key, TType value);
  160. void AddStructuredValidator(TStructuredValidator validator);
  161. TLogger WithRawTag(const std::string& tag) const;
  162. template <class... TArgs>
  163. TLogger WithTag(const char* format, TArgs&&... args) const;
  164. template <class TType>
  165. TLogger WithStructuredTag(TStringBuf key, TType value) const;
  166. TLogger WithStructuredValidator(TStructuredValidator validator) const;
  167. TLogger WithMinLevel(ELogLevel minLevel) const;
  168. TLogger WithEssential(bool essential = true) const;
  169. const std::string& GetTag() const;
  170. const TStructuredTags& GetStructuredTags() const;
  171. const TStructuredValidators& GetStructuredValidators() const;
  172. protected:
  173. // NB: Mind TSerializableLogger when changing the state.
  174. // These fields are set only during logger creation, so they are effectively const
  175. // and accessing them is thread-safe.
  176. ILogManager* LogManager_ = nullptr;
  177. const TLoggingCategory* Category_ = nullptr;
  178. bool Essential_ = false;
  179. ELogLevel MinLevel_ = NullLoggerMinLevel;
  180. struct TCoWState final
  181. {
  182. std::string Tag;
  183. TStructuredTags StructuredTags;
  184. TStructuredValidators StructuredValidators;
  185. };
  186. TIntrusivePtr<const TCoWState> CoWState_;
  187. TCoWState* GetMutableCoWState();
  188. void ResetCoWState();
  189. private:
  190. //! This method checks level against category's min level.
  191. //! Refer to comment in TLogger::IsLevelEnabled for more details.
  192. bool IsLevelEnabledHeavy(ELogLevel level) const;
  193. };
  194. ////////////////////////////////////////////////////////////////////////////////
  195. void LogStructuredEvent(
  196. const TLogger& logger,
  197. NYson::TYsonString message,
  198. ELogLevel level);
  199. ////////////////////////////////////////////////////////////////////////////////
  200. #ifdef YT_ENABLE_TRACE_LOGGING
  201. #define YT_LOG_TRACE(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Trace, __VA_ARGS__)
  202. #define YT_LOG_TRACE_IF(condition, ...) if (condition) YT_LOG_TRACE(__VA_ARGS__)
  203. #define YT_LOG_TRACE_UNLESS(condition, ...) if (!(condition)) YT_LOG_TRACE(__VA_ARGS__)
  204. #else
  205. #define YT_LOG_UNUSED(...) if (true) { } else { YT_LOG_DEBUG(__VA_ARGS__); }
  206. #define YT_LOG_TRACE(...) YT_LOG_UNUSED(__VA_ARGS__)
  207. #define YT_LOG_TRACE_IF(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  208. #define YT_LOG_TRACE_UNLESS(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  209. #endif
  210. #define YT_LOG_DEBUG(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Debug, __VA_ARGS__)
  211. #define YT_LOG_DEBUG_IF(condition, ...) if (condition) YT_LOG_DEBUG(__VA_ARGS__)
  212. #define YT_LOG_DEBUG_UNLESS(condition, ...) if (!(condition)) YT_LOG_DEBUG(__VA_ARGS__)
  213. #define YT_LOG_INFO(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Info, __VA_ARGS__)
  214. #define YT_LOG_INFO_IF(condition, ...) if (condition) YT_LOG_INFO(__VA_ARGS__)
  215. #define YT_LOG_INFO_UNLESS(condition, ...) if (!(condition)) YT_LOG_INFO(__VA_ARGS__)
  216. #define YT_LOG_WARNING(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Warning, __VA_ARGS__)
  217. #define YT_LOG_WARNING_IF(condition, ...) if (condition) YT_LOG_WARNING(__VA_ARGS__)
  218. #define YT_LOG_WARNING_UNLESS(condition, ...) if (!(condition)) YT_LOG_WARNING(__VA_ARGS__)
  219. #define YT_LOG_ERROR(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Error, __VA_ARGS__)
  220. #define YT_LOG_ERROR_IF(condition, ...) if (condition) YT_LOG_ERROR(__VA_ARGS__)
  221. #define YT_LOG_ERROR_UNLESS(condition, ...) if (!(condition)) YT_LOG_ERROR(__VA_ARGS__)
  222. #define YT_LOG_ALERT(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Alert, __VA_ARGS__);
  223. #define YT_LOG_ALERT_IF(condition, ...) if (condition) YT_LOG_ALERT(__VA_ARGS__)
  224. #define YT_LOG_ALERT_UNLESS(condition, ...) if (!(condition)) YT_LOG_ALERT(__VA_ARGS__)
  225. #define YT_LOG_FATAL(...) \
  226. do { \
  227. YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Fatal, __VA_ARGS__); \
  228. Y_UNREACHABLE(); \
  229. } while(false)
  230. #define YT_LOG_FATAL_IF(condition, ...) if (Y_UNLIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  231. #define YT_LOG_FATAL_UNLESS(condition, ...) if (!Y_LIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  232. #define YT_LOG_EVENT(logger, level, ...) \
  233. do { \
  234. const auto& logger__ = (logger)(); \
  235. auto level__ = (level); \
  236. auto location__ = __LOCATION__; \
  237. static ::NYT::TLeakyStorage<::NYT::NLogging::TLoggingAnchor> anchorStorage__; \
  238. auto* anchor__ = anchorStorage__.Get(); \
  239. \
  240. bool anchorUpToDate__ = logger__.IsAnchorUpToDate(*anchor__); \
  241. [[likely]] if (anchorUpToDate__) { \
  242. auto effectiveLevel__ = ::NYT::NLogging::TLogger::GetEffectiveLoggingLevel(level__, *anchor__); \
  243. if (!logger__.IsLevelEnabled(effectiveLevel__)) { \
  244. break; \
  245. } \
  246. } \
  247. \
  248. auto loggingContext__ = ::NYT::NLogging::GetLoggingContext(); \
  249. auto message__ = ::NYT::NLogging::NDetail::BuildLogMessage(loggingContext__, logger__, __VA_ARGS__); \
  250. \
  251. [[unlikely]] if (!anchorUpToDate__) { \
  252. static std::atomic<bool> anchorRegistered__; \
  253. logger__.UpdateStaticAnchor(anchor__, &anchorRegistered__, location__, message__.Anchor); \
  254. } \
  255. \
  256. auto effectiveLevel__ = ::NYT::NLogging::TLogger::GetEffectiveLoggingLevel(level__, *anchor__); \
  257. if (!logger__.IsLevelEnabled(effectiveLevel__)) { \
  258. break; \
  259. } \
  260. \
  261. ::NYT::NLogging::NDetail::LogEventImpl( \
  262. loggingContext__, \
  263. logger__, \
  264. effectiveLevel__, \
  265. location__, \
  266. anchor__, \
  267. std::move(message__.MessageRef)); \
  268. } while (false)
  269. #define YT_LOG_EVENT_WITH_DYNAMIC_ANCHOR(logger, level, anchor, ...) \
  270. do { \
  271. const auto& logger__ = (logger)(); \
  272. auto level__ = (level); \
  273. auto location__ = __LOCATION__; \
  274. auto* anchor__ = (anchor); \
  275. \
  276. bool anchorUpToDate__ = logger__.IsAnchorUpToDate(*anchor__); \
  277. [[unlikely]] if (!anchorUpToDate__) { \
  278. logger__.UpdateDynamicAnchor(anchor__); \
  279. } \
  280. \
  281. auto effectiveLevel__ = ::NYT::NLogging::TLogger::GetEffectiveLoggingLevel(level__, *anchor__); \
  282. if (!logger__.IsLevelEnabled(effectiveLevel__)) { \
  283. break; \
  284. } \
  285. \
  286. auto loggingContext__ = ::NYT::NLogging::GetLoggingContext(); \
  287. auto message__ = ::NYT::NLogging::NDetail::BuildLogMessage(loggingContext__, logger__, __VA_ARGS__); \
  288. \
  289. ::NYT::NLogging::NDetail::LogEventImpl( \
  290. loggingContext__, \
  291. logger__, \
  292. effectiveLevel__, \
  293. location__, \
  294. anchor__, \
  295. std::move(message__.MessageRef)); \
  296. } while (false)
  297. ////////////////////////////////////////////////////////////////////////////////
  298. } // namespace NYT::NLogging
  299. #define LOGGER_INL_H_
  300. #include "logger-inl.h"
  301. #undef LOGGER_INL_H_