logger.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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<TString, 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 UpdateAnchor(TLoggingAnchor* anchor) const;
  149. void RegisterStaticAnchor(TLoggingAnchor* anchor, ::TSourceLocation sourceLocation, TStringBuf message) const;
  150. void Write(TLogEvent&& event) const;
  151. void AddRawTag(const TString& tag);
  152. template <class... TArgs>
  153. void AddTag(const char* format, TArgs&&... args);
  154. template <class TType>
  155. void AddStructuredTag(TStringBuf key, TType value);
  156. TLogger WithRawTag(const TString& tag) const;
  157. template <class... TArgs>
  158. TLogger WithTag(const char* format, TArgs&&... args) const;
  159. template <class TType>
  160. TLogger WithStructuredTag(TStringBuf key, TType value) const;
  161. TLogger WithStructuredValidator(TStructuredValidator validator) const;
  162. TLogger WithMinLevel(ELogLevel minLevel) const;
  163. TLogger WithEssential(bool essential = true) const;
  164. const TString& GetTag() const;
  165. const TStructuredTags& GetStructuredTags() const;
  166. const TStructuredValidators& GetStructuredValidators() const;
  167. protected:
  168. // These fields are set only during logger creation, so they are effectively const
  169. // and accessing them is thread-safe.
  170. ILogManager* LogManager_ = nullptr;
  171. const TLoggingCategory* Category_ = nullptr;
  172. bool Essential_ = false;
  173. ELogLevel MinLevel_ = NullLoggerMinLevel;
  174. TString Tag_;
  175. TStructuredTags StructuredTags_;
  176. TStructuredValidators StructuredValidators_;
  177. private:
  178. //! This method checks level against category's min level.
  179. //! Refer to comment in TLogger::IsLevelEnabled for more details.
  180. bool IsLevelEnabledHeavy(ELogLevel level) const;
  181. };
  182. ////////////////////////////////////////////////////////////////////////////////
  183. void LogStructuredEvent(
  184. const TLogger& logger,
  185. NYson::TYsonString message,
  186. ELogLevel level);
  187. ////////////////////////////////////////////////////////////////////////////////
  188. #ifdef YT_ENABLE_TRACE_LOGGING
  189. #define YT_LOG_TRACE(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Trace, __VA_ARGS__)
  190. #define YT_LOG_TRACE_IF(condition, ...) if (condition) YT_LOG_TRACE(__VA_ARGS__)
  191. #define YT_LOG_TRACE_UNLESS(condition, ...) if (!(condition)) YT_LOG_TRACE(__VA_ARGS__)
  192. #else
  193. #define YT_LOG_UNUSED(...) if (true) { } else { YT_LOG_DEBUG(__VA_ARGS__); }
  194. #define YT_LOG_TRACE(...) YT_LOG_UNUSED(__VA_ARGS__)
  195. #define YT_LOG_TRACE_IF(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  196. #define YT_LOG_TRACE_UNLESS(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  197. #endif
  198. #define YT_LOG_DEBUG(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Debug, __VA_ARGS__)
  199. #define YT_LOG_DEBUG_IF(condition, ...) if (condition) YT_LOG_DEBUG(__VA_ARGS__)
  200. #define YT_LOG_DEBUG_UNLESS(condition, ...) if (!(condition)) YT_LOG_DEBUG(__VA_ARGS__)
  201. #define YT_LOG_INFO(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Info, __VA_ARGS__)
  202. #define YT_LOG_INFO_IF(condition, ...) if (condition) YT_LOG_INFO(__VA_ARGS__)
  203. #define YT_LOG_INFO_UNLESS(condition, ...) if (!(condition)) YT_LOG_INFO(__VA_ARGS__)
  204. #define YT_LOG_WARNING(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Warning, __VA_ARGS__)
  205. #define YT_LOG_WARNING_IF(condition, ...) if (condition) YT_LOG_WARNING(__VA_ARGS__)
  206. #define YT_LOG_WARNING_UNLESS(condition, ...) if (!(condition)) YT_LOG_WARNING(__VA_ARGS__)
  207. #define YT_LOG_ERROR(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Error, __VA_ARGS__)
  208. #define YT_LOG_ERROR_IF(condition, ...) if (condition) YT_LOG_ERROR(__VA_ARGS__)
  209. #define YT_LOG_ERROR_UNLESS(condition, ...) if (!(condition)) YT_LOG_ERROR(__VA_ARGS__)
  210. #define YT_LOG_ALERT(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Alert, __VA_ARGS__);
  211. #define YT_LOG_ALERT_IF(condition, ...) if (condition) YT_LOG_ALERT(__VA_ARGS__)
  212. #define YT_LOG_ALERT_UNLESS(condition, ...) if (!(condition)) YT_LOG_ALERT(__VA_ARGS__)
  213. #define YT_LOG_FATAL(...) \
  214. do { \
  215. YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Fatal, __VA_ARGS__); \
  216. Y_UNREACHABLE(); \
  217. } while(false)
  218. #define YT_LOG_FATAL_IF(condition, ...) if (Y_UNLIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  219. #define YT_LOG_FATAL_UNLESS(condition, ...) if (!Y_LIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  220. #define YT_LOG_EVENT(logger, level, ...) \
  221. YT_LOG_EVENT_WITH_ANCHOR(logger, level, nullptr, __VA_ARGS__)
  222. #define YT_LOG_EVENT_WITH_ANCHOR(logger, level, anchor, ...) \
  223. do { \
  224. const auto& logger__ = (logger)(); \
  225. auto level__ = (level); \
  226. auto location__ = __LOCATION__; \
  227. \
  228. ::NYT::NLogging::TLoggingAnchor* anchor__ = (anchor); \
  229. [[unlikely]] if (!anchor__) { \
  230. static ::NYT::TLeakyStorage<::NYT::NLogging::TLoggingAnchor> staticAnchor__; \
  231. anchor__ = staticAnchor__.Get(); \
  232. } \
  233. \
  234. bool anchorUpToDate__ = logger__.IsAnchorUpToDate(*anchor__); \
  235. [[likely]] if (anchorUpToDate__) { \
  236. auto effectiveLevel__ = ::NYT::NLogging::TLogger::GetEffectiveLoggingLevel(level__, *anchor__); \
  237. if (!logger__.IsLevelEnabled(effectiveLevel__)) { \
  238. break; \
  239. } \
  240. } \
  241. \
  242. auto loggingContext__ = ::NYT::NLogging::GetLoggingContext(); \
  243. auto message__ = ::NYT::NLogging::NDetail::BuildLogMessage(loggingContext__, logger__, __VA_ARGS__); \
  244. \
  245. [[unlikely]] if (!anchorUpToDate__) { \
  246. logger__.RegisterStaticAnchor(anchor__, location__, message__.Anchor); \
  247. } \
  248. \
  249. auto effectiveLevel__ = ::NYT::NLogging::TLogger::GetEffectiveLoggingLevel(level__, *anchor__); \
  250. if (!logger__.IsLevelEnabled(effectiveLevel__)) { \
  251. break; \
  252. } \
  253. \
  254. ::NYT::NLogging::NDetail::LogEventImpl( \
  255. loggingContext__, \
  256. logger__, \
  257. effectiveLevel__, \
  258. location__, \
  259. anchor__, \
  260. std::move(message__.MessageRef)); \
  261. } while (false)
  262. ////////////////////////////////////////////////////////////////////////////////
  263. } // namespace NYT::NLogging
  264. #define LOGGER_INL_H_
  265. #include "logger-inl.h"
  266. #undef LOGGER_INL_H_