logger-inl.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #ifndef LOGGER_INL_H_
  2. #error "Direct inclusion of this file is not allowed, include logger.h"
  3. // For the sake of sane code completion.
  4. #include "logger.h"
  5. #endif
  6. #undef LOGGER_INL_H_
  7. #include <library/cpp/yt/yson_string/convert.h>
  8. #include <library/cpp/yt/yson_string/string.h>
  9. #include <library/cpp/yt/misc/tls.h>
  10. namespace NYT::NLogging {
  11. ////////////////////////////////////////////////////////////////////////////////
  12. inline bool TLogger::IsAnchorUpToDate(const TLoggingAnchor& position) const
  13. {
  14. return
  15. !Category_ ||
  16. position.CurrentVersion == Category_->ActualVersion->load(std::memory_order::relaxed);
  17. }
  18. template <class... TArgs>
  19. void TLogger::AddTag(const char* format, TArgs&&... args)
  20. {
  21. AddRawTag(Format(TRuntimeFormat{format}, std::forward<TArgs>(args)...));
  22. }
  23. template <class TType>
  24. void TLogger::AddStructuredTag(TStringBuf key, TType value)
  25. {
  26. StructuredTags_.emplace_back(key, NYson::ConvertToYsonString(value));
  27. }
  28. template <class... TArgs>
  29. TLogger TLogger::WithTag(const char* format, TArgs&&... args) const
  30. {
  31. auto result = *this;
  32. result.AddTag(format, std::forward<TArgs>(args)...);
  33. return result;
  34. }
  35. template <class TType>
  36. TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) const
  37. {
  38. auto result = *this;
  39. result.AddStructuredTag(key, value);
  40. return result;
  41. }
  42. Y_FORCE_INLINE bool TLogger::IsLevelEnabled(ELogLevel level) const
  43. {
  44. // This is the first check which is intended to be inlined next to
  45. // logging invocation point. Check below is almost zero-cost due
  46. // to branch prediction (which requires inlining for proper work).
  47. if (level < MinLevel_) {
  48. return false;
  49. }
  50. // Next check is heavier and requires full log manager definition which
  51. // is undesirable in -inl.h header file. This is why we extract it
  52. // to a separate method which is implemented in cpp file.
  53. return IsLevelEnabledHeavy(level);
  54. }
  55. Y_FORCE_INLINE const TLogger& TLogger::operator()() const
  56. {
  57. return *this;
  58. }
  59. ////////////////////////////////////////////////////////////////////////////////
  60. namespace NDetail {
  61. struct TMessageStringBuilderContext
  62. {
  63. TSharedMutableRef Chunk;
  64. };
  65. struct TMessageBufferTag
  66. { };
  67. class TMessageStringBuilder
  68. : public TStringBuilderBase
  69. {
  70. public:
  71. TSharedRef Flush();
  72. // For testing only.
  73. static void DisablePerThreadCache();
  74. protected:
  75. void DoReset() override;
  76. void DoReserve(size_t newLength) override;
  77. private:
  78. TSharedMutableRef Buffer_;
  79. static constexpr size_t ChunkSize = 128_KB - 64;
  80. };
  81. inline bool HasMessageTags(
  82. const TLoggingContext& loggingContext,
  83. const TLogger& logger)
  84. {
  85. if (logger.GetTag()) {
  86. return true;
  87. }
  88. if (loggingContext.TraceLoggingTag) {
  89. return true;
  90. }
  91. return false;
  92. }
  93. inline void AppendMessageTags(
  94. TStringBuilderBase* builder,
  95. const TLoggingContext& loggingContext,
  96. const TLogger& logger)
  97. {
  98. bool printComma = false;
  99. if (const auto& loggerTag = logger.GetTag()) {
  100. builder->AppendString(loggerTag);
  101. printComma = true;
  102. }
  103. if (auto traceLoggingTag = loggingContext.TraceLoggingTag) {
  104. if (printComma) {
  105. builder->AppendString(TStringBuf(", "));
  106. }
  107. builder->AppendString(traceLoggingTag);
  108. }
  109. }
  110. inline void AppendLogMessage(
  111. TStringBuilderBase* builder,
  112. const TLoggingContext& loggingContext,
  113. const TLogger& logger,
  114. TRef message)
  115. {
  116. if (HasMessageTags(loggingContext, logger)) {
  117. if (message.Size() >= 1 && message[message.Size() - 1] == ')') {
  118. builder->AppendString(TStringBuf(message.Begin(), message.Size() - 1));
  119. builder->AppendString(TStringBuf(", "));
  120. } else {
  121. builder->AppendString(TStringBuf(message.Begin(), message.Size()));
  122. builder->AppendString(TStringBuf(" ("));
  123. }
  124. AppendMessageTags(builder, loggingContext, logger);
  125. builder->AppendChar(')');
  126. } else {
  127. builder->AppendString(TStringBuf(message.Begin(), message.Size()));
  128. }
  129. }
  130. template <class... TArgs>
  131. void AppendLogMessageWithFormat(
  132. TStringBuilderBase* builder,
  133. const TLoggingContext& loggingContext,
  134. const TLogger& logger,
  135. TStringBuf format,
  136. TArgs&&... args)
  137. {
  138. if (HasMessageTags(loggingContext, logger)) {
  139. if (format.size() >= 2 && format[format.size() - 1] == ')') {
  140. builder->AppendFormat(format.substr(0, format.size() - 1), std::forward<TArgs>(args)...);
  141. builder->AppendString(TStringBuf(", "));
  142. } else {
  143. builder->AppendFormat(format, std::forward<TArgs>(args)...);
  144. builder->AppendString(TStringBuf(" ("));
  145. }
  146. AppendMessageTags(builder, loggingContext, logger);
  147. builder->AppendChar(')');
  148. } else {
  149. builder->AppendFormat(format, std::forward<TArgs>(args)...);
  150. }
  151. }
  152. struct TLogMessage
  153. {
  154. TSharedRef MessageRef;
  155. TStringBuf Anchor;
  156. };
  157. template <class... TArgs>
  158. TLogMessage BuildLogMessage(
  159. const TLoggingContext& loggingContext,
  160. const TLogger& logger,
  161. TFormatString<TArgs...> format,
  162. TArgs&&... args)
  163. {
  164. TMessageStringBuilder builder;
  165. AppendLogMessageWithFormat(&builder, loggingContext, logger, format.Get(), std::forward<TArgs>(args)...);
  166. return {builder.Flush(), format.Get()};
  167. }
  168. template <CFormattable T>
  169. requires (!CStringLiteral<std::remove_cvref_t<T>>)
  170. TLogMessage BuildLogMessage(
  171. const TLoggingContext& loggingContext,
  172. const TLogger& logger,
  173. const T& obj)
  174. {
  175. TMessageStringBuilder builder;
  176. FormatValue(&builder, obj, TStringBuf("v"));
  177. if (HasMessageTags(loggingContext, logger)) {
  178. builder.AppendString(TStringBuf(" ("));
  179. AppendMessageTags(&builder, loggingContext, logger);
  180. builder.AppendChar(')');
  181. }
  182. if constexpr (std::same_as<TStringBuf, std::remove_cvref_t<T>>) {
  183. // NB(arkady-e1ppa): This is the overload where TStringBuf
  184. // falls as well as zero-argument format strings.
  185. // Formerly (before static analysis) there was a special overload
  186. // which guaranteed that Anchor is set to the value of said TStringBuf
  187. // object. Now we have overload for TFormatString<> which fordids
  188. // us having overload for TStringBuf (both have implicit ctors from
  189. // string literals) thus we have to accommodate TStringBuf specifics
  190. // in this if constexpr part.
  191. return {builder.Flush(), obj};
  192. } else {
  193. return {builder.Flush(), TStringBuf()};
  194. }
  195. }
  196. inline TLogMessage BuildLogMessage(
  197. const TLoggingContext& loggingContext,
  198. const TLogger& logger,
  199. TFormatString<> format)
  200. {
  201. return BuildLogMessage(
  202. loggingContext,
  203. logger,
  204. format.Get());
  205. }
  206. inline TLogMessage BuildLogMessage(
  207. const TLoggingContext& loggingContext,
  208. const TLogger& logger,
  209. TRuntimeFormat format)
  210. {
  211. return BuildLogMessage(
  212. loggingContext,
  213. logger,
  214. format.Get());
  215. }
  216. inline TLogMessage BuildLogMessage(
  217. const TLoggingContext& loggingContext,
  218. const TLogger& logger,
  219. TSharedRef&& message)
  220. {
  221. if (HasMessageTags(loggingContext, logger)) {
  222. TMessageStringBuilder builder;
  223. AppendLogMessage(&builder, loggingContext, logger, message);
  224. return {builder.Flush(), TStringBuf()};
  225. } else {
  226. return {std::move(message), TStringBuf()};
  227. }
  228. }
  229. inline TLogEvent CreateLogEvent(
  230. const TLoggingContext& loggingContext,
  231. const TLogger& logger,
  232. ELogLevel level)
  233. {
  234. TLogEvent event;
  235. event.Instant = loggingContext.Instant;
  236. event.Category = logger.GetCategory();
  237. event.Essential = logger.IsEssential();
  238. event.Level = level;
  239. event.ThreadId = loggingContext.ThreadId;
  240. event.ThreadName = loggingContext.ThreadName;
  241. event.FiberId = loggingContext.FiberId;
  242. event.TraceId = loggingContext.TraceId;
  243. event.RequestId = loggingContext.RequestId;
  244. return event;
  245. }
  246. void OnCriticalLogEvent(
  247. const TLogger& logger,
  248. const TLogEvent& event);
  249. inline void LogEventImpl(
  250. const TLoggingContext& loggingContext,
  251. const TLogger& logger,
  252. ELogLevel level,
  253. ::TSourceLocation sourceLocation,
  254. TLoggingAnchor* anchor,
  255. TSharedRef message)
  256. {
  257. auto event = CreateLogEvent(loggingContext, logger, level);
  258. event.MessageKind = ELogMessageKind::Unstructured;
  259. event.MessageRef = std::move(message);
  260. event.Family = ELogFamily::PlainText;
  261. event.SourceFile = sourceLocation.File;
  262. event.SourceLine = sourceLocation.Line;
  263. event.Anchor = anchor;
  264. logger.Write(std::move(event));
  265. if (Y_UNLIKELY(event.Level >= ELogLevel::Alert)) {
  266. OnCriticalLogEvent(logger, event);
  267. }
  268. }
  269. } // namespace NDetail
  270. ////////////////////////////////////////////////////////////////////////////////
  271. } // namespace NYT::NLogging