formatter.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "formatter.h"
  2. #include <library/cpp/yt/cpu_clock/clock.h>
  3. #include <library/cpp/yt/misc/port.h>
  4. #ifdef YT_USE_SSE42
  5. #include <emmintrin.h>
  6. #include <pmmintrin.h>
  7. #endif
  8. namespace NYT::NLogging {
  9. constexpr int MessageBufferWatermarkSize = 256;
  10. ////////////////////////////////////////////////////////////////////////////////
  11. namespace {
  12. // Ultra-fast specialized versions of AppendNumber.
  13. void AppendDigit(TBaseFormatter* out, ui32 value)
  14. {
  15. out->AppendChar('0' + value);
  16. }
  17. void AppendNumber2(TBaseFormatter* out, ui32 value)
  18. {
  19. AppendDigit(out, value / 10);
  20. AppendDigit(out, value % 10);
  21. }
  22. void AppendNumber3(TBaseFormatter* out, ui32 value)
  23. {
  24. AppendDigit(out, value / 100);
  25. AppendDigit(out, (value / 10) % 10);
  26. AppendDigit(out, value % 10);
  27. }
  28. void AppendNumber4(TBaseFormatter* out, ui32 value)
  29. {
  30. AppendDigit(out, value / 1000);
  31. AppendDigit(out, (value / 100) % 10);
  32. AppendDigit(out, (value / 10) % 10);
  33. AppendDigit(out, value % 10);
  34. }
  35. void AppendNumber6(TBaseFormatter* out, ui32 value)
  36. {
  37. AppendDigit(out, value / 100000);
  38. AppendDigit(out, (value / 10000) % 10);
  39. AppendDigit(out, (value / 1000) % 10);
  40. AppendDigit(out, (value / 100) % 10);
  41. AppendDigit(out, (value / 10) % 10);
  42. AppendDigit(out, value % 10);
  43. }
  44. } // namespace
  45. void FormatDateTime(TBaseFormatter* out, TInstant dateTime)
  46. {
  47. tm localTime;
  48. dateTime.LocalTime(&localTime);
  49. AppendNumber4(out, localTime.tm_year + 1900);
  50. out->AppendChar('-');
  51. AppendNumber2(out, localTime.tm_mon + 1);
  52. out->AppendChar('-');
  53. AppendNumber2(out, localTime.tm_mday);
  54. out->AppendChar(' ');
  55. AppendNumber2(out, localTime.tm_hour);
  56. out->AppendChar(':');
  57. AppendNumber2(out, localTime.tm_min);
  58. out->AppendChar(':');
  59. AppendNumber2(out, localTime.tm_sec);
  60. }
  61. void FormatMilliseconds(TBaseFormatter* out, TInstant dateTime)
  62. {
  63. AppendNumber3(out, dateTime.MilliSecondsOfSecond());
  64. }
  65. void FormatMicroseconds(TBaseFormatter* out, TInstant dateTime)
  66. {
  67. AppendNumber6(out, dateTime.MicroSecondsOfSecond());
  68. }
  69. void FormatLevel(TBaseFormatter* out, ELogLevel level)
  70. {
  71. static char chars[] = "?TDIWEAF?";
  72. out->AppendChar(chars[static_cast<int>(level)]);
  73. }
  74. void FormatMessage(TBaseFormatter* out, TStringBuf message)
  75. {
  76. auto current = message.begin();
  77. #ifdef YT_USE_SSE42
  78. auto vectorLow = _mm_set1_epi8(PrintableASCIILow);
  79. auto vectorHigh = _mm_set1_epi8(PrintableASCIIHigh);
  80. #endif
  81. auto appendChar = [&] {
  82. char ch = *current;
  83. if (ch == '\n') {
  84. out->AppendString("\\n");
  85. } else if (ch == '\t') {
  86. out->AppendString("\\t");
  87. } else if (ch < PrintableASCIILow || ch > PrintableASCIIHigh) {
  88. unsigned char unsignedCh = ch;
  89. out->AppendString("\\x");
  90. out->AppendChar(IntToHexLowercase[unsignedCh >> 4]);
  91. out->AppendChar(IntToHexLowercase[unsignedCh & 15]);
  92. } else {
  93. out->AppendChar(ch);
  94. }
  95. ++current;
  96. };
  97. while (current < message.end()) {
  98. if (out->GetBytesRemaining() < MessageBufferWatermarkSize) {
  99. out->AppendString(TStringBuf("...<message truncated>"));
  100. break;
  101. }
  102. #ifdef YT_USE_SSE42
  103. // Use SSE for optimization.
  104. if (current + 16 > message.end()) {
  105. appendChar();
  106. } else {
  107. const void* inPtr = &(*current);
  108. void* outPtr = out->GetCursor();
  109. auto value = _mm_lddqu_si128(static_cast<const __m128i*>(inPtr));
  110. if (_mm_movemask_epi8(_mm_cmplt_epi8(value, vectorLow)) ||
  111. _mm_movemask_epi8(_mm_cmpgt_epi8(value, vectorHigh))) {
  112. for (int index = 0; index < 16; ++index) {
  113. appendChar();
  114. }
  115. } else {
  116. _mm_storeu_si128(static_cast<__m128i*>(outPtr), value);
  117. out->Advance(16);
  118. current += 16;
  119. }
  120. }
  121. #else
  122. // Unoptimized version.
  123. appendChar();
  124. #endif
  125. }
  126. }
  127. ////////////////////////////////////////////////////////////////////////////////
  128. void TCachingDateFormatter::Format(TBaseFormatter* buffer, TInstant dateTime, bool printMicroseconds)
  129. {
  130. auto currentSecond = dateTime.Seconds();
  131. if (CachedSecond_ != currentSecond) {
  132. Cached_.Reset();
  133. FormatDateTime(&Cached_, dateTime);
  134. CachedSecond_ = currentSecond;
  135. }
  136. buffer->AppendString(Cached_.GetBuffer());
  137. buffer->AppendChar(',');
  138. if (printMicroseconds) {
  139. FormatMicroseconds(buffer, dateTime);
  140. } else {
  141. FormatMilliseconds(buffer, dateTime);
  142. }
  143. }
  144. ////////////////////////////////////////////////////////////////////////////////
  145. TPlainTextEventFormatter::TPlainTextEventFormatter(bool enableSourceLocation)
  146. : EnableSourceLocation_(enableSourceLocation)
  147. { }
  148. void TPlainTextEventFormatter::Format(TBaseFormatter* buffer, const TLogEvent& event)
  149. {
  150. CachingDateFormatter_.Format(buffer, CpuInstantToInstant(event.Instant), true);
  151. buffer->AppendChar('\t');
  152. FormatLevel(buffer, event.Level);
  153. buffer->AppendChar('\t');
  154. buffer->AppendString(event.Category->Name);
  155. buffer->AppendChar('\t');
  156. FormatMessage(buffer, event.MessageRef.ToStringBuf());
  157. buffer->AppendChar('\t');
  158. if (event.ThreadName.Length > 0) {
  159. buffer->AppendString(TStringBuf(event.ThreadName.Buffer.data(), event.ThreadName.Length));
  160. } else if (event.ThreadId != TThreadId()) {
  161. buffer->AppendNumber(event.ThreadId, 16);
  162. }
  163. buffer->AppendChar('\t');
  164. if (event.FiberId != TFiberId()) {
  165. buffer->AppendNumber(event.FiberId, 16);
  166. }
  167. buffer->AppendChar('\t');
  168. if (event.TraceId != TTraceId()) {
  169. buffer->AppendGuid(event.TraceId);
  170. }
  171. if (EnableSourceLocation_) {
  172. buffer->AppendChar('\t');
  173. if (event.SourceFile) {
  174. auto sourceFile = event.SourceFile;
  175. buffer->AppendString(sourceFile.RNextTok(LOCSLASH_C));
  176. buffer->AppendChar(':');
  177. buffer->AppendNumber(event.SourceLine);
  178. }
  179. }
  180. buffer->AppendChar('\n');
  181. }
  182. ////////////////////////////////////////////////////////////////////////////////
  183. } // namespace NYT::NLogging