logger.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. std::atomic<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. };
  74. ////////////////////////////////////////////////////////////////////////////////
  75. struct ILogManager
  76. {
  77. virtual ~ILogManager() = default;
  78. virtual void RegisterStaticAnchor(
  79. TLoggingAnchor* anchor,
  80. ::TSourceLocation sourceLocation,
  81. TStringBuf anchorMessage) = 0;
  82. virtual void UpdateAnchor(TLoggingAnchor* anchor) = 0;
  83. virtual void Enqueue(TLogEvent&& event) = 0;
  84. virtual const TLoggingCategory* GetCategory(TStringBuf categoryName) = 0;
  85. virtual void UpdateCategory(TLoggingCategory* category) = 0;
  86. virtual bool GetAbortOnAlert() const = 0;
  87. };
  88. ILogManager* GetDefaultLogManager();
  89. ////////////////////////////////////////////////////////////////////////////////
  90. struct TLoggingContext
  91. {
  92. TCpuInstant Instant;
  93. TThreadId ThreadId;
  94. TThreadName ThreadName;
  95. TFiberId FiberId;
  96. TTraceId TraceId;
  97. TRequestId RequestId;
  98. TStringBuf TraceLoggingTag;
  99. };
  100. TLoggingContext GetLoggingContext();
  101. ////////////////////////////////////////////////////////////////////////////////
  102. //! Sets the minimum logging level for messages in current thread.
  103. // NB: In fiber environment, min log level is attached to a fiber,
  104. // so after context switch thread min log level might change.
  105. void SetThreadMinLogLevel(ELogLevel minLogLevel);
  106. ELogLevel GetThreadMinLogLevel();
  107. ////////////////////////////////////////////////////////////////////////////////
  108. static constexpr auto NullLoggerMinLevel = ELogLevel::Maximum;
  109. // Min level for non-null logger depends on whether we are in debug or release build.
  110. // - For release mode default behavior is to omit trace logging,
  111. // this is done by setting logger min level to Debug by default.
  112. // - For debug mode logger min level is set to trace by default, so that trace logging is
  113. // allowed by logger, but still may be discarded by category min level.
  114. #ifdef NDEBUG
  115. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Debug;
  116. #else
  117. static constexpr auto LoggerDefaultMinLevel = ELogLevel::Trace;
  118. #endif
  119. class TLogger
  120. {
  121. public:
  122. using TStructuredValidator = std::function<void(const NYson::TYsonString&)>;
  123. using TStructuredValidators = std::vector<TStructuredValidator>;
  124. using TStructuredTag = std::pair<TString, NYson::TYsonString>;
  125. // TODO(max42): switch to TCompactVector after YT-15430.
  126. using TStructuredTags = std::vector<TStructuredTag>;
  127. TLogger() = default;
  128. TLogger(const TLogger& other) = default;
  129. TLogger& operator=(const TLogger& other) = default;
  130. TLogger(ILogManager* logManager, TStringBuf categoryName);
  131. explicit TLogger(TStringBuf categoryName);
  132. explicit operator bool() const;
  133. const TLoggingCategory* GetCategory() const;
  134. //! Validate that level is admitted by logger's own min level
  135. //! and by category's min level.
  136. bool IsLevelEnabled(ELogLevel level) const;
  137. bool GetAbortOnAlert() const;
  138. bool IsEssential() const;
  139. bool IsAnchorUpToDate(const TLoggingAnchor& anchor) const;
  140. void UpdateAnchor(TLoggingAnchor* anchor) const;
  141. void RegisterStaticAnchor(TLoggingAnchor* anchor, ::TSourceLocation sourceLocation, TStringBuf message) const;
  142. void Write(TLogEvent&& event) const;
  143. void AddRawTag(const TString& tag);
  144. template <class... TArgs>
  145. void AddTag(const char* format, TArgs&&... args);
  146. template <class TType>
  147. void AddStructuredTag(TStringBuf key, TType value);
  148. TLogger WithRawTag(const TString& tag) const;
  149. template <class... TArgs>
  150. TLogger WithTag(const char* format, TArgs&&... args) const;
  151. template <class TType>
  152. TLogger WithStructuredTag(TStringBuf key, TType value) const;
  153. TLogger WithStructuredValidator(TStructuredValidator validator) const;
  154. TLogger WithMinLevel(ELogLevel minLevel) const;
  155. TLogger WithEssential(bool essential = true) const;
  156. const TString& GetTag() const;
  157. const TStructuredTags& GetStructuredTags() const;
  158. const TStructuredValidators& GetStructuredValidators() const;
  159. protected:
  160. // These fields are set only during logger creation, so they are effectively const
  161. // and accessing them is thread-safe.
  162. ILogManager* LogManager_ = nullptr;
  163. const TLoggingCategory* Category_ = nullptr;
  164. bool Essential_ = false;
  165. ELogLevel MinLevel_ = NullLoggerMinLevel;
  166. TString Tag_;
  167. TStructuredTags StructuredTags_;
  168. TStructuredValidators StructuredValidators_;
  169. private:
  170. //! This method checks level against category's min level.
  171. //! Refer to comment in TLogger::IsLevelEnabled for more details.
  172. bool IsLevelEnabledHeavy(ELogLevel level) const;
  173. };
  174. ////////////////////////////////////////////////////////////////////////////////
  175. void LogStructuredEvent(
  176. const TLogger& logger,
  177. NYson::TYsonString message,
  178. ELogLevel level);
  179. ////////////////////////////////////////////////////////////////////////////////
  180. #ifdef YT_ENABLE_TRACE_LOGGING
  181. #define YT_LOG_TRACE(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Trace, __VA_ARGS__)
  182. #define YT_LOG_TRACE_IF(condition, ...) if (condition) YT_LOG_TRACE(__VA_ARGS__)
  183. #define YT_LOG_TRACE_UNLESS(condition, ...) if (!(condition)) YT_LOG_TRACE(__VA_ARGS__)
  184. #else
  185. #define YT_LOG_UNUSED(...) if (true) { } else { YT_LOG_DEBUG(__VA_ARGS__); }
  186. #define YT_LOG_TRACE(...) YT_LOG_UNUSED(__VA_ARGS__)
  187. #define YT_LOG_TRACE_IF(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  188. #define YT_LOG_TRACE_UNLESS(condition, ...) YT_LOG_UNUSED(__VA_ARGS__)
  189. #endif
  190. #define YT_LOG_DEBUG(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Debug, __VA_ARGS__)
  191. #define YT_LOG_DEBUG_IF(condition, ...) if (condition) YT_LOG_DEBUG(__VA_ARGS__)
  192. #define YT_LOG_DEBUG_UNLESS(condition, ...) if (!(condition)) YT_LOG_DEBUG(__VA_ARGS__)
  193. #define YT_LOG_INFO(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Info, __VA_ARGS__)
  194. #define YT_LOG_INFO_IF(condition, ...) if (condition) YT_LOG_INFO(__VA_ARGS__)
  195. #define YT_LOG_INFO_UNLESS(condition, ...) if (!(condition)) YT_LOG_INFO(__VA_ARGS__)
  196. #define YT_LOG_WARNING(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Warning, __VA_ARGS__)
  197. #define YT_LOG_WARNING_IF(condition, ...) if (condition) YT_LOG_WARNING(__VA_ARGS__)
  198. #define YT_LOG_WARNING_UNLESS(condition, ...) if (!(condition)) YT_LOG_WARNING(__VA_ARGS__)
  199. #define YT_LOG_ERROR(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Error, __VA_ARGS__)
  200. #define YT_LOG_ERROR_IF(condition, ...) if (condition) YT_LOG_ERROR(__VA_ARGS__)
  201. #define YT_LOG_ERROR_UNLESS(condition, ...) if (!(condition)) YT_LOG_ERROR(__VA_ARGS__)
  202. #define YT_LOG_ALERT(...) YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Alert, __VA_ARGS__);
  203. #define YT_LOG_ALERT_IF(condition, ...) if (condition) YT_LOG_ALERT(__VA_ARGS__)
  204. #define YT_LOG_ALERT_UNLESS(condition, ...) if (!(condition)) YT_LOG_ALERT(__VA_ARGS__)
  205. #define YT_LOG_FATAL(...) \
  206. do { \
  207. YT_LOG_EVENT(Logger, ::NYT::NLogging::ELogLevel::Fatal, __VA_ARGS__); \
  208. Y_UNREACHABLE(); \
  209. } while(false)
  210. #define YT_LOG_FATAL_IF(condition, ...) if (Y_UNLIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  211. #define YT_LOG_FATAL_UNLESS(condition, ...) if (!Y_LIKELY(condition)) YT_LOG_FATAL(__VA_ARGS__)
  212. #define YT_LOG_EVENT(logger, level, ...) \
  213. YT_LOG_EVENT_WITH_ANCHOR(logger, level, nullptr, __VA_ARGS__)
  214. #define YT_LOG_EVENT_WITH_ANCHOR(logger, level, anchor, ...) \
  215. do { \
  216. const auto& logger__ = (logger); \
  217. auto level__ = (level); \
  218. \
  219. if (!logger__.IsLevelEnabled(level__)) { \
  220. break; \
  221. } \
  222. \
  223. auto location__ = __LOCATION__; \
  224. \
  225. ::NYT::NLogging::TLoggingAnchor* anchor__ = (anchor); \
  226. if (!anchor__) { \
  227. static ::NYT::TLeakyStorage<::NYT::NLogging::TLoggingAnchor> staticAnchor__; \
  228. anchor__ = staticAnchor__.Get(); \
  229. } \
  230. \
  231. bool anchorUpToDate__ = logger__.IsAnchorUpToDate(*anchor__); \
  232. if (anchorUpToDate__ && !anchor__->Enabled.load(std::memory_order::relaxed)) { \
  233. break; \
  234. } \
  235. \
  236. auto loggingContext__ = ::NYT::NLogging::GetLoggingContext(); \
  237. auto message__ = ::NYT::NLogging::NDetail::BuildLogMessage(loggingContext__, logger__, __VA_ARGS__); \
  238. \
  239. if (!anchorUpToDate__) { \
  240. logger__.RegisterStaticAnchor(anchor__, location__, message__.Anchor); \
  241. logger__.UpdateAnchor(anchor__); \
  242. } \
  243. \
  244. if (!anchor__->Enabled.load(std::memory_order::relaxed)) { \
  245. break; \
  246. } \
  247. \
  248. static YT_THREAD_LOCAL(i64) localByteCounter__; \
  249. static YT_THREAD_LOCAL(ui8) localMessageCounter__; \
  250. \
  251. localByteCounter__ += message__.MessageRef.Size(); \
  252. if (Y_UNLIKELY(++localMessageCounter__ == 0)) { \
  253. anchor__->MessageCounter.Current += 256; \
  254. anchor__->ByteCounter.Current += localByteCounter__; \
  255. localByteCounter__ = 0; \
  256. } \
  257. \
  258. ::NYT::NLogging::NDetail::LogEventImpl( \
  259. loggingContext__, \
  260. logger__, \
  261. level__, \
  262. location__, \
  263. std::move(message__.MessageRef)); \
  264. } while (false)
  265. ////////////////////////////////////////////////////////////////////////////////
  266. } // namespace NYT::NLogging
  267. #define LOGGER_INL_H_
  268. #include "logger-inl.h"
  269. #undef LOGGER_INL_H_